Hi,

I wanted to make a union to map some type to a byte array and back again so I started off like so;

# example class I want to map to a byte array
class N-GtkTargetEntry is repr('CStruct') is export {
  has Str $.target;
  has guint $.flags;
  has guint $.info;

  submethod BUILD ( Str :$target, Int :$!flags, Int :$!info ) {
    $!target := $target;
  }
}


# mapper class/union
class TargetEntryBytes is repr('CUnion') {
  HAS N-GtkTargetEntry $.target-entry;
  HAS CArray[uint8] $.target-bytes;

  multi submethod BUILD ( N-GtkTargetEntry :$target-entry! ) {
    $!target-entry := $target-entry;
  }

  multi submethod BUILD ( CArray[uint8] :$target-bytes! ) {
    $!target-bytes := $target-bytes;
  }
}


The first build method of classTargetEntryBytesis doing well and when setting the $!target-entry I can retrieve the bytes from $!target-bytes.

Now, the second build method gives problems. I get nonsense values for the fields of $!target-entry when I want to set the $!target-bytes.

The next try did not improve matters

  multi submethod BUILD ( CArray[uint8] :$target-bytes! ) {
    $!target-bytes := CArray[uint8].new;
    my Int $array-size = nativesizeof(N-GtkTargetEntry);
    for ^$array-size -> $i {
      $!target-bytes[$i] = $target-bytes[$i];
    }
  }

What I think is happening is that only an address is stored there pointing to an array elsewhere which does not map to the other union member. In this situation, the creation of the array does not take the 'HAS' (uppercased!) attribute declaration into account.


I get a good result when the line '$!target-bytes := CArray[uint8].new;' is changed to '$!target-entry := N-GtkTargetEntry.new( :target(''), :flags(0), :info(0));' making space by setting a dummy $target-entry first and then overwrite the data by writing in $target-bytes.

The question: is it a bug or is this known behavior?
Anyways, it might be a good thing to know about,

Regards,
Marcel

Reply via email to