#if VMG_UVAR
STATIC I32 vmg_svt_val(pTHX_ IV action, SV *sv) {
struct ufuncs *uf;
- MAGIC *mg;
- SV *key = NULL;
+ MAGIC *mg, *umg;
+ SV *key = NULL, *newkey = NULL;
- mg = mg_find(sv, PERL_MAGIC_uvar);
- /* mg can't be NULL or we wouldn't be there. */
- key = mg->mg_obj;
- uf = (struct ufuncs *) mg->mg_ptr;
+ umg = mg_find(sv, PERL_MAGIC_uvar);
+ /* umg can't be NULL or we wouldn't be there. */
+ key = umg->mg_obj;
+ uf = (struct ufuncs *) umg->mg_ptr;
if (uf[1].uf_val != NULL) { uf[1].uf_val(aTHX_ action, sv); }
if (uf[1].uf_set != NULL) { uf[1].uf_set(aTHX_ action, sv); }
|| (mg->mg_private < SIG_MIN)
|| (mg->mg_private > SIG_MAX)) { continue; }
w = SV2MGWIZ(mg->mg_ptr);
- if (!w->uvar) { continue; }
+ switch (w->uvar) {
+ case 0:
+ continue;
+ case 2:
+ if (!newkey)
+ newkey = key = umg->mg_obj = sv_2mortal(newSVsv(umg->mg_obj));
+ }
switch (action) {
case 0:
if (w->cb_fetch) { vmg_cb_call2(w->cb_fetch, sv, mg->mg_obj, key); }
+ 1
#endif /* MGf_LOCAL */
#if VMG_UVAR
- + 4
+ + 5
#endif /* VMG_UVAR */
) { croak(vmg_wrongargnum); }
VMG_SET_CB(ST(i++), store);
VMG_SET_CB(ST(i++), exists);
VMG_SET_CB(ST(i++), delete);
+ cb = ST(i++);
+ if (w->cb_fetch || w->cb_store || w->cb_exists || w->cb_delete)
+ w->uvar = SvTRUE(cb) ? 2 : 1;
+ else
+ w->uvar = 0;
#endif /* VMG_UVAR */
#if VMG_MULTIPLICITY
w->owner = aTHX;
#endif /* VMG_MULTIPLICITY */
-
- w->vtbl = t;
- w->sig = sig;
-#if VMG_UVAR
- w->uvar = (w->cb_fetch || w->cb_store || w->cb_exists || w->cb_delete);
-#endif /* VMG_UVAR */
+ w->vtbl = t;
+ w->sig = sig;
sv = MGWIZ2SV(w);
mg = sv_magicext(sv, NULL, PERL_MAGIC_ext, &vmg_wizard_vtbl, NULL, 0);
sub wizard {
croak 'Wrong number of arguments for wizard()' if @_ % 2;
my %opts = @_;
- my @cbs = qw/sig data get set len clear free/;
- push @cbs, 'copy' if MGf_COPY;
- push @cbs, 'dup' if MGf_DUP;
- push @cbs, 'local' if MGf_LOCAL;
- push @cbs, qw/fetch store exists delete/ if VMG_UVAR;
- my $ret = eval { _wizard(map $opts{$_}, @cbs) };
+ my @keys = qw/sig data get set len clear free/;
+ push @keys, 'copy' if MGf_COPY;
+ push @keys, 'dup' if MGf_DUP;
+ push @keys, 'local' if MGf_LOCAL;
+ push @keys, qw/fetch store exists delete copy_key/ if VMG_UVAR;
+ my $ret = eval { _wizard(map $opts{$_}, @keys) };
if (my $err = $@) {
$err =~ s/\sat\s+.*?\n//;
croak $err;
use strict;
use warnings;
-use Config qw/%Config/;
-
use Test::More;
use Variable::Magic qw/wizard cast dispell VMG_UVAR/;
if (VMG_UVAR) {
- plan tests => 2 * 9 + 7 + 12 + 1;
+ plan tests => 2 * 10 + 8 + 14 + 1;
} else {
plan skip_all => 'No nice uvar magic for this perl';
}
check { $x = delete $h{z} } { delete => 1 }, 'delete non-existing key';
ok !defined $x, 'uvar: delete non-existing key correctly';
-my $wiz2 = wizard fetch => sub { 0 };
+my $wiz2 = wizard get => sub { 0 };
+cast %h, $wiz2;
+
+check { $x = $h{a} } { fetch => 1 }, 'fetch directly with also non uvar magic';
+is $x, 1, 'uvar: fetch directly with also non uvar magic correctly';
+
+$wiz2 = wizard fetch => sub { 0 };
my %h2 = (a => 37, b => 2, c => 3);
cast %h2, $wiz2;
is $@, '', 'uvar: store with incomplete magic doesn\'t croak';
is $h2{a}, 73, 'uvar: store with incomplete magic correctly';
-my $wiz3 = wizard store => sub { ++$_[2]; 0 };
+my $wiz3 = wizard store => sub { ++$_[2]; 0 }, copy_key => 1;
my %h3 = (a => 3);
cast %h3, $wiz3;
for my $i (1 .. 2) {
- eval { my $key = 'a'; $h3{$key} = 3 + $i };
+ my $key = 'a';
+ eval { $h3{$key} = 3 + $i };
is $@, '', "uvar: change key in store doesn't croak ($i)";
+ is $key, 'a', "uvar: change key didn't clobber \$key ($i)";
is_deeply \%h3, { a => 3, b => 3 + $i },
"uvar: change key in store correcty ($i)";
}
-my $ro_bare_hk = $] >= 5.010 && $Config{useithreads};
-diag 'This perl has readonly bare hash keys' if $ro_bare_hk;
-
for my $i (1 .. 2) {
eval { $h3{b} = 5 + $i };
- if ($ro_bare_hk) {
- like $@, qr/Modification\s+of\s+a\s+read-only\s+value/,
- "uvar: change readonly key in store croaks ($i)";
- is_deeply \%h3, { a => 3, b => 5 },
- "uvar: change readonly key in store correcty ($i)";
- } else {
- is $@, '', "uvar: change readonly key in store croaks ($i)";
- is_deeply \%h3, { a => 3, b => 5, c => 6, (d => 7) x ($i >= 2) },
+ is $@, '', "uvar: change readonly key in store croaks ($i)";
+ is_deeply \%h3, { a => 3, b => 5, c => 5 + $i },
"uvar: change readonly key in store correcty ($i)";
- }
}
-