Platypus Next Generation
Platypus is getting an update. It’s not backward compatible, so you have to opt-in when you create the platypus instance. That makes it backward compatible for all the old code you may or may not have written. Please spread the word.
# old code:
use FFI::Platypus;
my $ffi = FFI::Platypus->new;
# new code:
use FFI::Platypus 1.00;
my $ffi = FFI::Platypus->new( api => 1 );
You should generally write all new code using the new API so that you can take advantage of the newer features and design fixes. You may want to also consider upgrading your existing code to use the new API for the same reasons.
The main enhancement you get is the ability to pass and return records by value in addition to as pointers of by reference. This missing feature was a design bug in the original implementation of Platypus, and I am pleased to make this feature available. In the old interface records are assumed to be pointers. In the new interface they are assumed to be records, and you have to use the pointer decorator (*
) to use pointers to records.
# both versions:
package Foo {
use FFI::Platypus::Record;
record_layout
int bar
int baz
;
}
# old code:
use FFI::Platypus;
my $ffi = FFI::Platypus->new;
# XXX can't use Foo pass-by-value # pass-by-value
$ffi->type('record(Foo)' => 'foo_t'); # pass-by-pointer/reference
# new code:
use FFI::Platypus 1.00;
my $ffi = FFI::Platypus->new( api => 1 );
$ffi->type('record(Foo)' => 'foo_t'); # pass-by-value
$ffi->type('record(Foo)*' => 'foo_ptr'); # pass-by-pointer/reference
A minor tweak on the internals mean that you can also decorate aliases as pointer or array types.
# old code:
use FFI::Platypus;
my $ffi = FFI::Platypus->new;
$ffi->type('opaque' => 'o_t');
$ffi->type('opaque*' => 'o_ptr');
$ffi->type('opaque[10]' => 'o_array');
# XXX no records-by-value
$ffi->type('record(Foo)' => 'foo_ptr');
# new code:
use FFI::Platypus 1.00;
my $ffi = FFI::Platypus->new( api => 1 );
$ffi->type('opaque' => 'o_t');
$ffi->type('o_t*'); # pointer to o_t doesn't require an extra alias
$ffi->type('o_t[10]'); # same for arrays
$ffi->type('record(Foo)' => 'foo_t');
$fii->type('foo_t*'); # or pointers to records
Last, but not least, Platypus also now supports out of the box the common opaque pointer as an object pattern. TL;DR, given a C interface like this:
typedef struct foo_t;
foo_t* foo_new();
void foo_set_bar(foo_t*, const char *);
const char *foo_get_bar(foo_t*);
void foo_free(foo_t*);
You can write Perl like this:
# new code:
package Foo {
use FFI::Platypus 1.00;
my $ffi = FFI::Platypus->new( api => 1 );
$ffi->type('object(Foo)' => 'foo_t');
$ffi->mangler(sub {
my $name = shift;
$name =~ s/^foo_//r; # prefix all symbol lookups with foo_
});
$ffi->attach( new => [ ] => 'foo_t*' );
$ffi->attach( set_bar => [ 'foo_t*', 'string' ] );
$ffi->attach( get_bar => [ 'foo_t*' ] => 'string' );
$ffi->attach( free => [ 'foo_t*' ] );
sub DESTROY
{
my $self = shift;
$self->free;
}
}
my $foo = Foo->new;
$foo->set_bar("baz");
my $baz = $foo->get_bar;
If Platypus or the new API has piqued your interest or you have questions, we should definitely hang out! Join us on #native on irc.perl.org, check out the project on metacpan or github. If in person interaction is more your jam, then I will be at DCBPW in Baltimore next year along with TPCiH in Houston.
Leave a comment