develooper Front page | perl.perl6.users | Postings from June 2021

native union structure

From:
Marcel Timmerman
Date:
June 1, 2021 12:54
Subject:
native union structure
Message ID:
2d78d727-7aa4-0bc7-abbe-233dfecd5458@gmail.com
Hi,

(I reposted this because I did not saw it appear on the mailing list and 
added some new info)

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 class N-TargetEntryBytes is 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 set the $!target-bytes.

Then, the next attempt for the BUILD 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 here is that only an address is stored, 
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 better result when the line '$!target-bytes := 
CArray[uint8].new;' is replaced by  '$!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.

Still not correct, the target value in the N-GtkTargetEntry keeps the 
string value I set, i.e. the empty string ''. Flags and info are now ok.

Final changes shown below give the proper outcome, i.e. the target 
string, flags and info  in the N-GtkTargetEntryclassare now set to the 
correct values! (Change is that the init of N-GtkTargetEntry in the 2nd 
BUILD is called without the :target argument)


class N-GtkTargetEntry is repr('CStruct') is export {
   has Str $.target;
   has guint $.flags;
   has guint $.info;

   submethod BUILD ( Str :$target?, Int :$!flags = 0, Int :$!info = 0 ) {
     $!target := $target if $target.defined;
   }
}

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! ) {
     # need to make dummy to create proper space
     $!target-entry := N-GtkTargetEntry.new;

     my Int $array-size = nativesizeof(N-GtkTargetEntry);

     for ^$array-size -> $i {
       $!target-bytes[$i] = $target-bytes[$i];
     }
   }
}



The question: is there an explanation for this behavior because I do not 
understand it completely why it should be written like this ? It feels 
that there are some quirks where you need to program around it and 
afraid that it might change later without warning?


Regards,
Marcel




nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About