File Coverage

blib/lib/AnyEvent/POE_Reference.pm
Criterion Covered Total %
statement 44 48 91.6
branch 9 12 75.0
condition 4 8 50.0
subroutine 10 10 100.0
pod 0 1 0.0
total 67 79 84.8


line stmt bran cond sub pod time code
1             package AnyEvent::POE_Reference;
2              
3 2     2   45724 use 5.008;
  2         8  
  2         81  
4 2     2   12 use strict;
  2         3  
  2         72  
5 2     2   32 use warnings;
  2         14  
  2         99  
6              
7 2     2   3471 use AnyEvent (); BEGIN { AnyEvent::common_sense }
  2     2   11741  
  2         58  
  2         12  
8 2     2   3040 use AnyEvent::Handle;
  2         48170  
  2         78  
9              
10 2     2   36 use Carp;
  2         5  
  2         2389  
11              
12             our $VERSION = '0.11';
13              
14             sub FREEZE () { 0 }
15             sub THAW () { 1 }
16              
17             my %SERIALIZERS;
18             my $ZLIB;
19              
20             our $SERIALIZED_MAX_SIZE = 1_000_000; # bytes
21              
22             sub new
23             {
24 14     14 0 1118 my $class = shift;
25              
26 14 50       35 @_ > 2 and croak "usage: ${\__PACKAGE__}->new([SERIALIZER[, COMPRESSION]])";
  0         0  
27              
28 14         23 my($serializer, $compress) = @_;
29              
30 14   100     38 $serializer ||= 'Storable';
31              
32 14 100       28 $compress = $compress ? '/z' : '';
33              
34 14         27 my $self = $SERIALIZERS{"$serializer$compress"};
35              
36 14 100       30 unless (defined $self)
37             {
38 4         9 $self = bless [], $class;
39             eval
40             {
41 4         10 (my $serializer_path = $serializer) =~ s,::,/,g;
42 4         1326 require "$serializer_path.pm";
43              
44 4   33     3958 my $freeze = $serializer->can('nfreeze')
45             || $serializer->can('freeze')
46             || croak("${\__PACKAGE__} can't find n?freeze method "
47             . "in $serializer module");
48              
49 4   33     23 my $thaw = $serializer->can('thaw')
50             || croak("${\__PACKAGE__} can't find thaw method "
51             . "in $serializer module");
52              
53 4 100       12 if ($compress)
54             {
55 2 50       5 eval { require Compress::Zlib; }
  2         1181  
56 0         0 or croak "${\__PACKAGE__} can't load Compress::Zlib";
57              
58             $self->[FREEZE] = sub
59             {
60 3     3   91 Compress::Zlib::compress($freeze->($_[0]));
61 2         100479 };
62              
63             $self->[THAW] = sub
64             {
65 2     2   9 $thaw->(Compress::Zlib::uncompress($_[0]));
66 2         13 };
67             }
68             else
69             {
70 2         11 $self->[FREEZE] = $freeze;
71 2         4 $self->[THAW] = $thaw;
72             }
73              
74 4         41 1;
75             }
76             or do
77 4 50       6 {
78 0         0 croak "${\__PACKAGE__} can't load serializer $serializer\n";
  0         0  
79             };
80              
81 4         14 $SERIALIZERS{"$serializer$compress"} = $self;
82             }
83              
84 14         34 return $self;
85             }
86              
87             {
88             package # hide from pause
89             AnyEvent::Handle;
90              
91             # poe_reference => $data, [$serializer[, $compress]]
92             register_write_type(
93             poe_reference => sub
94             {
95             # (SELF, DATA)
96             # (SELF, SERIALIZER, DATA)
97             # (SELF, SERIALIZER, COMPRESS, DATA)
98             my $self = shift;
99             my $data = pop;
100              
101             # (SERIALIZER)
102             # (SERIALIZER, COMPRESS)
103             my($serializer, $compress) = @_;
104              
105             unless (ref $serializer)
106             {
107             $serializer = AnyEvent::POE_Reference->new(
108             $serializer, $compress);
109             }
110              
111             $data = $serializer->
112             [AnyEvent::POE_Reference::FREEZE]->($data);
113             return length($data) . "\0" . $data;
114             });
115              
116             # poe_reference => [$serializer[, $compress]], $cb->($hdl, $data)
117             register_read_type(
118             poe_reference => sub
119             {
120             my($self, $cb, $serializer, $compress) = @_;
121              
122             my $rbuf = \$self->{rbuf};
123              
124             return sub
125             {
126             if ($$rbuf =~ /^(\d+)(\D)/)
127             {
128             if ($1 > $AnyEvent::POE_Reference::SERIALIZED_MAX_SIZE)
129             {
130             $self->_error(Errno::E2BIG);
131             return 0;
132             }
133              
134             # \0 not found
135             if ($2 ne "\0")
136             {
137             $self->_error(Errno::EBADMSG);
138             return 0;
139             }
140              
141             return 0 if length($$rbuf) < length($1) + 1 + $1;
142              
143             my $buf = substr($$rbuf, 0, length($1) + 1 + $1, '');
144              
145             unless (ref $serializer)
146             {
147             $serializer = AnyEvent::POE_Reference->new(
148             $serializer, $compress);
149             }
150              
151             # FreezeThaw returns in list context...
152             if (my($ref) = eval {
153             $serializer->[AnyEvent::POE_Reference::THAW]->(
154             substr($buf, length($1) + 1)) })
155             {
156             $cb->($_[0], $ref);
157              
158             return 1;
159             }
160             else
161             {
162             $self->_error(Errno::EBADMSG);
163             }
164             }
165             # Not a number...
166             elsif ($$rbuf =~ /^\D/)
167             {
168             $self->_error(Errno::EBADMSG);
169             }
170             # Too much numbers...
171             elsif (length($$rbuf)
172             > length($AnyEvent::POE_Reference::SERIALIZED_MAX_SIZE))
173             {
174             $self->_error(Errno::EBADMSG);
175             }
176              
177             return 0;
178             };
179             });
180             }
181              
182             1;
183             __END__