« Previous  |  Next »

DemoFFI - Type Mapping

17 March 2016

I've pushed another update to libffidemo, adding the class DemoFFITypeMappedThing and tests. With Pharo v50647 image's UFFI enhancements, all DemoFFI tests pass.

DemoFFITypeMappedThing allows using the C typedef demo_thing in #ffiCall: function signatures:

DemoFFILibrary>>apiAllocByMappedPointerPointer: handle
    "int alloc_by_pointer_pointer(demo_thing**)"
    ^ self ffiCall: #(int alloc_by_pointer_pointer (demo_thing **handle))

The C and Smalltalk signatures match. The ability to specify #ffiCall: function signatures very much like the actual C function signatures should make it easier to create bindings for UFFI.

The magic of DemoFFITypeMappedThing lies in FFIOpaqueObject, and,

DemoFFILibrary class>>initializeTypeMap
    TypeMap := Dictionary newFromPairs: #(
        demo_thing    FFIOpaqueObject
    )

With the above, UFFI maps (a pointer to) demo_thing in #ffiCall: signature to FFIOpaqueObject.

Compare and contrast with the earlier versions of DemoFFI:

DemoFFILibrary>>apiAllocByPointerPointer: handle
    "int alloc_by_pointer_pointer(demo_thing**)"
    ^ self ffiCall: #(int alloc_by_pointer_pointer (DemoFFIExternalObject *handle))

Notice "demo_thing**" in the C signature, and "DemoFFIExternalObject*" in the Smalltalk signature. Conceptually, DemoFFIExternalObject represents a pointer to demo_thing, hence "demo_thing**" == "DemoFFIExternalObject*". Still, the difference in number of asterisks can cause confusion or result in subtle typo's.

Sometimes, it may be worth creating subclasses of FFIOpaqueObject to represent pointers to different C structure types. One may think of FFIOpaqueObject as a generic "void*", and, say, DemoFFIExternalObject as "demo_thing*", or, NBSQLite3DatabaseExternalObject as "sqlite3*" and NBSQLite3StatementExternalObject as "sqlite3_stmt*".

Blog comments powered by Disqus