FFI-Platypus
view release on metacpan or search on metacpan
lib/FFI/Platypus.pm view on Meta::CPAN
));
sub as_string {
my($self) = @_;
sprintf "%s: [red:%02x green:%02x blue:%02x]",
$self->name, $self->red, $self->green, $self->blue;
}
}
$ffi->type('record(Color)' => 'color_t');
$ffi->attach( color_increase_red => ['color_t','uint8'] => 'color_t' );
my $gray = Color->new(
name => 'gray',
red => 0xDC,
green => 0xDC,
blue => 0xDC,
);
my $slightly_red = color_increase_red($gray, 20);
print "$gray\n";
print "$slightly_red\n";
=head3 Execute
$ cc -shared -o color.so color.c
$ perl color.pl
gray: [red:dc green:dc blue:dc]
reddish: [red:f0 green:dc blue:dc]
=head3 Discussion
In the C source of this example, we pass a C C<struct> by value by
copying it onto the stack. On the Perl side we create a C<Color> class
using L<FFI::Platypus::Record>, which allows us to pass the structure
the way the C source wants us to.
Generally you should only reach for L<FFI::Platypus::Record> if you
need to pass small records on the stack like this. For more complicated
(including nested) data you want to use L<FFI::C> using pointers.
=head2 Avoiding Copy Using Memory Windows (with libzmq3)
=head3 C API
L<ÃMQ/3.2.6 API Reference|http://api.zeromq.org/3-2:_start>
=head3 Perl Source
use constant ZMQ_IO_THREADS => 1;
use constant ZMQ_MAX_SOCKETS => 2;
use constant ZMQ_REQ => 3;
use constant ZMQ_REP => 4;
use FFI::CheckLib qw( find_lib_or_die );
use FFI::Platypus 2.00;
use FFI::Platypus::Memory qw( malloc );
use FFI::Platypus::Buffer qw( scalar_to_buffer window );
my $endpoint = "ipc://zmq-ffi-$$";
my $ffi = FFI::Platypus->new(
api => 2,
lib => find_lib_or_die lib => 'zmq',
);
$ffi->attach(zmq_version => ['int*', 'int*', 'int*'] => 'void');
my($major,$minor,$patch);
zmq_version(\$major, \$minor, \$patch);
print "libzmq version $major.$minor.$patch\n";
die "this script only works with libzmq 3 or better" unless $major >= 3;
$ffi->type('opaque' => 'zmq_context');
$ffi->type('opaque' => 'zmq_socket');
$ffi->type('opaque' => 'zmq_msg_t');
$ffi->attach(zmq_ctx_new => [] => 'zmq_context');
$ffi->attach(zmq_ctx_set => ['zmq_context', 'int', 'int'] => 'int');
$ffi->attach(zmq_socket => ['zmq_context', 'int'] => 'zmq_socket');
$ffi->attach(zmq_connect => ['opaque', 'string'] => 'int');
$ffi->attach(zmq_bind => ['zmq_socket', 'string'] => 'int');
$ffi->attach(zmq_send => ['zmq_socket', 'opaque', 'size_t', 'int'] => 'int');
$ffi->attach(zmq_msg_init => ['zmq_msg_t'] => 'int');
$ffi->attach(zmq_msg_recv => ['zmq_msg_t', 'zmq_socket', 'int'] => 'int');
$ffi->attach(zmq_msg_data => ['zmq_msg_t'] => 'opaque');
$ffi->attach(zmq_errno => [] => 'int');
$ffi->attach(zmq_strerror => ['int'] => 'string');
my $context = zmq_ctx_new();
zmq_ctx_set($context, ZMQ_IO_THREADS, 1);
my $socket1 = zmq_socket($context, ZMQ_REQ);
zmq_connect($socket1, $endpoint);
my $socket2 = zmq_socket($context, ZMQ_REP);
zmq_bind($socket2, $endpoint);
{ # send
our $sent_message = "hello there";
my($pointer, $size) = scalar_to_buffer $sent_message;
my $r = zmq_send($socket1, $pointer, $size, 0);
die zmq_strerror(zmq_errno()) if $r == -1;
}
{ # recv
my $msg_ptr = malloc 100;
zmq_msg_init($msg_ptr);
my $size = zmq_msg_recv($msg_ptr, $socket2, 0);
die zmq_strerror(zmq_errno()) if $size == -1;
my $data_ptr = zmq_msg_data($msg_ptr);
window(my $recv_message, $data_ptr, $size);
print "recv_message = $recv_message\n";
}
=head3 Execute
$ perl zmq3.pl
libzmq version 4.3.4
recv_message = hello there
=head3 Discussion
ÃMQ is a high-performance asynchronous messaging library. There are a
few things to note here.
Firstly, sometimes there may be multiple versions of a library in the
wild and you may need to verify that the library on a system meets your
needs (alternatively you could support multiple versions and configure
your bindings dynamically). Here we use C<zmq_version> to ask libzmq
which version it is.
C<zmq_version> returns the version number via three integer pointer
arguments, so we use the pointer to integer type: C<int *>. In order to
pass pointer types, we pass a reference. In this case it is a reference
to an undefined value, because zmq_version will write into the pointers
the output values, but you can also pass in references to integers,
floating point values and opaque pointer types. When the function
returns the C<$major> variable (and the others) has been updated and we
can use it to verify that it supports the API that we require.
Finally we attach the necessary functions, send and receive a message.
When we receive we use the L<FFI::Platypus::Buffer> function C<window>
instead of C<buffer_to_scalar>. They have a similar effect in that
the provide a scalar from a region of memory, but C<window> doesn't
have to copy any data, so it is cheaper to call. The only downside
is that a windowed scalar like this is read-only.
=head2 libarchive
=head3 C Documentation
L<https://www.libarchive.org/>
=head3 Perl Source
use FFI::Platypus 2.00;
( run in 2.495 seconds using v1.01-cache-2.11-cpan-d01c6094234 )