From: Matt S Trout Date: Sat, 20 Jun 2009 20:49:21 +0000 (-0400) Subject: tentative endeavour at recusive comprehension during serialization perigrinations X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=3aa089043a81238f12264b987ec1d6e20287821a;p=gitmo%2FMooseX-Antlers.git tentative endeavour at recusive comprehension during serialization perigrinations --- diff --git a/tracer.pl b/tracer.pl index 4cee5c5..a58c25a 100644 --- a/tracer.pl +++ b/tracer.pl @@ -49,6 +49,8 @@ extends 'Data::Visitor'; with 'Visitor::NameTracking'; +# dump the lazy when we get a sensible version of D::V on the dev system + has '_traced_refs' => (is => 'ro', lazy => 1, default => sub { {} }); has '_traced_names' => (is => 'ro', lazy => 1, default => sub { {} }); @@ -94,8 +96,49 @@ package Ref::Replacer; # actually be faster for reconstructing structures but it's fairly academic # as yet -#use Moose; -#use Variable::Magic qw(getdata); +use Moose; +# ensure we have next::method available - just because Moose loads it +# as a side effect doesn't mean it's clever to rely on that +use MRO::Compat (); +use Scalar::Util qw(refaddr isweak); +use namespace::clean -except => 'meta'; + +extends 'Data::Visitor'; + +with 'Visitor::NameTracking'; + +has 'external_mappings' => (is => 'ro', lazy => 1, default => sub { {} }); +has 'weaken_these' => (is => 'ro', lazy => 1, default => sub { {} }); +has 'map_these' => (is => 'ro', lazy => 1, default => sub { {} }); + +# fairly sure an around modifier will get severely fucked up here +# in that the copying of @_ will lose the weakness we need to check + +sub visit_ref { + my $self = shift; + + # have to test $_[0] directly since copying a weak ref gives a strong ref + + if (isweak $_[0]) { + $self->weaken_these->{$self->_current_trace_name} = 1; + } + + # if we've got a mapping for a reference (i.e. it's supplied from + # somewhere else) then we need to record where we are and then + # return undef for the fmap process so we serialize an undefined + # value and the fixup puts the external reference back in later + + if (my $m = $self->external_mappings->{refaddr $_[0]}) { + $self->map_these->{$self->_current_trace_name} = $m; + return undef; + } + + return $self->next::method(@_); +} + +# force recursion into objects (Data::Visitor doesn't by default) + +sub visit_object { shift->visit_ref(@_) } }