COMMUNITY

How to bind C Struct to HashLink

I’ll try and keep things simple.

I wish to writing bindings to an arbitrary C library. However, this library uses struct values. Example:

typedef struct { int a; int b; } MyThing;
MyThing createThing();
void useThing(MyThing t);

What would be the best way to go about implementing these functions? I don’t need to access the struct’s properties in the Haxe context, I just want to pass it between functions provided by the library. Preferably, the outputted HL/C code would simply pass around the “MyThing” value, but I’m having difficulty finding the correct way to set it up that way using the current HashLink/C examples.

The difficult part is these functions are not using pointers, so some of the typical options (like _ABSTRACT(MyThing) and hl.Abstract<"MyThing">) do not seem appropriate. Of course, I could wrap the functions and use “malloc”/“free” to force them into using “MyThing” pointers, but it’d be messy and require a manual destroy function instead of using garbage collection.

I also considered _OBJ(_I32 _I32) (of course, adding the hl_type* to a custom struct), but it’s still a little annoying since I cannot simply pass the struct into the function; instead, I must reconstruct it using the properties from the special struct containing hl_type* every time the function is called. Plus, once again, I don’t know how to represent structs that contain other struct “values”, i.e: typedef struct { MyThing one; MyThing two; } MyThingContainer;

Reading the HashLink API, there appears to be functions that allocate memory for the garbage collection. Perhaps I could use a special “malloc” to store and “pointer-ize” MyThing? If there is, I’m having trouble figuring it out. Perhaps I need to make my own hl_type instance?

Any guidance on the proper way to handle this scenario would be greatly appreciated!

Hi!

I wrote a little entry about a sample binding HashLink/C I did for learning purposes

hope this helps

1 Like

Thank you so much!

But, well, I guess there’s no way to expose a struct directly. I suppose with a garbage collected environment, it wouldn’t make sense. Oh well. :0

If I understand correctly, I guess you don’t need to pass MyThing, see hl.uv.Loop.hx and libs/uv/uv.c

For allocating, you could use hl_gc_alloc_noptr() for simple struct*, And if have a field in the struct* is a pointer that also allocated by the GC, then use hl_gc_alloc_raw()

On the haxe side, if it is a simple struct, I think it should be able to be created by hl.Bytes:

// This could be built automatically by haxe macro
abstract MyThing(hl.Bytes) {
    public var a(get, set) : Int ;
    public var b(get, set) : Int ;
    public inline function new() {
        this = new hl.Bytes(8);
    }
    inline function get_a() return this.getI32(0);
    inline function get_b() return this.getI32(4);
    inline function set_a(v:Int) {
        this.setI32(0, v);
        return v;
    }
    inline function set_b(v:Int) {
        this.setI32(4, v);
        return v;
    }
}