wizard#
Create a wizard: an opaque bundle of magic callbacks.
Synopsis#
use Peta::XS ':magic';
my $w = wizard(
get => sub { my ($ref, $data) = @_; ... },
set => sub { my ($ref, $data) = @_; ... },
free => sub { my ($ref, $data) = @_; ... },
data => sub { my ($ref, @args) = @_; return { count => 0 } },
);
What you get back#
An opaque handle. Hold it, pass it to cast, dispell and getdata - nothing else. One wizard can be cast on any number of variables; each attachment gets its own private data.
Contract#
All keys are optional but at least one of get/set/free is required; every value must be a code reference (anything else croaks, as does an unknown key). get is called before the variable’s value is used, set after it changed, free while it is being destroyed; each receives (\$var, $data) and its return value is ignored (no value substitution in v1). data is called once per cast to build that attachment’s private data. A callback that dies propagates exactly like a dying tied-variable FETCH/STORE. A variable carrying wizard magic is never JIT-compiled, so callbacks fire on every single access, compiled neighbors notwithstanding.
Examples#
## a watchpoint: who is touching $config?
my $watch = wizard(
get => sub { warn "read at @{[ join ':', caller ]}\n" },
set => sub { warn "now: ${$_[0]}\n" },
);
## lazy initialization: get may write the variable before the
## pending read uses it (magic is suspended inside callbacks, so
## this does not recurse)
my $lazy = wizard(get => sub { ${$_[0]} //= expensive() });
my $val;
cast(\$val, $lazy);
say $val; # expensive() runs here, exactly once
say $val; # cached now
## per-attachment counters via a data callback
my $counted = wizard(
data => sub { { reads => 0, writes => 0 } },
get => sub { $_[1]{reads}++ },
set => sub { $_[1]{writes}++ },
);