Skip to content

Commit 90460f2

Browse files
committed
split parse and encode methods into resp2 and resp3 versions
1 parent b80f108 commit 90460f2

File tree

1 file changed

+162
-42
lines changed

1 file changed

+162
-42
lines changed

lib/Protocol/Redis.pm

Lines changed: 162 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,149 @@ sub api {
3131
$self->{api};
3232
}
3333

34+
sub get_message {
35+
shift @{$_[0]->{_messages}};
36+
}
37+
38+
sub encode {
39+
my $self = shift;
40+
return $self->{api} == 3 ? $self->_encode_resp3(@_) : $self->_encode_resp2(@_);
41+
}
42+
43+
sub on_message {
44+
my ($self, $cb) = @_;
45+
$self->{_on_message_cb} = $cb || \&_gather_messages;
46+
}
47+
48+
sub parse {
49+
my $self = shift;
50+
return $self->{api} == 3 ? $self->_parse_resp3(@_) : $self->_parse_resp2(@_);
51+
}
52+
53+
sub _gather_messages {
54+
push @{$_[0]->{_messages}}, $_[1];
55+
}
56+
3457
my %simple_types = ('+' => 1, '-' => 1, ':' => 1);
58+
59+
sub _encode_resp2 {
60+
my $self = shift;
61+
62+
my $encoded_message = '';
63+
while (@_) {
64+
my $message = shift;
65+
66+
# Bulk string
67+
if ($message->{type} eq '$') {
68+
if (defined $message->{data}) {
69+
$encoded_message .= '$' . length($message->{data}) . "\r\n" . $message->{data} . "\r\n";
70+
}
71+
else {
72+
$encoded_message .= "\$-1\r\n";
73+
}
74+
}
75+
# Array (multi bulk)
76+
elsif ($message->{type} eq '*') {
77+
if (defined $message->{data}) {
78+
$encoded_message .= '*' . scalar(@{$message->{data}}) . "\r\n";
79+
unshift @_, @{$message->{data}};
80+
}
81+
else {
82+
$encoded_message .= "*-1\r\n";
83+
}
84+
}
85+
# String, error, integer
86+
elsif (exists $simple_types{$message->{type}}) {
87+
$encoded_message .= $message->{type} . $message->{data} . "\r\n";
88+
}
89+
else {
90+
Carp::croak(qq/Unknown message type $message->{type}/);
91+
}
92+
}
93+
94+
return $encoded_message;
95+
}
96+
97+
sub _parse_resp2 {
98+
my $self = shift;
99+
$self->{_buffer}.= shift;
100+
101+
my $message = $self->{_message} ||= {};
102+
my $buffer = \$self->{_buffer};
103+
104+
CHUNK:
105+
while ((my $pos = index($$buffer, "\r\n")) != -1) {
106+
# Check our state: are we parsing new message or completing existing
107+
if (!$message->{type}) {
108+
if ($pos < 1) {
109+
Carp::croak(qq/Unexpected input "$$buffer"/);
110+
}
111+
112+
$message->{type} = substr $$buffer, 0, 1;
113+
$message->{_argument} = substr $$buffer, 1, $pos - 1;
114+
substr $$buffer, 0, $pos + 2, ''; # Remove type + argument + \r\n
115+
}
116+
117+
# Simple Strings, Errors, Integers
118+
if (exists $simple_types{$message->{type}}) {
119+
$message->{data} = delete $message->{_argument};
120+
}
121+
# Bulk Strings
122+
elsif ($message->{type} eq '$') {
123+
if ($message->{_argument} eq '-1') {
124+
$message->{data} = undef;
125+
}
126+
elsif (length($$buffer) >= $message->{_argument} + 2) {
127+
$message->{data} = substr $$buffer, 0, $message->{_argument}, '';
128+
substr $$buffer, 0, 2, ''; # Remove \r\n
129+
}
130+
else {
131+
return # Wait more data
132+
}
133+
}
134+
# Arrays
135+
elsif ($message->{type} eq '*') {
136+
if ($message->{_argument} eq '-1') {
137+
$message->{data} = undef;
138+
} else {
139+
$message->{data} = [];
140+
if ($message->{_argument} > 0) {
141+
$message = $self->{_message} = {_parent => $message};
142+
next;
143+
}
144+
}
145+
}
146+
# Invalid input
147+
else {
148+
Carp::croak(qq/Unexpected input "$self->{_message}{type}"/);
149+
}
150+
151+
delete $message->{_argument};
152+
delete $self->{_message};
153+
154+
# Fill parents with data
155+
while (my $parent = delete $message->{_parent}) {
156+
push @{$parent->{data}}, $message;
157+
158+
if (@{$parent->{data}} < $parent->{_argument}) {
159+
$message = $self->{_message} = {_parent => $parent};
160+
next CHUNK;
161+
}
162+
else {
163+
$message = $parent;
164+
delete $parent->{_argument};
165+
}
166+
}
167+
168+
$self->{_on_message_cb}->($self, $message);
169+
$message = $self->{_message} = {};
170+
}
171+
}
172+
35173
my %blob_types = ('$' => 1, '!' => 1, '=' => 1);
36174
my %aggregate_types = ('*' => 1, '%' => 1, '~' => 1, '|' => 1, '>' => 1);
37-
my $rn = "\r\n";
38175

39-
sub encode {
176+
sub _encode_resp3 {
40177
my $self = shift;
41178

42179
my $encoded_message = '';
@@ -53,7 +190,7 @@ sub encode {
53190
}
54191

55192
# Bulk string, Blob error, Verbatim string
56-
elsif ($message->{type} eq '$' or ($self->{api} == 3 and exists $blob_types{$message->{type}})) {
193+
elsif (exists $blob_types{$message->{type}}) {
57194
if (defined $message->{data}) {
58195
$encoded_message .= $message->{type} . length($message->{data}) . "\r\n" . $message->{data} . "\r\n";
59196
}
@@ -62,8 +199,7 @@ sub encode {
62199
}
63200
}
64201
# Array, Set, Push
65-
elsif ($message->{type} eq '*'
66-
or ($self->{api} == 3 and ($message->{type} eq '~' or $message->{type} eq '>'))) {
202+
elsif ($message->{type} eq '*' or $message->{type} eq '~' or $message->{type} eq '>') {
67203
if (defined $message->{data}) {
68204
$encoded_message .= $message->{type} . scalar(@{$message->{data}}) . "\r\n";
69205
unshift @_, @{$message->{data}};
@@ -73,7 +209,7 @@ sub encode {
73209
}
74210
}
75211
# Map
76-
elsif ($self->{api} == 3 and $message->{type} eq '%') {
212+
elsif ($message->{type} eq '%') {
77213
if (ref $message->{data} eq 'ARRAY') {
78214
$encoded_message .= $message->{type} . int(@{$message->{data}} / 2) . "\r\n";
79215
unshift @_, @{$message->{data}};
@@ -84,12 +220,11 @@ sub encode {
84220
}
85221
}
86222
# String, error, integer, big number
87-
elsif (exists $simple_types{$message->{type}}
88-
or ($self->{api} == 3 and $message->{type} eq '(')) {
223+
elsif (exists $simple_types{$message->{type}} or $message->{type} eq '(') {
89224
$encoded_message .= $message->{type} . $message->{data} . "\r\n";
90225
}
91226
# Double
92-
elsif ($self->{api} == 3 and $message->{type} eq ',') {
227+
elsif ($message->{type} eq ',') {
93228
# inf
94229
if ($message->{data} == $message->{data} * 2) {
95230
$encoded_message .= ',' . ($message->{data} > 0 ? '' : '-') . "inf\r\n";
@@ -103,11 +238,11 @@ sub encode {
103238
}
104239
}
105240
# Null
106-
elsif ($self->{api} == 3 and $message->{type} eq '_') {
241+
elsif ($message->{type} eq '_') {
107242
$encoded_message .= "_\r\n";
108243
}
109244
# Boolean
110-
elsif ($self->{api} == 3 and $message->{type} eq '#') {
245+
elsif ($message->{type} eq '#') {
111246
$encoded_message .= '#' . ($message->{data} ? 't' : 'f') . "\r\n";
112247
}
113248
else {
@@ -118,16 +253,7 @@ sub encode {
118253
return $encoded_message;
119254
}
120255

121-
sub get_message {
122-
shift @{$_[0]->{_messages}};
123-
}
124-
125-
sub on_message {
126-
my ($self, $cb) = @_;
127-
$self->{_on_message_cb} = $cb || \&_gather_messages;
128-
}
129-
130-
sub parse {
256+
sub _parse_resp3 {
131257
my $self = shift;
132258
$self->{_buffer}.= shift;
133259

@@ -148,7 +274,7 @@ sub parse {
148274
}
149275

150276
# Streamed String Parts - must be checked for first
151-
if ($self->{api} == 3 and $message->{_streaming}) {
277+
if ($message->{_streaming}) {
152278
unless ($message->{type} eq ';') {
153279
Carp::croak(qq/Unexpected input "$message->{type}"/);
154280
}
@@ -172,30 +298,30 @@ sub parse {
172298
$message->{data} = delete $message->{_argument};
173299
}
174300
# Null
175-
elsif ($self->{api} == 3 and $message->{type} eq '_') {
301+
elsif ($message->{type} eq '_') {
176302
delete $message->{_argument};
177303
$message->{data} = undef;
178304
}
179305
# Booleans
180-
elsif ($self->{api} == 3 and $message->{type} eq '#') {
306+
elsif ($message->{type} eq '#') {
181307
$message->{data} = !!(delete($message->{_argument}) eq 't');
182308
}
183309
# Doubles
184-
elsif ($self->{api} == 3 and $message->{type} eq ',') {
310+
elsif ($message->{type} eq ',') {
185311
$message->{data} = delete $message->{_argument};
186312
$message->{data} = 'nan' if $message->{data} =~ m/^[-+]?nan/i;
187313
}
188314
# Big Numbers
189-
elsif ($self->{api} == 3 and $message->{type} eq '(') {
315+
elsif ($message->{type} eq '(') {
190316
require Math::BigInt;
191317
$message->{data} = Math::BigInt->new(delete $message->{_argument});
192318
}
193319
# Bulk/Blob Strings, Blob Errors, Verbatim Strings
194-
elsif ($message->{type} eq '$' or ($self->{api} == 3 and exists $blob_types{$message->{type}})) {
320+
elsif (exists $blob_types{$message->{type}}) {
195321
if ($message->{_argument} eq '-1') {
196322
$message->{data} = undef;
197323
}
198-
elsif ($self->{api} == 3 and $message->{type} eq '$' and $message->{_argument} eq '?') {
324+
elsif ($message->{type} eq '$' and $message->{_argument} eq '?') {
199325
$message->{data} = '';
200326
$message = $self->{_message} = {_streaming => $message};
201327
next;
@@ -209,23 +335,23 @@ sub parse {
209335
}
210336
}
211337
# Arrays, Maps, Sets, Attributes, Push
212-
elsif ($message->{type} eq '*' or ($self->{api} == 3 and exists $aggregate_types{$message->{type}})) {
338+
elsif (exists $aggregate_types{$message->{type}}) {
213339
if ($message->{_argument} eq '-1') {
214340
$message->{data} = undef;
215341
} else {
216-
if ($self->{api} == 3 and ($message->{type} eq '%' or $message->{type} eq '|')) {
342+
if ($message->{type} eq '%' or $message->{type} eq '|') {
217343
$message->{data} = {};
218344
} else {
219345
$message->{data} = [];
220346
}
221347

222-
if (($self->{api} == 3 and $message->{_argument} eq '?') or $message->{_argument} > 0) {
348+
if ($message->{_argument} eq '?' or $message->{_argument} > 0) {
223349
$message = $self->{_message} = {_parent => $message};
224350
next;
225351
}
226352
}
227353
# Populate empty attributes for next message if we reach here
228-
if ($self->{api} == 3 and $message->{type} eq '|') {
354+
if ($message->{type} eq '|') {
229355
$message->{attributes} = {};
230356
delete $message->{type};
231357
delete $message->{data};
@@ -234,8 +360,7 @@ sub parse {
234360
}
235361
}
236362
# Streamed Aggregate End
237-
elsif ($self->{api} == 3 and $message->{type} eq '.'
238-
and $message->{_parent} and $message->{_parent}{_argument} eq '?') {
363+
elsif ($message->{type} eq '.' and $message->{_parent} and $message->{_parent}{_argument} eq '?') {
239364
$message = delete $message->{_parent};
240365
delete $message->{_elements};
241366
}
@@ -250,7 +375,7 @@ sub parse {
250375
# Fill parents with data
251376
while (my $parent = delete $message->{_parent}) {
252377
# Map key or value
253-
if ($self->{api} == 3 and ($parent->{type} eq '%' or $parent->{type} eq '|')) {
378+
if ($parent->{type} eq '%' or $parent->{type} eq '|') {
254379
if (exists $parent->{_key}) {
255380
$parent->{_elements}++;
256381
$parent->{data}{delete $parent->{_key}} = $message;
@@ -265,8 +390,7 @@ sub parse {
265390
}
266391

267392
# Do we need more elements?
268-
if (($self->{api} == 3 and $parent->{_argument} eq '?')
269-
or ($parent->{_elements} || 0) < $parent->{_argument}) {
393+
if ($parent->{_argument} eq '?' or ($parent->{_elements} || 0) < $parent->{_argument}) {
270394
$message = $self->{_message} = {_parent => $parent};
271395
next CHUNK;
272396
}
@@ -278,7 +402,7 @@ sub parse {
278402
delete $message->{_key};
279403

280404
# Attributes apply to the following message
281-
if ($self->{api} == 3 and $message->{type} eq '|') {
405+
if ($message->{type} eq '|') {
282406
$self->{_message} = $message;
283407
$message->{attributes} = delete $message->{data};
284408
delete $message->{type};
@@ -291,10 +415,6 @@ sub parse {
291415
}
292416
}
293417

294-
sub _gather_messages {
295-
push @{$_[0]->{_messages}}, $_[1];
296-
}
297-
298418
1;
299419
__END__
300420

0 commit comments

Comments
 (0)