如何将用户数据传递给回调函数

Fer*_*ata 7 c callback perl6 nativecall raku

我正在使用NativeCall接口; 有一个接受回调的C函数,定义如下:

typedef void (* ExifContentForeachEntryFunc) (ExifEntry *, void *user_data);
void exif_content_foreach_entry (ExifContent *content, ExifContentForeachEntryFunc func, void *user_data);
Run Code Online (Sandbox Code Playgroud)

我的第一次采取是:

sub exif_content_foreach_entry(ExifContent $exifcontent, &func (ExifEntry $entry, Buf $data), Buf $user_data) is native(LIB) is export { * }
Run Code Online (Sandbox Code Playgroud)

但是在调用时,此函数会生成错误:

Internal error: unhandled dyncall callback argument type
  in method CALL-ME at /opt/rakudo-pkg/share/perl6/sources/24DD121B5B4774C04A7084827BFAD92199756E03 (NativeCall) line 588
Run Code Online (Sandbox Code Playgroud)

如果我忽略user_data参数,一切正常,所以声明的其余部分都没问题:我只是不能将任何额外的数据传递给回调函数.

在其他情况下,我使用Buf将(可能的)二进制数据块传递给C函数并且它工作; 这里的区别是回调函数.知道如何解决这个问题吗?

(使用perl6 2018.03)

Håk*_*and 4

我不确定如何将 aBuf作为用户数据传递,因为Buf它不是本机类型。但你可以使用例如 aCStruct代替:

class UserData is repr('CStruct') {
    has int32 $.dummy;
}
Run Code Online (Sandbox Code Playgroud)

那么声明将是:

sub exif_content_foreach_entry(
    ExifContent $exifcontent, 
    &func (ExifEntry $entry, UserData $data),
    UserData $user_data) is native(LIB) is export { * }
Run Code Online (Sandbox Code Playgroud)

回调可以声明和定义,例如:

sub my-callback (ExifEntry $entry, UserData $data) {
    say "In callback";
    say "Value of data: ", $data.dummy;
}
Run Code Online (Sandbox Code Playgroud)

编辑

这是一种使用闭包将 Perl 6 类型Buf(即不是本机类型)传递给回调的解决方法。例如:

my $buf = Buf.new( 1, 2, 3);
my $callback = my sub (ExifEntry $entry, UserData $data) {
    my-callback( $entry, $buf);
}
Run Code Online (Sandbox Code Playgroud)

my-callback然后像这样声明真正的回调:

sub my-callback (ExifEntry $entry, Buf $data) {
    say "In callback";
    say "Value of data: ", $data;
}
Run Code Online (Sandbox Code Playgroud)

并像这样调用库函数:

exif_content_foreach_entry( $content, &$callback, $data );
Run Code Online (Sandbox Code Playgroud)