rakunativecall

Bit fields in NativeCall


I am trying to create Perl6 bindings for Cgraph, and one of the structs has bit fields set for some of its attributes with values under 8. How should I represent that in my module?

I have tried defining a custom type using the is nativesize(x) trait, but CStructs only support types that are a multiple of 8 bits wide.

C example code:

struct Agtag_s {
    unsigned objtype:2;
}

What I tried:

my native objtype is repr('P6int') is Int is nativesize(2) is export { }
class Agtag is repr('CStruct') is export {
    has objtype $.object-type;
}

Trying to use my module with that code fails with the following error message: CStruct only supports native types that are a multiple of 8 bits wide (was passed: 2)


Solution

  • Here is an example. I assume a function use_struct() is defined in a library libslib :

    #include <stdio.h>
    
    struct Agtag_s {
        unsigned objtype:2;
        unsigned footype:4;
        unsigned bartype:6;
    };
    
    void use_struct (struct Agtag_s *s) {
        printf("sizeof(struct Agtag_s): %ld\n", sizeof( struct Agtag_s ));
        printf("objtype = %d\n", s->objtype);
        printf("footype = %d\n", s->footype);
        printf("bartype = %d\n", s->bartype);
        s->objtype = 3;
        s->footype = 13;
        s->bartype = 55;
    }
    

    Then in Perl 6:

    use v6;
    use NativeCall;
    
    class Agtag is repr('CStruct') is export {
        has int32 $.bitfield is rw;
    }
    
    sub use_struct(Agtag $s is rw) is native("./libslib.so") { * };
    
    my $s = Agtag.new();
    my $objtype = 1;
    my $footype = 7;
    my $bartype = 31;
    $s.bitfield = $objtype +| ($footype +< 2 ) +| ($bartype +< 6);
    say "Calling library function..";
    say "--------------------------";
    use_struct( $s );
    say "After call..";
    say "------------";
    say "objtype = ", $s.bitfield +& 3;
    say "footype = ", ($s.bitfield +> 2) +& 15;
    say "bartype = ", ($s.bitfield +> 6) +& 63;
    

    Output:

    Calling library function..
    --------------------------
    sizeof(struct Agtag_s): 4
    objtype = 1
    footype = 7
    bartype = 31
    After call..
    ------------
    objtype = 3
    footype = 13
    bartype = 55