I'm trying to use NativeCall to interact with some C functions.
I have a simple C struct, and a function that wants an array of them.
struct foo {
int x;
char *s;
};
struct foo foo_array[3];
foo_array[0].x = 12;
foo_array[0].s = "foo";
foo_array[1].x = 27;
foo_array[1].s = "bar";
foo_array[2].x = -1;
void somefunc(foo_array);
I've tried a bunch of ways, but can't seem to get it quite right.
class foo is repr('CStruct') {
has int32 $.x;
has Str $.s
};
sub somefunc(CArray[foo]) is native { * }
my @foo-array := CArray[foo].new;
@foo-array[0] = ???
@foo-array[1] = ???
@foo-array[2] = ???
somefunc(@foo-array);
How do I properly create an object of class foo and set their values, and how do I make an array of them suitable for passing?
As far as I'm aware, there's no built-in way to do this. However, there's enough rope to hang yourself build a workaround:
role StructArray[Mu:U \T where .REPR eq 'CStruct'] does Positional[T] {
has $.bytes;
has $.elems;
method new(UInt \n) {
self.bless(bytes => buf8.allocate(n * nativesizeof T), elems => n);
}
method AT-POS(UInt \i where ^$!elems) {
nativecast(T, Pointer.new(nativecast(Pointer, $!bytes) + i * nativesizeof T));
}
method pointer {
nativecast(Pointer[T], $!bytes);
}
}
This should allow the following to work:
my @foo-array := StructArray[foo].new(10); # 'array' with 10 elements
@foo-array[0].x = 42;
Interaction with C functions is possible by passing @foo-array.pointer
to a parameter of type Pointer[foo]
. As structures are passed by pointer as well, you could also pass @foo-array[0]
to a parameter of type foo
for the same effect.