Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create FFI::C::Array with preexisting objects rather than hash references #53

Open
sanko opened this issue Jun 11, 2021 · 2 comments
Open

Comments

@sanko
Copy link

sanko commented Jun 11, 2021

I'm trying to find a way to pass an array of ::Struct based objects into a newly created ::Array. Here's an example of my goal based on the synopsis from FFI::C::Array:

    use FFI::C::ArrayDef;
    use FFI::C::StructDef;
 
    my $point_def = FFI::C::StructDef->new(
      name  => 'point_t',
      class => 'Point',
      members => [
        x => 'double',
        y => 'double',
      ],
    );
     
    my $rect_def = FFI::C::ArrayDef->new(
      name    => 'rectangle_t',
      class   => 'Rectangle',
      members => [
        $point_def, 2,
      ]
    );
    
    # create a rectangle using the def's create method
    my $square = $rect_def->create([
       Point->new( {x => 1.0, y => 1.0} ), # Obtained somehow as full objects...
       Point->new( {x => 2.0, y => 2.0} )  # ...rather than hash references
    ]);
    
    printf "[[%d %d][%d %d]]\n",
      $square->[0]->x, $square->[0]->y,
      $square->[1]->x, $square->[1]->y;   # [[1 1][2 2]]

In my project, I would have these Point objects returned from C by yet another attached function. My only solution to FFI::C::Util::perl_to_c(...) croaking on this is to map { ... } the objects back to plain hash references and let FFI::C::Def instantiate brand new objects with the exposed data (this would break on complex C objects). Before I start looking for a place to do this quickly and cleanly enough for a PR (maybe), am I missing something obvious?

@plicease
Copy link
Member

What you want to do is pass in an array of hash references to the create $rect_def->create call like so:

# create a rectangle using the def's create method
my $square = $rect_def->create([
   {x => 1.0, y => 1.0}, # Obtained somehow as full objects...
   {x => 2.0, y => 2.0}   # ...rather than hash references
]);

This saves you from explicitly having to call perl_to_c. Then the script works:

% perl foo.pl 
[[1 1][2 2]]

You unfortunately cannot build up an C array from existing point objects because in C an array is contiguous memory, and the Point objects would have to be copied (I think doing an implicit copy in this situation would be a confusing interface). You can still get the point objects once the array has been created though:

my $point1 = $square->[0];
printf "[%d %d]\n", `$pint1->x,` $point1->y;   # [1 1]

That isn't a copy, that is the actual element in contiguous memory of the array:

$point1->x(3);
printf "[[%d %d][%d %d]]\n",
  $square->[0]->x, $square->[0]->y,
  $square->[1]->x, $square->[1]->y;   # [[3 1][2 2]]

@plicease
Copy link
Member

A copy from an existing object could be a useful thing to do, but if that really is what you are trying to do I think we want to think about how to work the interface so that it is clear that is what is happening.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants