Provided by: libffi-platypus-perl_0.47-3_amd64 bug

NAME

       FFI::Platypus::Type - Defining types for FFI::Platypus

VERSION

       version 0.47

SYNOPSIS

       OO Interface:

        use FFI::Platypus;
        my $ffi = FFI::Platypus->new;
        $ffi->type('int' => 'my_int');

DESCRIPTION

       This document describes how to define types using FFI::Platypus.  Types may be "defined"
       ahead of time, or simply used when defining or attaching functions.

        # OO example of defining types
        use FFI::Platypus;
        my $ffi = FFI::Platypus->new;
        $ffi->type('int');
        $ffi->type('string');

        # OO example of simply using types in function declaration or attachment
        my $f = $ffi->function(puts => ['string'] => 'int');
        $ffi->attach(puts => ['string'] => 'int');

       If you are using the declarative interface, you can either pass the types you need to the
       FFI::Platypus::Declare "use" invocation, or you can use the FFI::Platypus::Declare#type
       function.  The advantage of the former is that it creates a Perl constant for that type so
       that you do not need to use quotation marks when using the type.

        # Declarative with use
        use FFI::Platypus::Declare 'string', 'int';
        attach puts => [string] => int;

        # Declarative with type
        use FFI::Platypus::Declare;
        type 'string';
        type 'int';
        attach puts => ['string'] => 'int';

       Unless you are using aliases the FFI::Platypus#type method or FFI::Platypus::Declare#type
       function are not necessary, but they will throw an exception if the type is incorrectly
       specified or not supported, which may be helpful.

       Note: This document sometimes uses the term "C Function" as short hand for function
       implemented in a compiled language.  Unless the term is referring literally to a C
       function example code, you can assume that it should also work with another compiled
       language.

   meta information about types
       You can get the size of a type using the FFI::Platypus#sizeof method.

        # OO interface
        my $intsize = $ffi->sizeof('int');
        my intarraysize = $ffi->sizeof('int[64]');

        # Declare interface
        my $intsize = sizeof 'int';
        my intarraysize = sizeof 'int[64]';

   converting types
       Sometimes it is necessary to convert types.  In particular various pointer types often
       need to be converted for consumption in Perl.  For this purpose the FFI::Platypus#cast
       method is provided.  It needs to be used with care though, because not all type
       combinations are supported.  Here are some useful ones:

        # OO interface
        my $address = $ffi->cast('string' => 'opaque', $string);
        my $string  = $ffi->cast('opaque' => 'string', $pointer);

        # Declare interface
        use FFI::Platypus::Declare;
        my $address = cast 'string' => 'opaque', $string;
        my $string  = cast 'opaque' => 'string', $pointer;

   aliases
       Some times using alternate names is useful for documenting the purpose of an argument or
       return type.  For this "aliases" can be helpful.  The second argument to the
       FFI::Platypus#type method or FFI::Platypus::Declare#type function can be used to define a
       type alias that can later be used by function declaration and attachment.

        # OO style
        use FFI::Platypus;
        my $ffi = FFI::Platypus->new;
        $ffi->type('int'    => 'myint');
        $ffi->type('string' => 'mystring');
        my $f = $ffi->function( puts => ['mystring'] => 'myint' );
        $ffi->attach( puts => ['mystring'] => 'myint' );

        # Declarative style
        use FFI::Platypus::Declare;
        type 'int'    => 'myint';
        type 'string' => 'mystring';
        attach puts => ['mystring'] => 'myint';

        # Declarative style with use (and with fewer quotes)
        use FFI::Platypus::Declare
          [ int    => 'myint' ],
          [ string => 'mystring' ];
        attach puts => [mystring] => myint;

       Aliases are contained without the FFI::Platypus object, or the current package if you are
       using FFI::Platypus::Declare, so feel free to define your own crazy types without stepping
       on the toes of other CPAN Platypus developers.

TYPE CATEGORIES

   Native types
       So called native types are the types that the CPU understands that can be passed on the
       argument stack or returned by a function.  It does not include more complicated types like
       arrays or structs, which can be passed via pointers (see the opaque type below).
       Generally native types include void, integers, floats and pointers.

       the void type

       This can be used as a return value to indicate a function does not return a value (or if
       you want the return value to be ignored).

       integer types

       The following native integer types are always available (parentheticals indicates the
       usual corresponding C type):

       sint8
           Signed 8 bit byte ("signed char", "int8_t").

       uint8
           Unsigned 8 bit byte ("unsigned char", "uint8_t").

       sint16
           Signed 16 bit integer ("short", "int16_t")

       uint16
           Unsigned 16 bit integer ("unsigned short", "uint16_t")

       sint32
           Signed 32 bit integer ("int", "int32_t")

       uint32
           Unsigned 32 bit integer ("unsigned int", "uint32_t")

       sint64
           Signed 64 bit integer ("long" or "long long", "int64_t")

       uint64
           Unsigned 64 bit integer ("unsigned long" or "unsigned long long", "uint64_t")

       You may also use "uchar", "ushort", "uint" and "ulong" as short names for "unsigned char",
       "unsigned short", "unsigned int" and "unsigned long".

       These integer types are also available, but there actual size and sign may depend on the
       platform.

       char
           Somewhat confusingly, "char" is an integer type!  This is really an alias for either
           "sint8_t" or "uint8_t" depending on your platform.  If you want to pass a character
           (not integer) in to a C function that takes a character you want to use the perl ord
           function.  Here is an example that uses the standard libc "isalpha", "isdigit" type
           functions:

            use FFI::Platypus;

            my $ffi = FFI::Platypus->new;
            $ffi->lib(undef);
            $ffi->type('int' => 'character');

            my @list = qw(
              alnum alpha ascii blank cntrl digit lower print punct
              space upper xdigit
            );

            $ffi->attach("is$_" => ['character'] => 'int') for @list;

            my $char = shift(@ARGV) || 'a';

            no strict 'refs';
            printf "'%s' is %s %s\n", $char, $_, &{'is'.$_}(ord $char) for @list;

       size_t
           This is usually an "unsigned long", but it is up to the compiler to decide.  The
           "malloc" function is defined in terms of "size_t":

            use FFI::Platypus::Declare qw( size_t opaque );
            attach malloc => [size_t] => opaque;

           (Note that you can get "malloc" from FFI::Platypus::Memory).

       There are a number of other types that may or may not be available if they are detected
       when FFI::Platypus is installed.  This includes things like "wchar_t", "off_t", "wint_t".
       You can use this script to list all the integer types that FFI::Platypus knows about, plus
       how they are implemented.

        use FFI::Platypus;

        my $ffi = FFI::Platypus->new;

        foreach my $type_name (sort FFI::Platypus->types)
        {
          my $meta = $ffi->type_meta($type_name);
          next unless $meta->{element_type} eq 'int';
          printf "%20s %s\n", $type_name, $meta->{ffi_type};
        }

       If you need a common system type that is not provided, please open a ticket in the
       Platypus project's GitHub issue tracker.  Be sure to include the usual header file the
       type can be found in.

       floating point types

       The following native floating point types are always available (parentheticals indicates
       the usual corresponding C type):

       float
           Single precision floating point (float)

       double
           Double precision floating point (double)

       longdouble
           Floating point that may be larger than "double" (longdouble).  This type is only
           available if supported by the C compiler used to build FFI::Platypus.  There may be a
           performance penalty for using this type, even if your Perl uses long doubles
           internally for its number value (NV) type, because of the way FFI::Platypus interacts
           with "libffi".

           As an argument type either regular number values (NV) or instances of Math::LongDouble
           are accepted.  When used as a return type, Math::LongDouble will be used, if you have
           that module installed.  Otherwise the return type will be downgraded to whatever your
           Perl's number value (NV) is.

       complex_float
           Complex single precision floating point (float complex)

       complex_double
           Complex double precision floating point (double complex)

           "complex_float" and "complex_double" are only available if supported by your C
           compiler and by libffi.  Complex numbers are only supported in very recent versions of
           libffi, and as of this writing the latest production version doesn't work on x86_64.
           It does seem to work with the latest production version of libffi on 32 bit Intel
           (x86), and with the latest libffi version in git on x86_64.

       Support for "complex_float", "complex_double" and "longdouble" are limited at the moment.
       Complex types can only be used as simple arguments (not return types, pointers, arrays or
       record members) and the "longdouble" can only be used as simple argument or return values
       (not pointers, arrays or record members).  Adding support for these is not difficult, but
       time consuming, so if you are in need of these features please do not hesitate to open a
       support ticket on the project's github issue tracker:

       <https://github.com/plicease/FFI-Platypus/issues>

       In particular I am hesitant to implementing complex return types, as there are performance
       and interface ramifications, and I would appreciate talking to someone who is actually
       going to use these features.

       opaque pointers

       Opaque pointers are simply a pointer to a region of memory that you do not manage, and do
       not know the structure of. It is like a "void *" in C.  These types are represented in
       Perl space as integers and get converted to and from pointers by FFI::Platypus.  You may
       use "pointer" as an alias for "opaque".  (The Platypus documentation uses the convention
       of using "pointer" to refer to pointers to known types (see below) and "opaque" as short
       hand for opaque pointer).

       As an example, libarchive defines "struct archive" type in its header files, but does not
       define its content.  Internally it is defined as a "struct" type, but the caller does not
       see this.  It is therefore opaque to its caller.  There are "archive_read_new" and
       "archive_write_new" functions to create a new instance of this opaque object and
       "archive_read_free" and "archive_write_free" to destroy this objects when you are done.

        use FFI::Platypus::Declare qw( opaque int );
        attach archive_read_new   => []       => opaque;
        attach archive_write_new  => []       => opaque;
        attach archive_read_free  => [opaque] => int;
        attach archive_write_free => [opaque] => int;

       As a special case, when you pass "undef" into a function that takes an opaque type it will
       be translated into "NULL" for C.  When a C function returns a NULL pointer, it will be
       translated back to "undef".

   Strings
       From the CPU's perspective, strings are just pointers.  From Perl and C's perspective,
       those pointers point to a series of characters.  For C they are null terminates ("\0").
       FFI::Platypus handles the details where they differ.  Basically when you see "char *" or
       "const char *" used in a C header file you can expect to be able to use the "string" type.

        use FFI::Platypus::Declare qw( string int );
        attach puts => [string] => int;

       Currently strings are only supported as simple argument and return types and as argument
       (but not return types) for closures.  In the future pointers to strings or arrays of
       strings may be supported.

   Pointer / References
       In C you can pass a pointer to a variable to a function in order accomplish the task of
       pass by reference.  In Perl the same is task is accomplished by passing a reference
       (although you can also modify the argument stack thus Perl supports proper pass by
       reference as well).

       With FFI::Platypus you can define a pointer types to any of the native types described
       above (that is all the types we have covered so far except for strings).  When using this
       you must make sure to pass in a reference to a scalar, or "undef" ("undef" will be
       translated into "NULL").

       If the C code makes a change to the value pointed to by the pointer, the scalar will be
       updated before returning to Perl space.  Example, with C code.

        /* foo.c */
        void increment_int(int *value)
        {
          if(value != NULL)
            (*value)++;
          else
            fprintf(stderr, "NULL pointer!\n");
        }

        # foo.pl
        use FFI::Platypus::Declare 'void', ['int*' =>'int_p'];
        lib 'libfoo.so'; # change to reflect the dynamic lib
                         # that contains foo.c
        attach increment_int => [int_p] => void;
        my $i = 0;
        increment_int(\$i);   # $i == 1
        increment_int(\$i);   # $i == 2
        increment_int(\$i);   # $i == 3
        increment_int(undef); # prints "NULL pointer!\n"

   Records
       Records are structured data of a fixed length.  In C they are called "struct"s To declare
       a record type, use "record":

        $ffi->type( 'record (42)' => 'my_record_of_size_42_bytes' );

       The easiest way to mange records with Platypus is by using FFI::Platypus::Record to define
       a record layout for a record class.  Here is a brief example:

        package My::UnixTime;

        use FFI::Platypus::Record;

        record_layout(qw(
            int    tm_sec
            int    tm_min
            int    tm_hour
            int    tm_mday
            int    tm_mon
            int    tm_year
            int    tm_wday
            int    tm_yday
            int    tm_isdst
            long   tm_gmtoff
            string tm_zone
        ));

        my $ffi = FFI::Platypus->new;
        $ffi->lib(undef);
        # define a record class My::UnixTime and alias it to "tm"
        $ffi->type("record(My::UnixTime)" => 'tm');

        # attach the C localtime function as a constructor
        $ffi->attach( localtime => ['time_t*'] => 'tm', sub {
          my($inner, $class, $time) = @_;
          $time = time unless defined $time;
          $inner->(\$time);
        });

        package main;

        # now we can actually use our My::UnixTime class
        my $time = My::UnixTime->localtime;
        printf "time is %d:%d:%d %s\n",
          $time->tm_hour,
          $time->tm_min,
          $time->tm_sec,
          $time->tm_zone;

       For more detailed usage, see FFI::Platypus::Record.

       Platypus does not manage the structure of a record (that is up to you), it just keeps
       track of their size and makes sure that they are copied correctly when used as a return
       type.  A record in Perl is just a string of bytes stored as a scalar.  In addition to
       defining a record layout for a record class, there are a number of tools you can use
       manipulate records in Perl, two notable examples are pack and unpack and
       Convert::Binary::C.

       Here is an example with commentary that uses Convert::Binary::C to extract the component
       time values from the C "localtime" function, and then smushes them back together to get
       the original "time_t" (an integer).

        use Convert::Binary::C;
        use FFI::Platypus;
        use Data::Dumper qw( Dumper );

        my $c = Convert::Binary::C->new;

        # Alignment of zero (0) means use
        # the alignment of your CPU
        $c->configure( Alignment => 0 );

        # parse the tm record structure so
        # that Convert::Binary::C knows
        # what to spit out and suck in
        $c->parse(<<ENDC);
        struct tm {
          int tm_sec;
          int tm_min;
          int tm_hour;
          int tm_mday;
          int tm_mon;
          int tm_year;
          int tm_wday;
          int tm_yday;
          int tm_isdst;
          long int tm_gmtoff;
          const char *tm_zone;
        };
        ENDC

        # get the size of tm so that we can give it
        # to Platypus
        my $tm_size = $c->sizeof("tm");

        # create the Platypus instance and create the appropriate
        # types and functions
        my $ffi = FFI::Platypus->new;
        $ffi->lib(undef);
        $ffi->type("record($tm_size)" => 'tm');
        $ffi->attach( [ localtime => 'my_localtime' ] => ['time_t*'] => 'tm'     );
        $ffi->attach( [ time      => 'my_time'      ] => ['tm']      => 'time_t' );

        # ===============================================
        # get the tm struct from the C localtime function
        # note that we pass in a reference to the value that time
        # returns because localtime takes a pointer to time_t
        # for some reason.
        my $time_hashref = $c->unpack( tm => my_localtime(\time) );

        # tm_zone comes back from Convert::Binary::C as an opaque,
        # cast it into a string.  We localize it to just this do
        # block so that it will be a pointer when we pass it back
        # to C land below.
        do {
          local $time_hashref->{tm_zone} = $ffi->cast(opaque => string => $time_hashref->{tm_zone});
          print Dumper($time_hashref);
        };

        # ===============================================
        # convert the tm struct back into an epoch value
        my $time = my_time( $c->pack( tm => $time_hashref ) );

        print "time      = $time\n";
        print "perl time = ", time, "\n";

       You can also link a record type to a class.  It will then be accepted when blessed into
       that class as an argument passed into a C function, and when it is returned from a C
       function it will be blessed into that class.  Basically:

        $ffi->type( 'record(My::Class)' => 'my_class' );
        $ffi->attach( my_function1 => [ 'my_class' ] => 'void' );
        $ffi->attach( my_function2 => [ ] => 'my_class' );

       The only thing that your class MUST provide is either a "ffi_record_size" or
       "_ffi_record_size" class method that returns the size of the record in bytes.

       Here is a longer practical example, once again using the tm struct:

        package My::UnixTime;

        use FFI::Platypus;
        use FFI::TinyCC;
        use FFI::TinyCC::Inline 'tcc_eval';

        # store the source of the tm struct
        # for repeated use later
        my $tm_source = <<ENDTM;
          struct tm {
            int tm_sec;
            int tm_min;
            int tm_hour;
            int tm_mday;
            int tm_mon;
            int tm_year;
            int tm_wday;
            int tm_yday;
            int tm_isdst;
            long int tm_gmtoff;
            const char *tm_zone;
          };
        ENDTM

        # calculate the size of the tm struct
        # this time using Tiny CC
        my $tm_size = tcc_eval qq{
          $tm_source
          int main()
          {
            return sizeof(struct tm);
          }
        };

        # To use My::UnixTime as a record class, we need to
        # specify a size for the record, a function called
        # either ffi_record_size or _ffi_record_size should
        # return the size in bytes.  This function has to
        # be defined before you try to define it as a type.
        sub _ffi_record_size { $tm_size };

        my $ffi = FFI::Platypus->new;
        $ffi->lib(undef);
        # define a record class My::UnixTime and alias it
        # to "tm"
        $ffi->type("record(My::UnixTime)" => 'tm');

        # attach the C localtime function as a constructor
        $ffi->attach( [ localtime => '_new' ] => ['time_t*'] => 'tm' );

        # the constructor needs to be wrapped in a Perl sub,
        # because localtime is expecting the time_t (if provided)
        # to come in as the first argument, not the second.
        # We could also acomplish something similar using
        # custom types.
        sub new { _new(\($_[1] || time)) }

        # for each attribute that we are interested in, create
        # get and set accessors.  We just make accessors for
        # hour, minute and second, but we could make them for
        # all the fields if we needed.
        foreach my $attr (qw( hour min sec ))
        {
          my $tcc = FFI::TinyCC->new;
          $tcc->compile_string(qq{
            $tm_source
            int
            get_$attr (struct tm *tm)
            {
              return tm->tm_$attr;
            }
            void
            set_$attr (struct tm *tm, int value)
            {
              tm->tm_$attr = value;
            }
          });
          $ffi->attach( [ $tcc->get_symbol("get_$attr") => "get_$attr" ] => [ 'tm' ] => 'int' );
          $ffi->attach( [ $tcc->get_symbol("set_$attr") => "set_$attr" ] => [ 'tm' ] => 'int' );
        }

        package main;

        # now we can actually use our My::UnixTime class
        my $time = My::UnixTime->new;
        printf "time is %d:%d:%d\n", $time->get_hour, $time->get_min, $time->get_sec;

       Contrast a record type which is stored as a scalar string of bytes in Perl to an opaque
       pointer which is stored as an integer in Perl.  Both are treated as pointers in C
       functions.  The situations when you usually want to use a record are when you know ahead
       of time what the size of the object that you are working with and probably something about
       its structure.  Because a function that returns a structure copies the structure into a
       Perl data structure, you want to make sure that it is okay to copy the record objects that
       you are dealing with if any of your functions will be returning one of them.

       Opaque pointers should be used when you do not know the size of the object that you are
       using, or if the objects are created and free'd through an API interface other than
       "malloc" and "free".

   Fixed length arrays
       Fixed length arrays of native types are supported by FFI::Platypus.  Like pointers, if the
       values contained in the array are updated by the C function these changes will be
       reflected when it returns to Perl space.  An example of using this is the Unix "pipe"
       command which returns a list of two file descriptors as an array.

        use FFI::Platypus;

        my $ffi = FFI::Platypus->new;
        $ffi->lib(undef);
        $ffi->attach([pipe=>'mypipe'] => ['int[2]'] => 'int');

        my @fd = (0,0);
        mypipe(\@fd);
        my($fd1,$fd2) = @fd;

        print "$fd1 $fd2\n";

   Variable length arrays
       [version 0.22]

       Variable length arrays are supported for argument types can also be specified by using the
       "[]" notation but by leaving the size empty:

        $ffi->type('int[]' => 'var_int_array');

       When used as an argument type it will probe the array reference that you pass in to
       determine the correct size.  Usually you will need to communicate the size of the array to
       the C code.  One way to do this is to pass the length of the array in as an additional
       argument.  For example the C code:

        int
        sum(int *array, int size)
        {
          int total,i;
          for(i=0,total=0; i<size; i++)
          {
            total += array[i];
          }
          return total;
        }

       Can be called from Perl like this:

        use FFI::Platypus;

        my $ffi = FFI::Platypus->new;
        $ffi->lib('./var_array.so');

        $ffi->attach( sum => [ 'int[]', 'int' ] => 'int' );

        my @list = (1..100);

        print sum(\@list, scalar @list), "\n";

       Another method might be to have a special value, such as 0 or NULL indicate the
       termination of the array.

   Closures
       A closure (called a "callback" by FFI::Raw, we use the "libffi" terminology) is a Perl
       subroutine that can be called from C.  In order to be called from C it needs to be passed
       to a C function.  To define the closure type you need to provide a list of argument types
       and a return type.  As of this writing only native types and strings are supported as
       closure argument types and only native types are supported as closure return types.  Here
       is an example, with C code:

        /*
         * closure.c - on Linux compile with: gcc closure.c -shared -o closure.so -fPIC
         */

        #include <stdio.h>

        typedef int (*closure_t)(int);
        closure_t my_closure = NULL;

        void set_closure(closure_t value)
        {
          my_closure = value;
        }

        int call_closure(int value)
        {
          if(my_closure != NULL)
            return my_closure(value);
          else
            fprintf(stderr, "closure is NULL\n");
        }

       And the Perl code:

        use FFI::Platypus;

        my $ffi = FFI::Platypus->new;
        $ffi->lib('./closure.so');
        $ffi->type('(int)->int' => 'closure_t');

        $ffi->attach(set_closure => ['closure_t'] => 'void');
        $ffi->attach(call_closure => ['int'] => 'int');

        my $closure1 = $ffi->closure(sub { $_[0] * 2 });
        set_closure($closure1);
        print  call_closure(2), "\n"; # prints "4"

        my $closure2 = $ffi->closure(sub { $_[0] * 4 });
        set_closure($closure2);
        print call_closure(2), "\n"; # prints "8"

       If you have a pointer to a function in the form of an "opaque" type, you can pass this in
       place of a closure type:

        use FFI::Platypus;

        my $ffi = FFI::Platypus->new;
        $ffi->lib('./closure.so');
        $ffi->type('(int)->int' => 'closure_t');

        $ffi->attach(set_closure => ['closure_t'] => 'void');
        $ffi->attach(call_closure => ['int'] => 'int');

        my $closure = $ffi->closure(sub { $_[0] * 6 });
        my $opaque = $ffi->cast(closure_t => 'opaque', $closure);
        set_closure($opaque);
        print call_closure(2), "\n"; # prints "12"

       The syntax for specifying a closure type is a list of comma separated types in
       parentheticals followed by a narrow arrow "->", followed by the return type for the
       closure.  For example a closure that takes a pointer, an integer and a string and returns
       an integer would look like this:

        $ffi->type('(opaque, int, string) -> int' => 'my_closure_type');

       Care needs to be taken with scoping and closures, because of the way Perl and C handle
       responsibility for allocating memory differently.  Perl keeps reference counts and frees
       objects when nothing is referencing them.  In C the code that allocates the memory is
       considered responsible for explicitly free'ing the memory for objects it has created when
       they are no longer needed.  When you pass a closure into a C function, the C code has a
       pointer or reference to that object, but it has no way up letting Perl know when it is no
       longer using it. As a result, if you do not keep a reference to your closure around it
       will be free'd by Perl and if the C code ever tries to call the closure it will probably
       SIGSEGV.  Thus supposing you have a C function "set_closure" that takes a Perl closure,
       this is almost always wrong:

        set_closure(closure { $_[0] * 2 });  # BAD

       In some cases, you may want to create a closure shouldn't ever be free'd.  For example you
       are passing a closure into a C function that will retain it for the lifetime of your
       application.  You can use the sticky keyword to indicate this, without the need to keep a
       reference of the closure:

        set_closure(sticky closure { $_[0] * 2 }); # OKAY

   Custom Types
       Custom Types in Perl

       Platypus custom types are the rough analogue to typemaps in the XS world.  They offer a
       method for converting Perl types into native types that the "libffi" can understand and
       pass on to the C code.

       Example 1: Integer constants

       Say you have a C header file like this:

        /* possible foo types: */
        #define FOO_STATIC  1
        #define FOO_DYNAMIC 2
        #define FOO_OTHER   3

        typedef int foo_t;

        void foo(foo_t foo);
        foo_t get_foo();

       One common way of implementing this would be to create and export constants in your Perl
       module, like this:

        package Foo;

        use FFI::Platypus::Declare qw( void int );
        use base qw( Exporter );

        our @EXPORT_OK = qw( FOO_STATIC FOO_DYNAMIC FOO_OTHER foo get_foo );

        use constant FOO_STATIC  => 1;
        use constant FOO_DYNAMIC => 2;
        use constant FOO_OTHER   => 3;

        attach foo => [int] => void;
        attach get_foo => [] => int;

       Then you could use the module thus:

        use Foo qw( foo FOO_STATIC );
        foo(FOO_STATIC);

       If you didn't want to rely on integer constants or exports, you could also define a custom
       type, and allow strings to be passed into your function, like this:

        package Foo;

        use FFI::Platypus::Declare qw( void );
        use base qw( Exporter );

        our @EXPORT_OK = qw( foo get_foo );

        my %foo_types = (
          static  => 1,
          dynamic => 2,
          other   => 3,
        );
        my %foo_types_reverse = reverse %foo_types;

        custom_type foo_t => {
          native_type    => 'int',
          native_to_perl => sub {
            $foo_types{$_[0]};
          },
          perl_to_native => sub {
            $foo_types_reverse{$_[0]};
          },
        };

        attach foo => ['foo_t'] => void;
        attach get_foo => [] => foo_t;

       Now when an argument of type "foo_t" is called for it will be converted from an
       appropriate string representation, and any function that returns a "foo_t" type will
       return a string instead of the integer representation:

        use Foo;
        foo('static');

       Example 2: Blessed references

       Supposing you have a C library that uses an opaque pointer with a pseudo OO interface,
       like this:

        typedef struct foo_t;

        foo_t *foo_new();
        void foo_method(foo_t *, int argument);
        void foo_free(foo_t *);

       One approach to adapting this to Perl would be to create a OO Perl interface like this:

        package Foo;

        use FFI::Platypus::Declare
          'void', 'int';
        use FFI::Platypus::API qw( arguments_get_string );

        custom_type foo_t => {
          native_type    => 'opaque',
          native_to_perl => sub {
            my $class = arguments_get_string(0);
            bless \$_[0], $class;
          }
          perl_to_native => sub { ${$_[0]} },
        };

        attach [ foo_new => 'new' ] => [ string ] => 'foo_t' );
        attach [ foo_method => 'method' ] => [ 'foo_t', int ] => void;
        attach [ foo_free => 'DESTROY' ] => [ 'foo_t' ] => void;

        my $foo = Foo->new;

       Here we are blessing a reference to the opaque pointer when we return the custom type for
       "foo_t", and dereferencing that reference before we pass it back in.  The function
       "arguments_get_string" queries the C arguments to get the class name to make sure the
       object is blessed into the correct class (for more details on the custom type API see
       FFI::Platypus::API), so you can inherit and extend this class like a normal Perl class.
       This works because the C "constructor" ignores the class name that we pass in as the first
       argument.  If you have a C "constructor" like this that takes arguments you'd have to
       write a wrapper for new.

       I good example of a C library that uses this pattern, including inheritance is
       "libarchive". Platypus comes with a more extensive example in "examples/archive.pl" that
       demonstrates this.

       Example 3: Pointers with pack / unpack

       TODO

       See example FFI::Platypus::Type::StringPointer.

       Example 4: Custom Type modules and the Custom Type API

       TODO

       See example FFI::Platypus::Type::PointerSizeBuffer.

       Example 5: Custom Type on CPAN

       You can distribute your own Platypus custom types on CPAN, if you think they may be
       applicable to others.  The default namespace is prefix with "FFI::Platypus::Type::",
       though you can stick it anywhere (under your own namespace may make more sense if the
       custom type is specific to your application).

       A good example and pattern to follow is FFI::Platypus::Type::StringArray.

       Custom Types in C/XS

       Custom types written in C or XS are a future goal of the FFI::Platypus project.  They
       should allow some of the flexibility of custom types written in Perl, with potential
       performance improvements of native code.

SEE ALSO

       FFI::Platypus
           Main platypus documentation.

       FFI::Platypus::Declare
           Declarative interface for FFI::Platypus.

       FFI::Platypus::API
           Custom types API.

       FFI::Platypus::Type::StringPointer
           String pointer type.

AUTHOR

       Author: Graham Ollis <plicease@cpan.org>

       Contributors:

       Bakkiaraj Murugesan (bakkiaraj)

       Dylan Cali (calid)

       pipcet

       Zaki Mughal (zmughal)

       Fitz Elliott (felliott)

       Vickenty Fesunov (vyf)

       Gregor Herrmann (gregoa)

COPYRIGHT AND LICENSE

       This software is copyright (c) 2015 by Graham Ollis.

       This is free software; you can redistribute it and/or modify it under the same terms as
       the Perl 5 programming language system itself.