NAME

Dyn::Callback - Perl Code as FFI Callbacks

SYNOPSIS

use Dyn::Callback qw[:all];
use Dyn::Load;
use Dyn::Call qw[DC_CALL_C_DEFAULT];
my $lib = Dyn::Load::dlLoadLibrary('path/to/lib.so');
my $ptr = Dyn::Load::dlFindSymbol( $lib, 'timer' );
my $cvm = dcNewCallVM(1024);
Dyn::Call::dcMode( $cvm, DC_CALL_C_DEFAULT );
Dyn::Call::dcReset($cvm);
my $cb = dcbNewCallback(       # Accepts an int and returns an int
    'i)i',
    sub {
        my ($cb, $args, $result, $userdata) = @_;
        ...;                   # do something
        return 'i';
    },
    5
);
Dyn::Call::dcArgPointer( $cvm, $cb );    # pass callbacks as pointers
Dyn::Call::dcCallVoid( $cvm, $ptr );     # your timer() function returns void

DESCRIPTION

Dyn::Callback is an interface to create callback objects that can be passed to functions as callback arguments. In other words, a pointer to the callback object can be "called" directly from the foreign library.

Functions

These may be imported by name or called directly.

dcbNewCallback( $signature, $coderef, $userdata )

Creates a new callback object, where $signature is a signature string describing the function.

my $pcb = dcbNewCallback(
    'i)i',
    sub {
        my ($cb, $args, $result, $userdata) = @_;
        ...;
        return 'i';
    },
    5
);

Expected parameters include:

signature - string describing any parameters and return value

This is needed for dyncallback dyncallback to correctly prepare the arguments passed in by the function that calls the callback handler.

code - a code reference

Note that the code reference doesn't return the value specified in the signature, directly, but a signature character, specifying the return value's type. The return value itself is stored where the callback's 3rd parameter points to (see below).

userdata - optional, arbitrary data

This data, if defined, is passed back to the given coderef as the 4th parameter.

dcbInitCallback( ... )

Initialize (or reinitialize) the callback object.

dcbInitCallback( $pcb, 'i)Z', sub { ...; }, undef );

Expected parameters include:

pcb - Dyn::Callback object to reinitialize
signature - string describing any parameters and return value
code - a code reference
userdata - optional, arbitrary data

dcbFreeCallback( ... )

Destroys and frees the callback.

dcbFreeCallback( $pcb );

Expected parameters include:

pcb - Dyn::Callback object to reinitialize

dcbGetUserData( ... )

Returns the userdata passed to the callback object on creation or initialization.

my $data = dcbGetUserData( $pcb );

Expected parameters include:

pcb - Dyn::Callback object to query

Example

Let's say, we want to create a callback object and call it. For simplicity, this example will omit passing it as a function pointer to a function in a separate library and demonstrate calling it directly. First, we need to define our callback handler:

sub cbHandler {
    my ( $cb, $args, $result, $userdata ) = @_;

    # $cb is a Dyn::Callback object
    # $args is a Dyn::Callback::Args object
    # $result is a Dyn::Callback::Value object
    # $userdata, if defined, is a normal Perl value
    my $arg1 = dcbArgInt($args);
    my $arg2 = dcbArgFloat($args);
    my $arg3 = dcbArgShort($args);
    my $arg4 = dcbArgDouble($args);
    my $arg5 = dcbArgLongLong($args);

    # do something here
    $result->s(1244);
    return 's';
}

Note that the return value of the handler is a signature character, not the actual return value, itself. Now, let's call it through a Dyn::Callback object:

my $userdata = 1337;
my $cb       = dcbNewCallback( 'ifsdl)s', \&cbHandler, $userdata );
my $result   = $cb->call( 123, 23, 3, 1.82, 9909 );                   # $result is 1244
dcbFreeCallback($cb);

LICENSE

Copyright (C) Sanko Robinson.

This library is free software; you can redistribute it and/or modify it under the terms found in the Artistic License 2. Other copyrights, terms, and conditions may apply to data transmitted through this module.

AUTHOR

Sanko Robinson <sanko@cpan.org>