FFI-Platypus

 view release on metacpan or  search on metacpan

README  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";

  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]

  Discussion

    In the C source of this example, we pass a C struct by value by copying
    it onto the stack. On the Perl side we create a Color class using
    FFI::Platypus::Record, which allows us to pass the structure the way
    the C source wants us to.

    Generally you should only reach for 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 FFI::C using pointers.

 Avoiding Copy Using Memory Windows (with libzmq3)

  C API

    ØMQ/3.2.6 API Reference <http://api.zeromq.org/3-2:_start>

  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";
     }

  Execute

     $ perl zmq3.pl
     libzmq version 4.3.4
     recv_message = hello there

  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 zmq_version to ask libzmq which
    version it is.

    zmq_version returns the version number via three integer pointer
    arguments, so we use the pointer to integer type: 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 $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 FFI::Platypus::Buffer function window
    instead of buffer_to_scalar. They have a similar effect in that the
    provide a scalar from a region of memory, but 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.

 libarchive

  C Documentation

    https://www.libarchive.org/

  Perl Source

     use FFI::Platypus 2.00;



( run in 0.555 second using v1.01-cache-2.11-cpan-c966e8aa7e8 )