File Coverage

blib/lib/Data/FastPack.pm
Criterion Covered Total %
statement 120 128 93.7
branch 24 32 75.0
condition 8 12 66.6
subroutine 13 15 86.6
pod 3 6 50.0
total 168 193 87.0


line stmt bran cond sub pod time code
1             package Data::FastPack;
2 2     2   226826 use strict;
  2         5  
  2         70  
3 2     2   17 use warnings;
  2         4  
  2         148  
4              
5             our $VERSION="v0.3.0";
6              
7 2     2   11 use feature ":all";
  2         3  
  2         437  
8 2     2   11 no warnings "experimental";
  2         7  
  2         127  
9 2     2   1136 use Export::These qw;
  2         1646  
  2         13  
10              
11              
12              
13 2     2   3165 use constant::more ;
  2         1935  
  2         213  
14              
15 2     2   852 use constant::more ;
  2         4  
  2         98  
16 2     2   868 use constant::more qw;
  2         4  
  2         11  
17              
18 2     2   714 use constant::more DEBUG=>0;
  2         9  
  2         9  
19              
20             # routine indicating the required size of a buffer to store the requested
21             # payload length
22             #
23             sub size_message {
24 0     0 0 0 my $payload_size=shift;
25 0         0 my$padding=($payload_size%8);
26 0 0       0 $padding= 8-$padding if $padding;
27              
28             #return the total length of the head, payload and padding
29 0         0 16+$payload_size+$padding;
30             }
31              
32             #passing arrays of arrays, [time, info, payload] Computes padding, appends
33             #the serialized data to the supplied buffer, and sets the length. If id
34             #has MORE bit set, at least one more messags to follow (at some point).
35             #$buf, [$time, $id, $data]
36             #
37             my $pbuf= pack "x8";
38              
39              
40             =over
41              
42             =item encode_message
43              
44             =item encode_fastpack
45              
46             Encodes an array of fast pack message structures into an buffer
47              
48             Buffer is aliased and is an in/out parameter. Encoded data is appended to the buffer.
49              
50             Inputs is an array of message structure (also array refs). Array is consumed
51              
52             An optional limit can be sepecified on how many messages to encode in a single call
53              
54             Returns the number of bytes encoded
55              
56              
57             =back
58              
59             =cut
60              
61             my @_ids; #original name cache
62             my $i;
63              
64             sub encode_message;
65             sub encode_message {
66 14     14 0 206946 \my $buf=\$_[0]; shift;
  14         25  
67 14         25 my $inputs=shift;
68 14         23 my $limit=shift;
69 14         25 my $ns=shift; # if name space is present. the id is taken as a name. Even though this could be numeric,
70             # It is then looked up from a dynamic table
71             # If it found, the allocated number is use.
72             # if is not, a system message with the table entry is created and set along with it.
73              
74 14   33     67 $limit//=@$inputs;
75 14         38 my $bytes=0;
76 14         24 my $processed=0;
77 14         25 my $padding;
78             my $tmp;
79            
80 14         22 my $flags=0;
81             # Loop through and do namespace name to id conversion
82 14 100       37 if($ns){
83 7         13 $i=0;
84 7         14 for(@$inputs){
85             # NOTE: messages with "0" and 0 and undef are ignored
86 7 100       18 if($_->[FP_MSG_ID]){
87             #DEBUG and
88 6         12 my $name=$_->[FP_MSG_ID];
89             # Convert to id if ns is present and ID is NOT 0
90 6         21 my $id=$ns->[N2E]{$name};
91              
92 6 50       16 if(!defined $id){
93 6         8 DEBUG and print STDERR $$.__PACKAGE__ . "id for name $name does NOT existes in table: $id\n";
94 6         26 DEBUG and print STDERR $$.__PACKAGE__ . "first payload is name... so we want to send/register\n";
95             # Update id tracking and lookup tables
96 6   33     27 $id=pop($ns->[FREE_ID]->@*)//$ns->[NEXT_ID]++;
97 6         17 $ns->[N2E]{$name}=$id;
98 6         20 $ns->[I2E]{$id}=$name;
99              
100 6         11 DEBUG and print STDERR __PACKAGE__ . "encode registration $id $name\n";
101             # encode definition into buffer
102 6         27 $bytes+=encode_message $buf, [[$_->[FP_MSG_TIME], $id, $name ]];
103             }
104              
105             # Same the new name for encoding
106 6         20 $_ids[$i++]=$id;
107             }
108             else {
109 1 50       7 unless($_->[FP_MSG_PAYLOAD]){
110             # No payload, and 0 id, and name space active...
111             # This is a name space reset message
112 1         5 $ns->[N2E]->%*=();
113 1         4 $ns->[I2E]->%*=();
114 1         3 $ns->[FREE_ID]->@*=();
115 1         3 $ns->[NEXT_ID]=1;
116             }
117 1         3 $_ids[$i++]=$_->[FP_MSG_ID];
118             # If the msg id is 0 this is passed thourgh un modified and not name translated.
119             #
120             #warn 'FastPack encode: Ignoring message. Named FastPack Messages cannot be named 0 or "0" or undefined';
121             }
122              
123             }
124 7         12 $i=0;
125 7         14 for(@$inputs){
126 7   100     21 $padding=((length($_->[FP_MSG_PAYLOAD]//""))%8);
127 7 100       17 $padding= 8-$padding if $padding;
128              
129 7   100     36 my $s=pack("d V V/a*", $_->[FP_MSG_TIME], $_ids[$i++], $_->[FP_MSG_PAYLOAD]//"" );
130 7         31 $tmp=$s.substr $pbuf, 0, $padding;
131 7         11 $bytes+=length $tmp;
132 7         15 $buf.=$tmp;
133 7 50       19 last if ++$processed == $limit;
134             }
135             }
136             else {
137 7         11 $i=0;
138 7         17 for(@$inputs){
139 8         17 $padding=((length $_->[FP_MSG_PAYLOAD])%8);
140 8 50       18 $padding= 8-$padding if $padding;
141              
142 8         38 my $s=pack("d V V/a*", @$_);
143 8         22 $tmp=$s.substr $pbuf, 0, $padding;
144 8         13 $bytes+=length $tmp;
145 8         32 $buf.=$tmp;
146 8 100       25 last if ++$processed == $limit;
147             }
148              
149             }
150              
151             # Remove the messages from the input array
152 14         29 splice @$inputs, 0, $processed;
153            
154 14         40 $bytes;
155             }
156              
157             *encode_fastpack=\&encode_message;
158              
159             # Decode a message from a buffer. Buffer is aliased
160             =over
161              
162             =item decode_message
163              
164             =item decode_fastpack
165              
166             Consumes data from an input buffer and decodes it into 0 or more messages.
167             Buffer is aliased and is an in/out parameter
168             Decoded messages are added to the dereferenced output array
169             An optional limit of message count can be specified.
170              
171             Returns the number of bytes consumed during decoding. I a message could not be
172             decoded, 0 bytes are consumed.
173              
174             buffer (aliased)
175             output (array ref)
176             limit (numeric)
177              
178             return (byte count)
179              
180              
181             =back
182              
183             =cut
184              
185             sub decode_message {
186 3     3 0 484 \my $buf=\$_[0]; shift;
  3         6  
187 3         7 my $output=shift;
188 3   100     14 my $limit=shift//4096;
189 3         5 my $ns=shift;
190              
191 3         24 my $byte_count=0;
192 3         13 for(1..$limit){
193             # Minimum message length 8 bytes long (header)
194 18 100       45 last if length($buf)<16;
195              
196             # Decode header. Leave length for in buffer
197 15         50 my @message= unpack "d V V", substr($buf, 0, 16);
198              
199              
200              
201             # Calculate pad. Payload in message here is actuall just length atm
202 15         28 my $pad= $message[FP_MSG_PAYLOAD]%8;
203 15 100       32 $pad=8-$pad if $pad;
204              
205             # Calculate total length
206 15         27 my $total=$message[FP_MSG_PAYLOAD]+16+$pad;
207              
208 15 50       41 last if(length($buf)<$total);
209              
210              
211              
212              
213 15         23 $byte_count+=$total;
214              
215              
216 15         45 ($message[FP_MSG_PAYLOAD],undef)=unpack "V/a* ", substr($buf,12);
217 15         27 push @message, $total;
218              
219             # remove from buffer
220 15         24 substr($buf, 0, $total,"");
221              
222             # Process name space definitions and lookups
223 15 100       57 if($ns ){
224             #print STDERR __PACKAGE__. "-------- ID of $message[FP_MSG_ID]=> $message[FP_MSG_PAYLOAD]\n";
225 13 100       29 if($message[FP_MSG_ID]){
226             # This is a non system message which needs conversion
227             #
228 12         21 my $id=$message[FP_MSG_ID];
229 12         25 my $name= $ns->[I2E]{$id};
230 12 100       23 unless($name){
231             # id not found, so this is the first message for this id
232             # The payload contains the name
233 6         10 DEBUG and print STDERR __PACKAGE__ . " message id has not been seen before: $id\n";
234             # This id has not been seen before. so we know the payload it the name
235 6         10 $name=$message[FP_MSG_PAYLOAD];
236              
237 6         10 DEBUG and print STDERR __PACKAGE__ . " use payload ans name: $name\n";
238 6         32 $ns->[I2E]{$id}=$name;
239 6         27 $ns->[N2E]{$name}=$id;
240             }
241             else {
242 6         8 DEBUG and print STDERR __PACKAGE__ . " message name exisits: $name\n";
243 6         10 DEBUG and print STDERR __PACKAGE__ . " has payload.. process as normal. push to output\n";
244             # only push the message to output if this code has been seen before
245 6         12 push @$output, \@message;
246              
247             # Finally convert id to name as we asked for named message
248 6         16 $message[FP_MSG_ID]=$name;
249             }
250             }
251             else {
252             #id of 0
253 1 50       5 unless($message[FP_MSG_PAYLOAD]){
254             # no payload, and 0 id,, reset name space, and consume message
255             #
256 1         4 $ns->[I2E]->%*=();
257 1         5 $ns->[N2E]->%*=();
258 1         2 $ns->[FREE_ID]->@*=();
259 1         3 $ns->[NEXT_ID]=1;
260             }
261             else {
262             # Direct pass through if a payload present
263 0         0 push @$output, \@message;
264             }
265             }
266             }
267             else {
268             # Direct pass through if no name space used
269             #
270 2         4 push @$output, \@message;
271             }
272             }
273 3         9 $byte_count;
274             }
275              
276             *decode_fastpack=\&decode_message;
277              
278             sub create_namespace {
279 4     4 1 245670 [{},{}, 1, []];
280             }
281              
282             sub id_for_name {
283              
284 12     12 1 3826 my $ns=shift;
285 12         23 my $name=shift;
286 12         36 $ns->[N2E]{$name};
287             }
288              
289             sub name_for_id {
290 0     0 1   my $ns=shift;
291 0           my $id=shift;
292 0           $ns->[I2E]{$id};
293              
294             }
295              
296              
297             1;