如何在Perl6 NativeCall结构中定义固定长度的字符串?

时间:2017-09-29 03:08:17

标签: perl6 nativecall

我有一个第三方C库,它定义了一个类似于:

的结构
struct myStruct {
  int a;
  int b;
  char str1[32];
  char str2[32];
};

一个函数,它接受一个指向这个结构的指针并填充它。我需要我的Perl6本机调用来提供该结构,然后读取结果。

到目前为止,我已经在Perl6中定义了结构:

class myStruct is repr('CStruct') {
  has int32 $.a;
  has int32 $.b;
  has Str $.str1; # Option A: This won't work as Perl won't know what length to allocate
  has CArray[uint8] $.str2; # Option B: This makes more sense, but again how to define length?  
                     # Also, would this allocate the array in place, or 
                     #    reference an array that is separately allocated (and therefore not valid)?
}

和本地电话一样:

sub fillStruct(myStruct) is native('test_lib') { ... }
my $struct = myStruct.new();
fillStruct($struct); # Gives a seg fault with any variation I've tried so far

我该如何做到这一点?

3 个答案:

答案 0 :(得分:2)

正如其他人所说,目前似乎没有办法实现这一目标。

我已经尝试将新的C函数定义为变通方法。该函数有效地充当一个访问器方法,只返回我需要的字段作为离散的NativeCall友好指针。

希望社区能够在某些时候为这个案例提供适当的支持。

答案 1 :(得分:1)

在撰写本文时,似乎并未处理此事 作为一种解决方法,我的看法是让宏生成32 int8,充分放置字段名称。

答案 2 :(得分:0)

从2020年7月开始,您应该可以执行以下操作:

sub setCharArray($a, $s, $l, $c is rw) {
  die 'Too many chars!' unless $s.chars <= $l;;

  $c = $s if $c;
  my $chars = $a.encode;
  $a[$_] = $chars[$_] for ^$chars.elems;
  $a[$chars.elems] = 0 unless $s.elems == 128;
}

class A repr<CStruct> is export {
  HAS uint8 @!myString[128] is CArray;

  state Str $cached;

  method myString is rw {
    Proxy.new:
      FETCH => sub($) {
        return if $cached;
        $cached = Buf.new(@!myString).decode
     },

     STORE => $, Str $s is raw {
       setCharArray(@!myString, $s, 128, $cached);
     }
  }
  
}

让我解释一下:

在NativeCall中已经有一段时间定义静态大小元素的“ HAS”声明符了,所以这不是实验部分。棘手的部分是“方法myString”。它允许类A的使用者设置@!myString属性并从中获取属性,就好像它是适当的属性,而不是数组一样。

如果首先从C中读取@!myString中的数据,则$ cache状态变量将为空。然后通过解码的Buf创建Str对象并返回。希望对用户隐藏对象实现中看到的复杂性,以便:

my $a = c_function_that_returns_A();
$a.myString;

...将按预期工作,并且类似:

$a.myString = 'Crab';

...也可以正常工作。

不幸的是,像setCharArray()这样的辅助函数需要迭代设置@!myString,但希望将来会改变。

重要注意事项-此实现假定一旦分配了对象,对@!myString的更改仅限于Raku端,否则,一旦设置,$ cached值将对其进行屏蔽。目前,我还没有真正的解决方法,除非您想花费时间来每次需要访问@!myString时都创建一个新的Str a-fresh。