I'm am trying to declare the following C struct in Perl 6:
struct myStruct
{
int A[2]; //<---NEED to declare this
int B;
int C;
};
My problem is that I don't know how to declare the int A[2];
part using the built in NativeCall api.
So for what I have is:
class myStruct is repr('CStruct') {
has CArray[int32] $.A;
has int32 $.B;
has int32 $.C;
};
However, I know that the has CArray[int32] $.A;
part is wrong as it does not declare a part in my struct that takes up ONLY 2 int32
sizes.
Update 2: It turned out that this didn't work at the time I first posted this answer, hence the comments. I still haven't tested it but it must surely work per Tobias's answer to Passing an inlined CArray in a CStruct to a shared library using NativeCall. \o/
I haven't tested this, but this should work when using Rakudo compiler release 2018.05:
use NativeCall;
class myStruct is repr('CStruct') {
HAS int32 @.A[2] is CArray;
has int32 $.B;
has int32 $.C;
}
HAS
instead of has
causes the attribute to be inline rather than a pointer;
int32
instead of int
is because the Perl 6 int
type isn't the same as C's int
type but is instead platform specific (and usually 64 bit);
@
instead of $
marks the attribute as being Positional
("supports looking up values by index") instead of scalar (which gets treated as a single thing);
[2]
"shapes" the Positional data to have 2 elements;
is CArray
binds a CArray
as the Positional data's container logic;
This commit from April this year wired up the is repr('CStruct')
to use the declared attribute information to appropriately allocate memory.
Fwiw I found out about this feature from a search of the #perl6 logs for CArray
and found out it had landed in master and 2018.05 from a search of Rakudo commits for the commit message title.
See Declaring an array inside a Perl 6 NativeCall CStruct
There are other ways, but the easiest is instead of an array, just declare each individual item.
class myStruct is repr('CStruct') {
has int32 $.A0;
has int32 $.A1;
... as many items as you need for your array ...
has int32 $.B;
has int32 $.C;
};
So I've done some experimentation on this and taken a look at the docs and it looks like the CArray type doesn't handle shaping the same way as Perl6 Arrays.
The closest thing you've got it the allocate constructor that preallocates space in the array but it doesn't enforce the size so you can add more things.
Your class definition is fine but you'd want to allocate the array in the BUILD
submethod.
https://docs.raku.org/language/nativecall#Arrays
(Further thought)
You could have two objects. One internal and one for the struct.
The Struct has a CArray[int32]
array. The internal data object has a shaped int32 cast array my int3 @a[2]
. Then you just need to copy between the two.
The getters and setter live on the main object and you use the struct object just when you want to talk to the lib?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With