Callbacks
Callbacks allow native libraries to call Haxe code, for example, to invoke a handler when an event happens. Callbacks in C generally belong to two categories:
- Static callbacks — the native library stores a function pointer directly.
- Callbacks with context — the native library stores a function pointer, as well as an additional
void*
value which is passed back to the function.
In ammer
, a callback is declared using the ammer.ffi.Callback<...>
type, which has 5 type parameters:
ammer.ffi.Callback< CallbackType, FunctionType, CallTarget, CallArgs, Lib >
The type parameters should be filled in as follows:
CallbackType
— The function type as seen by the native library.FunctionType
— The function type as seen by Haxe.CallTarget
— An expression (wrapped in square brackets) to reach thevoid*
value representing the callback context, or"global"
.CallArgs
— An array of expressions representing the arguments to pass to the Haxe function.Lib
— The parentammer
library.
It may be convenient to typedef
callback types when referring to them within ammer
definitions.
Example: declaring and using a callback type
Assuming a C library with the following implementation:
// Type alias for the function type. // It receives two integer arguments, in addition to the user-defined context. int32_t (* callback_type)(int32_t, int32_t, void*); static callback_type *stored_fptr = NULL; static void *stored_context = NULL; void store_callback(callback_type *fptr, void *call_context) { stored_fptr = fptr; stored_context = call_context; } int32_t invoke_callback(int32_t a, int32_t b) { return stored(a, b, stored_context); }
The callback type can be reflected in ammer
as follows:
typedef CallbackType = ammer.ffi.Callback< (ammer.ffi.Int32, ammer.ffi.Int32, Haxe<(Int, Int)->Int>)->ammer.ffi.Int32, (Int, Int)->Int, [arg2], [arg0, arg1], Foobar >;
Note that [arg2]
refers to the third, void*
-typed argument of callback_type
, whereas [arg0, arg1]
refer to the first two, int
-typed arguments.
The ammer
definition for the C library above may look like this:
class Foobar extends ammer.def.Library<"foobar"> { public static function store_callback(_:CallbackType, _:ammer.ffi.Haxe<(Int, Int)->Int>):Void; public static function invoke_callback(_:ammer.ffi.Int32, _:ammer.ffi.Int32):ammer.ffi.Int32; }
Finally, an example of using the library to invoke the callback:
var func = (a:Int, b:Int) -> { return a + b; }; var funcRef = ammer.Lib.createHaxeRef(func); funcRef.incref(); Foobar.store_callback(funcRef); // ... trace(Foobar.invoke_callback(1, 2)); // 3
Note the use of createHaxeRef
: func
is an instance of a Haxe type, thus it must be wrapped with a reference counter as explained in the Haxe types section.