File Coverage

blib/lib/Data/Transform/ExplicitMetadata.pm
Criterion Covered Total %
statement 265 282 93.9
branch 138 172 80.2
condition 53 77 68.8
subroutine 35 38 92.1
pod 2 2 100.0
total 493 571 86.3


line stmt bran cond sub pod time code
1             package Data::Transform::ExplicitMetadata;
2              
3 5     5   2163 use strict;
  5         30  
  5         113  
4 5     5   21 use warnings;
  5         10  
  5         96  
5              
6 5     5   20 use Scalar::Util;
  5         8  
  5         338  
7 5     5   1975 use Symbol;
  5         3574  
  5         287  
8 5     5   29 use Carp;
  5         8  
  5         337  
9 5     5   26 use Fcntl qw(F_GETFL O_WRONLY O_RDWR O_APPEND);
  5         9  
  5         233  
10              
11             our $VERSION = "0.09";
12              
13 5     5   24 use base 'Exporter';
  5         9  
  5         833  
14              
15             our @EXPORT_OK = qw( encode decode );
16              
17             our $HAS_FMODE;
18             BEGIN {
19 5   50 5   17 $HAS_FMODE = eval { require FileHandle::Fmode } || '';
20             }
21              
22             sub _get_open_mode_filehandle_fmode {
23 5     5   29 my $fh = shift;
24              
25 5 50       13 return unless FileHandle::Fmode::is_FH($fh);
26              
27 5         60 my $is_append = FileHandle::Fmode::is_A($fh);
28 5 100       92 if (FileHandle::Fmode::is_WO($fh)) {
    100          
29 2 100       38 return $is_append ? '>>' : '>';
30             } elsif (FileHandle::Fmode::is_RW($fh)) {
31 2 100       65 return $is_append ? '+>>' : '+<';
32             } else {
33 1         42 return '<';
34             }
35             }
36              
37             sub _get_open_mode_fcntl {
38 7     7   12 my $fh = shift;
39              
40 5     5   6376 my $flags = eval { no warnings 'uninitialized';
  5         9  
  5         5489  
  7         10  
41 7         71 fcntl($fh, F_GETFL, my $junk) };
42 7 50       23 return unless $flags;
43              
44 7         13 my $is_append = $flags & O_APPEND;
45 7 100       27 if ($flags & O_WRONLY) {
    100          
46 3 100       14 return $is_append ? '>>' : '>';
47             } elsif ($flags & O_RDWR) {
48 2 100       8 return $is_append ? '+>>' : '+<';
49             } else {
50 2         19 return '<';
51             }
52             }
53              
54             sub _get_open_mode {
55 12     12   20 my $fh = shift;
56              
57 12   66     25 return _get_open_mode_fcntl($fh)
58             ||
59             ($HAS_FMODE && _get_open_mode_filehandle_fmode($fh));
60             }
61              
62             sub encode {
63 138     138 1 62172 my $value = shift;
64 138         201 my $path_expr = shift;
65 138         177 my $seen = shift;
66              
67 138 100       276 if (!ref($value)) {
68 63         85 my $ref_to_value = \$value;
69 63         149 my $refaddr = Scalar::Util::refaddr($ref_to_value);
70 63         103 my $ref = ref($ref_to_value);
71 63         83 my $encoded_value = $value;
72             # perl 5.8 - ref() with a vstring returns SCALAR
73 63 100 66     274 if ($ref eq 'GLOB'
      66        
74             or
75             $ref eq 'VSTRING' or Scalar::Util::isvstring($value)
76             ) {
77 1         4 $encoded_value = encode($ref_to_value, $path_expr, $seen);
78 1         3 delete $encoded_value->{__refaddr};
79 1         3 delete $seen->{$refaddr};
80             }
81 63         169 return $encoded_value;
82             }
83              
84 75   100     217 $path_expr ||= '$VAR';
85 75   100     252 $seen ||= {};
86              
87 75         166 my $reftype = Scalar::Util::reftype($value);
88 75         126 my $refaddr = Scalar::Util::refaddr($value);
89 75         123 my $blesstype = Scalar::Util::blessed($value);
90              
91 75         94 my $encoded_value;
92              
93 75 100       174 if ($seen->{$refaddr}) {
94             $encoded_value = { __reftype => $reftype,
95             __refaddr => $refaddr,
96             __recursive => 1,
97 7         23 __value => $seen->{$refaddr} };
98 7 100       17 $encoded_value->{__blessed} = $blesstype if $blesstype;
99 7         22 return $encoded_value;
100             }
101 68         145 $seen->{$refaddr} = $path_expr;
102              
103             # Build a new path string for recursive calls
104             my $_p = sub {
105 102 100 100 102   556 return join('', '${', $path_expr, '}') if ($reftype eq 'SCALAR' or $reftype eq 'REF');
106 74 100       198 return join('', '*{', $path_expr, '}') if ($reftype eq 'GLOB');
107              
108 42 100       117 my @bracket = $reftype eq 'ARRAY' ? ( '[', ']' ) : ( '{', '}' );
109 42         231 return sprintf('%s->%s%s%s', $path_expr, $bracket[0], $_, $bracket[1]);
110 68         225 };
111              
112 68 100       161 if (my $tied = _is_tied($value)) {
113 4         8 local $_ = 'tied'; # &$_p needs this
114 4         9 my $original = encode(_untie_and_get_original_value($value), &$_p, $seen);
115             $encoded_value = { __reftype => $reftype,
116             __refaddr => $refaddr,
117 4 100       21 __tied => ref($original) ? $original->{__value} : $original,
118             __value => encode($tied, &$_p, $seen) };
119 4         12 _retie($value, $tied);
120 4 50       9 $encoded_value->{__blessed} = $blesstype if $blesstype;
121 4         23 return $encoded_value;
122             }
123              
124 64 100 100     392 if ($reftype eq 'HASH') {
    100 66        
    100 66        
    100 66        
    100 66        
    100          
    100          
    50          
    0          
125 7         34 $encoded_value = { map { $_ => encode($value->{$_}, &$_p, $seen) } sort(keys %$value) };
  13         30  
126              
127             } elsif ($reftype eq 'ARRAY') {
128 12         40 $encoded_value = [ map { encode($value->[$_], &$_p, $seen) } (0 .. $#$value) ];
  25         46  
129              
130             } elsif ($reftype eq 'GLOB') {
131 17         31 my %encoded_value = map { $_ => encode(*{$value}{$_},
  17         35  
132             &$_p."{$_}",
133             $seen) }
134 14         29 grep { *{$value}{$_} }
  42         52  
  42         112  
135             qw(HASH ARRAY SCALAR);
136 14         25 @encoded_value{'NAME','PACKAGE'} = (*{$value}{NAME}, *{$value}{PACKAGE});
  14         33  
  14         43  
137 14 100       25 if (*{$value}{CODE}) {
  14         34  
138 1         3 $encoded_value{CODE} = encode(*{$value}{CODE}, &$_p, $seen);
  1         2  
139             }
140 14 100       20 if (*{$value}{IO}) {
  14         60  
141 12 50       18 if ( $encoded_value{IO} = encode(fileno(*{$value}{IO}), &$_p, $seen) )
  12         47  
142             {
143 12         16 $encoded_value{IOmode} = _get_open_mode(*{$value}{IO});
  12         28  
144 12         78 $encoded_value{IOseek} = sysseek($value, 0, 1);
145             }
146             }
147 14         41 $encoded_value = \%encoded_value;
148             } elsif (($reftype eq 'REGEXP')
149             or ($reftype eq 'SCALAR' and defined($blesstype) and $blesstype eq 'Regexp')
150             ) {
151 1         3 $reftype = 'REGEXP';
152 1 50       5 undef($blesstype) unless $blesstype ne 'Regexp';
153 1         2 my($pattern, $modifiers);
154 1 50       17 if ($^V ge v5.9.5) {
155 1         9 require re;
156             }
157 1 50       5 if (defined &re::regexp_pattern) {
158 1         5 ($pattern, $modifiers) = re::regexp_pattern($value);
159             } else {
160 0         0 my $value_as_str = "$value";
161 0         0 ($modifiers, $pattern) = $value_as_str =~ m/\(\?(\w*)-\w*:(.*)\)$/;
162             }
163 1         3 $encoded_value = [ $pattern, $modifiers ];
164             } elsif ($reftype eq 'CODE') {
165 2         9 (my $copy = $value.'') =~ s/^(\w+)\=//; # Hack to change CodeClass=CODE(0x123) to CODE=(0x123)
166 2         5 $encoded_value = $copy;
167             } elsif ($reftype eq 'REF') {
168 7         15 $encoded_value = encode($$value, &$_p, $seen );
169             } elsif (($reftype eq 'VSTRING') or (ref($value) eq 'SCALAR' and Scalar::Util::isvstring($$value))) {
170 2         41 $reftype = 'VSTRING';
171 2         14 $encoded_value = [ unpack('c*', $$value) ];
172             } elsif ($reftype eq 'SCALAR') {
173 19         41 $encoded_value = encode($$value, &$_p, $seen);
174              
175             } elsif ($reftype eq 'IO') {
176 0 0       0 if ( $encoded_value->{IO} = encode(fileno($value), &$_p, $seen) )
177             {
178 0         0 $encoded_value->{IOmode} = _get_open_mode(*$value);
179 0         0 $encoded_value->{IOseek} = sysseek($value, 0, 1);
180             }
181             }
182              
183 64         185 $encoded_value = { __reftype => $reftype, __refaddr => $refaddr, __value => $encoded_value };
184 64 100       125 $encoded_value->{__blessed} = $blesstype if $blesstype;
185              
186 64         354 return $encoded_value;
187             }
188              
189             sub _is_tied {
190 72     72   102 my $ref = shift;
191              
192 72         122 my $reftype = Scalar::Util::reftype($ref);
193 72         95 my $tied;
194 72 100       207 if ($reftype eq 'HASH') { $tied = tied %$ref }
  9 100       18  
    100          
    100          
195 14         125 elsif ($reftype eq 'ARRAY') { $tied = tied @$ref }
196 21         40 elsif ($reftype eq 'SCALAR') { $tied = tied $$ref }
197 16         30 elsif ($reftype eq 'GLOB') { $tied = tied *$ref }
198              
199 72         301 return $tied;
200             }
201              
202             sub _untie_and_get_original_value {
203 4     4   7 my $ref = shift;
204              
205 4         7 my $tied_val = _is_tied($ref);
206 4         18 my $class = Scalar::Util::blessed($tied_val);
207 4         11 my $untie_function = join('::', $class, 'UNTIE');
208 5     5   36 no strict 'refs';
  5         14  
  5         186  
209 4     4   29 local *$untie_function = sub { };
210 5     5   22 use strict 'refs';
  5         9  
  5         1106  
211              
212 4         10 my $reftype = Scalar::Util::reftype($ref);
213 4         7 my $original;
214 4 50       20 if (!$reftype) {
    100          
    100          
    100          
    50          
215 0         0 untie $ref;
216 0         0 $original = $ref;
217             } elsif ($reftype eq 'SCALAR') {
218 1         4 untie $$ref;
219 1         4 $original = $$ref;
220             } elsif ($reftype eq 'ARRAY') {
221 1         3 untie @$ref;
222 1         3 $original = [ @$ref ];
223             } elsif ($reftype eq 'HASH') {
224 1         3 untie %$ref;
225 1         4 $original = { %$ref };
226             } elsif ($reftype eq 'GLOB') {
227 1         3 untie *$ref;
228 1         17 my $pkg = *$ref{PACKAGE};
229 1         10 my $name = *$ref{NAME};
230 1         4 $original = _create_anon_ref_of_type('GLOB', $pkg, $name);
231 1         4 *$original = *$ref;
232             } else {
233 0         0 Carp::croak("Cannot retrieve the original value of a tied $reftype");
234             }
235 4         17 return $original;
236             }
237              
238             sub _retie {
239 8     8   31 my($ref, $value) = @_;
240              
241 8         21 my $reftype = Scalar::Util::reftype($ref);
242 8         20 my $class = Scalar::Util::blessed($value);
243 5     5   30 no strict 'refs';
  5         8  
  5         153  
244 5     5   24 no warnings 'redefine';
  5         9  
  5         1455  
245 8 100       27 if ($reftype eq 'SCALAR') {
    100          
    100          
    50          
246 2         5 my $tiescalar = join('::',$class, 'TIESCALAR');
247 2     2   14 local *$tiescalar = sub { return $value };
  2         9  
248 2         6 tie $$ref, $class;
249              
250             } elsif ($reftype eq 'ARRAY') {
251 2         7 my $tiearray = join('::', $class, 'TIEARRAY');
252 2     2   11 local *$tiearray = sub { return $value };
  2         9  
253 2         7 tie @$ref, $class;
254              
255             } elsif ($reftype eq 'HASH') {
256 2         5 my $tiehash = join('::', $class, 'TIEHASH');
257 2     2   10 local *$tiehash = sub { return $value };
  2         9  
258 2         7 tie %$ref, $class;
259              
260             } elsif ($reftype eq 'GLOB') {
261 2         5 my $tiehandle = join('::', $class, 'TIEHANDLE');
262 2     2   12 local *$tiehandle = sub { return $value };
  2         8  
263 2         10 tie *$ref, $class;
264              
265             } else {
266 0         0 Carp::croak('Cannot recreate a tied '.scalar(ref $value));
267             }
268             }
269              
270             sub _create_anon_ref_of_type {
271 8     8   22 my($type, $package, $name) = @_;
272              
273 8 100       38 if ($type eq 'SCALAR') {
    100          
    100          
    50          
274 1         2 my $anon;
275 1         2 return \$anon;
276             } elsif ($type eq 'ARRAY') {
277 1         3 return [];
278             } elsif ($type eq 'HASH') {
279 1         3 return {};
280             } elsif ($type eq 'GLOB') {
281 5         7 my $rv;
282 5 100 66     44 if ($package and $name
      66        
      33        
283             and
284             $package ne 'Symbol'
285             and
286             $name !~ m/GEN\d/
287             ) {
288 4         21 my $globname = join('::',$package, $name);
289 5     5   33 $rv = do { no strict 'refs'; local *$globname; \*$globname; };
  5         9  
  5         5439  
  4         9  
  4         15  
  4         12  
290             } else {
291 1         4 $rv = Symbol::gensym();
292             }
293 5         28 return $rv;
294             }
295             }
296              
297             # $fh can be undef, in which case it's autovivified. But for handles that
298             # were originally created via Synbol::geniosym, it'll be passed in already
299             # created
300             sub _recreate_fh {
301 1     1   4 my($fileno, $mode, $fh) = @_;
302              
303 1 50       11 if ($mode) {
    50          
304 0 0       0 open($fh, $mode . '&=', $fileno)
305             || Carp::carp("Couldn't open filehandle for descriptor $fileno with mode $mode: $!");
306              
307             } elsif ($fileno) {
308 1 50 33     20 open($fh, '>&=', $fileno)
309             || open($fh, '<&=', $fileno)
310             || Carp::carp("Couldn't open filehandle for descriptor $fileno: $!");
311             }
312 1         4 return $fh;
313             }
314              
315             sub decode {
316 77     77 1 26561 my($input, $recursive_queue, $recurse_fill) = @_;
317              
318 77 100       158 unless (ref $input) {
319 27         110 return $input;
320             }
321              
322 50         117 _validate_decode_structure($input);
323              
324 50         317 my($value, $reftype, $refaddr, $blessed) = @$input{'__value','__reftype','__refaddr','__blessed'};
325 50         74 my $rv;
326 50         122 my $is_first_invocation = ! $recursive_queue;
327 50   100     127 $recursive_queue ||= [];
328              
329 50 100       222 if ($input->{__recursive}) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    0          
330 7         12 my $path = $input->{__value};
331             push @$recursive_queue,
332             sub {
333 7     7   13 my $VAR = shift;
334 7         711 $recurse_fill->(eval $path);
335 7         27 };
336              
337             } elsif ($input->{__tied}) {
338 4         12 $rv = _create_anon_ref_of_type($reftype);
339 4         7 my $tied_value;
340 4     0   28 $tied_value = decode($value, $recursive_queue, sub { $tied_value });
  0         0  
341 4         14 _retie($rv, $tied_value);
342              
343             } elsif ($reftype eq 'SCALAR') {
344 8         16 $rv = \$value;
345              
346             } elsif ($reftype eq 'ARRAY') {
347 11         21 $rv = [];
348 11         36 for (my $i = 0; $i < @$value; $i++) {
349 23         34 my $idx = $i;
350 23     4   116 push @$rv, decode($value->[$i], $recursive_queue, sub { $rv->[$idx] = shift });
  4         20  
351             }
352              
353             } elsif ($reftype eq 'HASH') {
354 6         10 $rv = {};
355 6         26 foreach my $key ( sort keys %$value ) {
356 12         18 my $k = $key;
357 12     1   60 $rv->{$key} = decode($value->{$key}, $recursive_queue, sub { $rv->{$k} = shift });
  1         5  
358             }
359              
360             } elsif ($reftype eq 'GLOB') {
361             my $is_real_glob = ($value->{PACKAGE} ne 'Symbol'
362             and $value->{NAME} !~ m/^GEN\d+/
363 3   33     33 and $value->{NAME} =~ m/^\w/);
364 3         11 $rv = _create_anon_ref_of_type('GLOB', $value->{PACKAGE}, $value->{NAME});
365              
366 3         10 foreach my $type ( keys %$value ) {
367 14 50 100     88 next if ($type eq 'NAME' or $type eq 'PACKAGE' or $type eq 'IOseek' or $type eq 'IOmode');
      66        
      66        
368 8 100       19 if ($type eq 'IO') {
    100          
369 1 50       28 if (my $fileno = $value->{IO}) {
370 1         6 $rv = _recreate_fh($fileno, $value->{IOmode});
371             }
372             } elsif ($type eq 'CODE') {
373 1 50       3 *{$rv} = \&_dummy_sub unless ($is_real_glob);
  0         0  
374              
375             } else {
376 6     0   28 *{$rv} = decode($value->{$type}, $recursive_queue, sub { *{$rv} = shift });
  6         55  
  0         0  
  0         0  
377             }
378             }
379              
380 3 50       8 $rv = *$rv unless $refaddr;
381              
382             } elsif ($reftype eq 'CODE') {
383 1         3 $rv = \&_dummy_sub;
384              
385             } elsif ($reftype eq 'REF') {
386 7         11 my $ref;
387 7     2   32 $ref = decode($value, $recursive_queue, sub { $ref = shift });
  2         12  
388 7         24 $rv = \$ref;
389              
390             } elsif ($reftype eq 'REGEXP') {
391 1         4 my($pattern,$modifiers) = @$value[0,1];
392 1         85 $rv = eval "qr($pattern)$modifiers";
393              
394             } elsif ($reftype eq 'VSTRING') {
395 2         105 my $vstring = eval 'v' . join('.', @$value);
396 2 100       11 $rv = $refaddr ? \$vstring : $vstring;
397              
398             } elsif ($reftype eq 'IO') {
399             # A filehandle that was created via Symbol::geniosym
400 0         0 my $fh = Symbol::geniosym;
401 0         0 $rv = _recreate_fh($value->{IO}, $value->{IOmode}, $fh);
402             }
403              
404 50 100 100     126 bless $rv, $blessed if ($blessed and ! $input->{__recursive});
405              
406 50 100       92 if ($is_first_invocation) {
407 21         49 $_->($rv) foreach @$recursive_queue;
408             }
409              
410 50         138 return $rv;
411             }
412              
413             sub _dummy_sub {
414 0     0   0 'Put in place by ' . __PACKAGE__ . ' when it could not find the named sub';
415             }
416              
417             sub _validate_decode_structure {
418 50     50   81 my $input = shift;
419              
420 50 50       99 ref($input) eq 'HASH'
421             or Carp::croak('Invalid decode data: expected hashref but got '.ref($input));
422              
423             exists($input->{__value})
424 50 50       104 or Carp::croak('Invalid decode data: expected key __value');
425             exists($input->{__reftype})
426 50 50       82 or Carp::croak('Invalid decode data: expected key __reftype');
427              
428 50         110 my($reftype, $value, $blesstype) = @$input{'__reftype','__value','__blesstype'};
429             $reftype eq 'GLOB'
430             or $reftype eq 'VSTRING'
431             or exists($input->{__refaddr})
432 50 50 100     230 or Carp::croak('Invalid decode data: expected key __refaddr');
      66        
433              
434 50 50 33     290 ($blesstype and $reftype)
      33        
435             or !$blesstype
436             or Carp::croak('Invalid decode data: Cannot have __blesstype without __reftype');
437              
438             my $compatible_references =
439             ( ( $reftype eq 'SCALAR' and ! ref($value) )
440             or
441             ( $reftype eq ref($value) )
442             or
443             ( $reftype eq 'GLOB' and exists($value->{SCALAR}))
444             or
445             ( $reftype eq 'CODE' and $value and ref($value) eq '' )
446             or
447             ( $reftype eq 'REF' and ref($value) eq 'HASH' and exists($value->{__reftype}) )
448             or
449             ( $reftype eq 'REGEXP' and ref($value) eq 'ARRAY' )
450             or
451             ( $reftype eq 'VSTRING' and ref($value) eq 'ARRAY' )
452             or
453             ( $reftype eq 'IO' and exists($value->{IO}) )
454             or
455             ( $reftype and ! ref($input->{__value}) and $input->{__recursive} )
456             or
457             ( $input->{__tied} and ref($input->{__value}) and $input->{__value}->{__blessed} )
458 50   66     667 );
459             $compatible_references or Carp::croak('Invalid decode data: __reftype is '
460             . $input->{__reftype}
461             . ' but __value is a '
462 50 50       104 . ref($input->{__value}));
463 50         87 return 1;
464             }
465              
466             1;
467              
468             =pod
469              
470             =head1 NAME
471              
472             Data::Transform::ExplicitMetadata - Encode Perl values in a json-friendly way
473              
474             =head1 SYNOPSIS
475              
476             use Data::Transform::ExplicitMetadata qw(encode decode);
477             use JSON;
478              
479             my $val = encode($some_data_structure);
480             $io->print( JSON::encode_json( $val ));
481              
482             my $data_structure_copy = decode($val);
483              
484             =head1 DESCRIPTION
485              
486             Transforms an arbitrarily nested data structure into an analogous data
487             structure composed of only simple scalars, arrayrefs and hashrefs that may
488             be safely JSON-encoded, while retaining all the Perl-specific metadata
489             about typeglobs, blessed and tied references, self-referential data,
490             reference addresses, etc.
491              
492             With a few exceptions, a copy of the original data structure can be recreated
493             from the encoded version.
494              
495             =head2 Functions
496              
497             =over 4
498              
499             =item encode
500              
501             Accepts a single value and returns a value that may be safely passed to
502             JSON::encode_json(). encode_json() cannot handle Perl-specific data like
503             blessed references or typeglobs. Non-reference scalar values like numbers
504             and strings are returned unchanged. For all references, encode()
505             returns a hashref with these keys
506              
507             =over 4
508              
509             =item * __reftype
510              
511             String indicating the type of reference, as returned by Scalar::Util::reftype()
512              
513             =item * __refaddr
514              
515             Memory address of the reference, as returned by Scalar::Util::refaddr()
516              
517             =item * __blessed
518              
519             Package this reference is blessed into, as returned by Scalar::Util::blessed.
520              
521             =item * __value
522              
523             Reference to the unblessed data.
524              
525             =item * __tied
526              
527             The original value hidden by the tie() operation.
528              
529             =item * __recursive
530              
531             Flag indicating this reference was seen before
532              
533             =back
534              
535             If the reference was not blessed or tied, then the __blessed and/or __tied keys
536             will not be present.
537              
538             C<__value> is generally a copy of the underlying data. For example, if the input
539             value is an hashref, then __value will also be a hashref containing the input
540             value's kays and values. For typeblobs and glob refs, __value will be a
541             hashref with the keys NAME, PACKAGE, SCALAR, ARRAY, HASH, IO and CODE. For
542             compiled regexps, __value will be a 2-element arrayref of the pattern and
543             modifiers. For coderefs, __value will be the stringified reference, like
544             "CODE=(0x12345678)". For v-strings and v-string refs, __value will by an
545             arrayref containing the integers making up the v-string.
546              
547             For tied objects, C<__tied> will be contain the original value hidden by tie()
548             and __value will contain the tied data. The original data is retrieved by:
549              
550             =over 4
551              
552             =item *
553              
554             call tied() to get a copy of the tied data
555              
556             =item *
557              
558             localize the UNTIE method in the appropriate class
559              
560             =item *
561              
562             untie the variable
563              
564             =item *
565              
566             save a copy of the original value
567              
568             =item *
569              
570             localize the appropriate TIE* mythod to return the tied data
571              
572             =item *
573              
574             call tie() to retie the variable
575              
576             =back
577              
578             if C<__recursive> is true, then __value will contain a string representation
579             of the first place this reference was seen in the data structure.
580              
581             encode() handles arbitrarily nested data structures, meaning that
582             values in the __values slot may also be encoded this way.
583              
584             =item decode
585              
586             Accepts a single value and returns a copy of the data structure originally
587             passed to encode(). __refaddr information is discarded and new copies of
588             nested data structures is created. Self-referential data is re-linked to the
589             appropriate placxe in the new copy. Blessed references are re-bless into
590             the original packages.
591              
592             Tied variables are re-tied by localizing the appropriate TIE* method to return
593             the tied data. The variable's original data is filled in before calling tie().
594              
595             The IO slot of typeglobs is recreated by opening the handle with the same
596             descriptor number and open mode. It will first try fcntl() with F_GETFL
597             to determine the open mode, falling back to using FileHandle::Fmode if it's
598             available. Finally, it will first try re-opening the file descriptor in
599             read mode, then write mode.
600              
601             Coderefs cannot be decoded properly. They are recreated by returning a
602             reference to a dummy sub that returns a message explaning the situation.
603              
604             =back
605              
606             =head1 SEE ALSO
607              
608             L, L, L, L
609              
610             =head1 AUTHOR
611              
612             Anthony Brummett
613              
614             =head1 COPYRIGHT
615              
616             Copyright 2016, Anthony Brummett. This module is free software. It may
617             be used, redistributed and/or modified under the same terms as Perl itself.