为 Perl 6 NativeCall 结构添加用户模式类型
Adding user mode types for Perl 6 NativeCall structs
Perl 6 docs 列出了一堆类型。其中一些,例如 Str
,具有更复杂的 box/unbox 行为。
是否可以定义我自己的类型,为 box/unboxing 指定我自己的例程?对于一个特定的项目,我有一堆我正在重用的类型,基本上 cut/pasting 我的访问器功能一遍又一遍。
例如,C 结构使用 time_t
,而我插入访问器方法去 to/from DateTime
。另一个例子是逗号分隔的列表,我想去 to/from 和 Array
并自动处理 split
/join
。
有更好的方法吗?
编辑:添加示例:
constant time_t = uint64;
constant FooType_t = uint16;
enum FooType <A B C>;
class Foo is repr('CStruct') is rw
{
has uint32 $.id;
has Str $.name;
has FooType_t $.type;
has time_t $.time;
method name(Str $n?) {
$!name := $n with $n;
$!name;
}
method type(FooType $t?) {
$!type = $t with $t;
FooType($!type);
}
method time(DateTime $d?) {
$!time = .Instant.to-posix[0].Int with $d;
DateTime.new($!time)
}
}
my $f = Foo.new;
$f.id = 12;
$f.name('myname');
$f.type(B);
$f.time(DateTime.new('2000-01-01T12:34:56Z'));
say "$f.id() $f.name() $f.type() $f.time()";
# 12 myname B 2000-01-01T12:34:56Z
这行得通,我可以用 Perl 风格设置 CStruct
的各个字段(没有左值,但我可以将它们作为参数传入)。
现在我想对许多结构中的许多字段使用 time_t
、FooType_t
等,并让它们以相同的方式运行。除了一遍又一遍地复制这些方法,还有更好的方法吗?
也许宏可以帮助解决这个问题?我还没有掌握它们。
您可以编写一个特征来处理在获取或存储属性时的自动属性转换。以下内容应该可以帮助您入门:
multi sub trait_mod:<is>(Attribute:D $attr, :$autoconv!) {
use nqp;
my $name := $attr.name;
$attr.package.^add_method: $name.substr(2), do given $attr.type {
when .REPR eq 'P6int' {
method () is rw {
my $self := self;
Proxy.new:
FETCH => method () {
$autoconv.out(nqp::getattr_i($self, $self.WHAT, $name));
},
STORE => method ($_) {
nqp::bindattr_i($self, $self.WHAT, $name,
nqp::decont($autoconv.in($_)));
}
}
}
default {
die "FIXME: no idea how to handle {.^name}";
}
}
}
例如,以 time_t
:
的用例为例
constant time_t = uint64;
class CTimeConversion {
multi method in(Int $_ --> time_t) { $_ }
multi method in(DateTime $_ --> time_t) { .posix }
method out(time_t $_ --> DateTime) { DateTime.new($_) }
}
class CTimeSpan is repr<CStruct> {
has time_t $.start is autoconv(CTimeConversion);
has time_t $.end is autoconv(CTimeConversion);
}
最后,一些示例代码展示了它的工作原理:
my $span = CTimeSpan.new;
say $span;
say $span.end;
$span.end = DateTime.now;
say $span;
say $span.end;
Perl 6 docs 列出了一堆类型。其中一些,例如 Str
,具有更复杂的 box/unbox 行为。
是否可以定义我自己的类型,为 box/unboxing 指定我自己的例程?对于一个特定的项目,我有一堆我正在重用的类型,基本上 cut/pasting 我的访问器功能一遍又一遍。
例如,C 结构使用 time_t
,而我插入访问器方法去 to/from DateTime
。另一个例子是逗号分隔的列表,我想去 to/from 和 Array
并自动处理 split
/join
。
有更好的方法吗?
编辑:添加示例:
constant time_t = uint64;
constant FooType_t = uint16;
enum FooType <A B C>;
class Foo is repr('CStruct') is rw
{
has uint32 $.id;
has Str $.name;
has FooType_t $.type;
has time_t $.time;
method name(Str $n?) {
$!name := $n with $n;
$!name;
}
method type(FooType $t?) {
$!type = $t with $t;
FooType($!type);
}
method time(DateTime $d?) {
$!time = .Instant.to-posix[0].Int with $d;
DateTime.new($!time)
}
}
my $f = Foo.new;
$f.id = 12;
$f.name('myname');
$f.type(B);
$f.time(DateTime.new('2000-01-01T12:34:56Z'));
say "$f.id() $f.name() $f.type() $f.time()";
# 12 myname B 2000-01-01T12:34:56Z
这行得通,我可以用 Perl 风格设置 CStruct
的各个字段(没有左值,但我可以将它们作为参数传入)。
现在我想对许多结构中的许多字段使用 time_t
、FooType_t
等,并让它们以相同的方式运行。除了一遍又一遍地复制这些方法,还有更好的方法吗?
也许宏可以帮助解决这个问题?我还没有掌握它们。
您可以编写一个特征来处理在获取或存储属性时的自动属性转换。以下内容应该可以帮助您入门:
multi sub trait_mod:<is>(Attribute:D $attr, :$autoconv!) {
use nqp;
my $name := $attr.name;
$attr.package.^add_method: $name.substr(2), do given $attr.type {
when .REPR eq 'P6int' {
method () is rw {
my $self := self;
Proxy.new:
FETCH => method () {
$autoconv.out(nqp::getattr_i($self, $self.WHAT, $name));
},
STORE => method ($_) {
nqp::bindattr_i($self, $self.WHAT, $name,
nqp::decont($autoconv.in($_)));
}
}
}
default {
die "FIXME: no idea how to handle {.^name}";
}
}
}
例如,以 time_t
:
constant time_t = uint64;
class CTimeConversion {
multi method in(Int $_ --> time_t) { $_ }
multi method in(DateTime $_ --> time_t) { .posix }
method out(time_t $_ --> DateTime) { DateTime.new($_) }
}
class CTimeSpan is repr<CStruct> {
has time_t $.start is autoconv(CTimeConversion);
has time_t $.end is autoconv(CTimeConversion);
}
最后,一些示例代码展示了它的工作原理:
my $span = CTimeSpan.new;
say $span;
say $span.end;
$span.end = DateTime.now;
say $span;
say $span.end;