Skip Menu |

This queue is for tickets about the XS-Writer CPAN distribution.

Report information
The Basics
Id: 34455
Status: new
Priority: 0/
Queue: XS-Writer

People
Owner: Nobody in particular
Requestors: schwern [...] pobox.com
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: (no value)



Subject: Easier type maps
Date: Wed, 26 Mar 2008 14:01:02 -0700
To: bug-XS-Writer [...] rt.cpan.org
From: Michael G Schwern <schwern [...] pobox.com>
Show quoted text
-------- Original Message -------- Subject: Re: XS::Writer Date: Sat, 22 Mar 2008 02:53:19 -0700 From: Tom Heady <tom@heady.org> To: Michael G Schwern <schwern@pobox.com> References: <47E38E25.6030802@pobox.com> <47E488AE.2040701@heady.org> Tom Heady wrote:
> Michael G Schwern wrote:
>> Hey folks, you might be interested in a module I just whipped up to >> generate the necessary XS code to make objects out of structs. >> http://svn.schwern.org/svn/CPAN/XS-Writer/ >>
> > We should come up with a more generic way to map types. I have a > struct with uint32_t and uint64_t that are fairly easy to map. >
Attached is a patch which makes it easier to map types. Just define which SV field you want at the top of Writer.pm for each type. Oh yeah, and tests too. Tom -- I do have a cause though. It's obscenity. I'm for it. - Tom Lehrer
Index: t/type_accessor.t =================================================================== --- t/type_accessor.t (revision 0) +++ t/type_accessor.t (revision 0) @@ -0,0 +1,150 @@ +#!/usr/bin/perl -w + +use Test::More tests => 7; +use Test::Differences; +use Test::Exception; + +use File::Path; + + +use_ok 'XS::Writer'; + +my $writer = XS::Writer->new( + package => 'Some::Employee' +); + +$writer->type_accessor(completelymadeuptype => <<'END'); +$type +$accessor( $class self, ... ) + CODE: + if( items > 1 ) + self->$key = SvIV(ST(1)); + RETVAL = self->$key; + OUTPUT: + RETVAL +END + +{ + $writer->struct(<<' END'); + typedef struct employee { + completelymadeuptype hair_color; + }; + END + + my $wanted = <<' END'; +completelymadeuptype +Some__Employee_hair_color( Some::Employee self, ... ) + CODE: + if( items > 1 ) + self->hair_color = SvIV(ST(1)); + RETVAL = self->hair_color; + OUTPUT: + RETVAL + + + END + + eq_or_diff( $writer->make_xs_accessors , $wanted , 'completelymadeuptype mapped correctly' ); +} + + +{ + $writer->struct(<<' END'); + typedef struct employee { + char * name; + }; + END + + my $wanted = <<' END'; +char * +Some__Employee_name( Some::Employee self, ... ) + CODE: + if( items > 1 ) + self->name = SvPV_nolen(ST(1)); + RETVAL = self->name; + OUTPUT: + RETVAL + + + END + + eq_or_diff( $writer->make_xs_accessors , $wanted , 'char * mapped correctly' ); +} + +{ + $writer->struct(<<' END'); + typedef struct employee { + double salary; + }; + END + + my $wanted = <<' END'; +double +Some__Employee_salary( Some::Employee self, ... ) + CODE: + if( items > 1 ) + self->salary = SvNV(ST(1)); + RETVAL = self->salary; + OUTPUT: + RETVAL + + + END + eq_or_diff( $writer->make_xs_accessors , $wanted , 'double mapped correctly' ); +} + +{ + $writer->struct(<<' END'); + typedef struct employee { + int id; + }; + END + + my $wanted = <<' END'; +int +Some__Employee_id( Some::Employee self, ... ) + CODE: + if( items > 1 ) + self->id = SvIV(ST(1)); + RETVAL = self->id; + OUTPUT: + RETVAL + + + END + eq_or_diff( $writer->make_xs_accessors , $wanted , 'int mapped correctly' ); +} + +{ + $writer->struct(<<' END'); + typedef struct employee { + uint32_t age; + }; + END + + my $wanted = <<' END'; +uint32_t +Some__Employee_age( Some::Employee self, ... ) + CODE: + if( items > 1 ) + self->age = SvUV(ST(1)); + RETVAL = self->age; + OUTPUT: + RETVAL + + + END + eq_or_diff( $writer->make_xs_accessors , $wanted , 'uint32_t mapped correctly' ); +} + +{ + $writer->struct(<<' END'); + typedef struct employee { + doesnotexist num_fingers; + }; + END + + eval{ $writer->make_xs_accessors }; + like( $@ , qr{\ANo accessor for type doesnotexist} , + 'throw error for unknown types' ); +} Index: lib/XS/Writer.pm =================================================================== --- lib/XS/Writer.pm (revision 4268) +++ lib/XS/Writer.pm (working copy) @@ -11,6 +11,20 @@ use Moose; use Moose::Autobox; +my $typemap = { + 'char *' => 'SvPV_nolen', + int => 'SvIV', + double => 'SvNV', + 'unsigned int' => 'SvUV', + long => 'SvIV', + 'unsigned long' => 'SvUV', + short => 'SvIV', + 'unsigned short' => 'SvUV', + 'unsigned char *' => 'SvPV_nolen', + 'const char *' => 'SvPV_nolen', + uint32_t => 'SvUV', +}; + { package StringWithWhitespace; use Moose::Role; @@ -206,43 +220,33 @@ my $class = shift; my $self = $class->SUPER::new(@_); - $self->type_accessor(int => <<'END'); -$type -$accessor( $class self, ... ) - CODE: - if( items > 1 ) - self->$key = SvIV(ST(1)); - RETVAL = self->$key; - OUTPUT: - RETVAL -END + return $self; +} - $self->type_accessor("char *" => <<'END'); -$type -$accessor( $class self, ... ) - CODE: - if( items > 1 ) - self->$key = SvPV_nolen(ST(1)); - RETVAL = self->$key; - OUTPUT: - RETVAL -END +sub _build_accessor +{ + my $self = shift; + my $type = shift; - $self->type_accessor(double => <<'END'); + my $accessors = $self->type_accessors; + + # if the user specified a type, return it + return $accessors->{$type} if $accessors->{$type}; + + # return the default + return $self->type_accessor($type => <<'END'); $type $accessor( $class self, ... ) CODE: if( items > 1 ) - self->$key = SvNV(ST(1)); + self->$key = $map(ST(1)); RETVAL = self->$key; OUTPUT: RETVAL END - return $self; } - =head3 struct $writer->struct($typedef); @@ -371,22 +375,28 @@ return $xs; } - sub make_xs_accessors { my $self = shift; my $xs = ''; my $elements = $self->struct_elements; - my $accessors = $self->type_accessors; my $xs_type = $self->xs_type; for my $key (sort { lc $a cmp lc $b } keys %$elements) { my $type = $elements->{$key}; - my $accessor = $accessors->{$type} - or croak "No accessor for type $type"; + my $accessor = $self->_build_accessor( $type ); + + my $map = $typemap->{ $type }; + + if ( $accessor =~ /\$map/ and ! $map ) + { + croak "No accessor for type $type"; + } + $accessor =~ s/\$accessor/${xs_type}_${key}/g; $accessor =~ s/\$key/$key/g; + $accessor =~ s/\$map/$map/g; $xs .= $accessor; $xs .= "\n\n"; @@ -395,7 +405,6 @@ return $xs; } - sub make_xs { my $self = shift;