uringmachine 0.28.3 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ext/um/um_stream.c CHANGED
@@ -1,164 +1,426 @@
1
1
  #include "um.h"
2
2
  #include <stdlib.h>
3
3
 
4
- static inline void stream_check_truncate_buffer(struct um_stream *stream) {
5
- if ((stream->pos == stream->len) && (stream->len >= 1 << 12)) {
6
- rb_str_modify(stream->buffer);
7
- rb_str_set_len(stream->buffer, 0);
8
- stream->len = 0;
9
- stream->pos = 0;
10
- }
11
- else if (stream->pos >= 1 << 12) {
12
- rb_str_modify(stream->buffer);
13
- char *base = RSTRING_PTR(stream->buffer);
14
- int len_rest = stream->len - stream->pos;
15
- memmove(base, base + stream->pos, len_rest);
16
- rb_str_set_len(stream->buffer, len_rest);
17
- stream->len = len_rest;
18
- stream->pos = 0;
4
+ inline void stream_add_segment(struct um_stream *stream, struct um_segment *segment) {
5
+ segment->next = NULL;
6
+ if (stream->tail) {
7
+ stream->tail->next = segment;
8
+ stream->tail = segment;
19
9
  }
10
+ else
11
+ stream->head = stream->tail = segment;
12
+ stream->pending_len += segment->len;
20
13
  }
21
14
 
22
- // returns true if eof
23
- int stream_read_more(struct um_stream *stream) {
24
- stream_check_truncate_buffer(stream);
25
-
26
- size_t maxlen = 1 << 12;
27
- size_t capa = rb_str_capacity(stream->buffer);
28
- if (capa - stream->pos < maxlen)
29
- rb_str_modify_expand(stream->buffer, maxlen - (capa - stream->pos));
15
+ inline int stream_process_op_result(struct um_stream *stream, struct um_op_result *result) {
16
+ if (likely(result->res > 0)) {
17
+ if (likely(result->segment)) {
18
+ stream_add_segment(stream, result->segment);
19
+ result->segment = NULL;
20
+ }
21
+ }
22
+ else
23
+ stream->eof = 1;
30
24
 
31
- rb_str_modify(stream->buffer);
32
- char *ptr = RSTRING_PTR(stream->buffer) + stream->pos;
33
- size_t ret = um_read_raw(stream->machine, stream->fd, ptr, maxlen);
25
+ return result->res;
26
+ }
34
27
 
35
- if (ret == 0) {
36
- stream->eof = 1;
37
- return 0;
28
+ #define STREAM_OP_FLAGS (OP_F_MULTISHOT | OP_F_BUFFER_POOL)
29
+
30
+ void stream_multishot_op_start(struct um_stream *stream) {
31
+ if (!stream->op)
32
+ stream->op = um_op_acquire(stream->machine);
33
+ struct io_uring_sqe *sqe;
34
+
35
+ bp_ensure_commit_level(stream->machine);
36
+
37
+ switch (stream->mode) {
38
+ case STREAM_BP_READ:
39
+ um_prep_op(stream->machine, stream->op, OP_READ_MULTISHOT, 2, STREAM_OP_FLAGS);
40
+ sqe = um_get_sqe(stream->machine, stream->op);
41
+ io_uring_prep_read_multishot(sqe, stream->fd, 0, -1, BP_BGID);
42
+ break;
43
+ case STREAM_BP_RECV:
44
+ um_prep_op(stream->machine, stream->op, OP_RECV_MULTISHOT, 2, STREAM_OP_FLAGS);
45
+ sqe = um_get_sqe(stream->machine, stream->op);
46
+ io_uring_prep_recv_multishot(sqe, stream->fd, NULL, 0, 0);
47
+ sqe->buf_group = BP_BGID;
48
+ sqe->flags |= IOSQE_BUFFER_SELECT;
49
+ break;
50
+ default:
51
+ um_raise_internal_error("Invalid multishot op");
38
52
  }
39
-
40
- stream->len = stream->pos + ret;
41
- rb_str_set_len(stream->buffer, stream->len);
42
- return 1;
53
+ stream->op->bp_commit_threshold = stream->machine->bp_commit_threshold;
43
54
  }
44
55
 
45
- // ensures given string can hold at least given len bytes (+trailing null)
46
- static inline void str_expand(VALUE str, size_t len) {
47
- rb_str_resize(str, len);
56
+ void stream_multishot_op_stop(struct um_stream *stream) {
57
+ assert(!stream->op);
58
+
59
+ if (!(stream->op->flags & OP_F_CQE_DONE)) {
60
+ stream->op->flags |= OP_F_ASYNC;
61
+ um_cancel_op(stream->machine, stream->op);
62
+ }
63
+ else
64
+ um_op_release(stream->machine, stream->op);
65
+ stream->op = NULL;
48
66
  }
49
67
 
50
- static inline void str_copy_bytes(VALUE dest, const char *src, ssize_t len) {
51
- str_expand(dest, len + 1);
52
- char *dest_ptr = RSTRING_PTR(dest);
53
- memcpy(dest_ptr, src, len);
54
- dest_ptr[len] = 0;
55
- rb_str_set_len(dest, len);
68
+ void um_stream_cleanup(struct um_stream *stream) {
69
+ if (stream->op) stream_multishot_op_stop(stream);
70
+
71
+ while (stream->head) {
72
+ struct um_segment *next = stream->head->next;
73
+ um_segment_checkin(stream->machine, stream->head);
74
+ stream->head = next;
75
+ }
76
+ stream->pending_len = 0;
56
77
  }
57
78
 
58
- VALUE stream_get_line(struct um_stream *stream, VALUE buf, ssize_t maxlen) {
59
- while (true) {
60
- char *start = RSTRING_PTR(stream->buffer) + stream->pos;
61
- ssize_t pending_len = stream->len - stream->pos;
62
- ssize_t search_len = pending_len;
63
- ssize_t absmax_len = labs(maxlen);
64
- int should_limit_len = (absmax_len > 0) && (search_len > maxlen);
65
- if (should_limit_len) search_len = absmax_len;
66
-
67
- char * lf_ptr = memchr(start, '\n', search_len);
68
- if (lf_ptr) {
69
- ssize_t len = lf_ptr - start;
70
- if (len && (start[len - 1] == '\r')) len -= 1;
79
+ // returns true if case of ENOBUFS error, sets more to true if more data forthcoming
80
+ inline int stream_process_segments(
81
+ struct um_stream *stream, size_t *total_bytes, int *more) {
82
+
83
+ *more = 0;
84
+ struct um_op_result *result = &stream->op->result;
85
+ stream->op->flags &= ~OP_F_CQE_SEEN;
86
+ while (result) {
87
+ if (unlikely(result->res == -ENOBUFS)) {
88
+ *more = 0;
89
+ return true;
90
+ }
91
+ if (unlikely(result->res == -ECANCELED)) {
92
+ *more = 0;
93
+ return false;
94
+ }
95
+ um_raise_on_error_result(result->res);
71
96
 
72
- stream->pos += lf_ptr - start + 1;
73
- if (NIL_P(buf)) return rb_utf8_str_new(start, len);
97
+ *more = (result->flags & IORING_CQE_F_MORE);
98
+ *total_bytes += result->res;
99
+ stream_process_op_result(stream, result);
100
+ result = result->next;
101
+ }
102
+ return false;
103
+ }
74
104
 
75
- str_copy_bytes(buf, start, len);
76
- return buf;
105
+ void stream_clear(struct um_stream *stream) {
106
+ if (stream->op && stream->machine->ring_initialized) {
107
+ if (OP_CQE_SEEN_P(stream->op)) {
108
+ size_t total_bytes = 0;
109
+ int more = false;
110
+ stream_process_segments(stream, &total_bytes, &more);
111
+ um_op_multishot_results_clear(stream->machine, stream->op);
77
112
  }
78
- else if (should_limit_len && pending_len > search_len)
79
- // hit maxlen
80
- return Qnil;
81
113
 
82
- if (!stream_read_more(stream))
83
- return Qnil;
114
+ if (OP_CQE_DONE_P(stream->op))
115
+ um_op_release(stream->machine, stream->op);
116
+ else
117
+ um_cancel_op_and_discard_cqe(stream->machine, stream->op);
118
+
119
+ stream->op = NULL;
120
+ }
121
+
122
+ while (stream->head) {
123
+ struct um_segment *next = stream->head->next;
124
+ um_segment_checkin(stream->machine, stream->head);
125
+ stream->head = next;
126
+ }
127
+ stream->pending_len = 0;
128
+
129
+ if (stream->working_buffer) {
130
+ bp_buffer_checkin(stream->machine, stream->working_buffer);
131
+ stream->working_buffer = NULL;
84
132
  }
85
133
  }
86
134
 
87
- VALUE stream_get_string(struct um_stream *stream, VALUE buf, ssize_t len) {
88
- size_t abslen = labs(len);
89
- while (stream->len - stream->pos < abslen) {
90
- if (!stream_read_more(stream)) {
91
- if (len > 0)
92
- return Qnil;
135
+ inline void stream_await_segments(struct um_stream *stream) {
136
+ if (unlikely(!stream->op)) stream_multishot_op_start(stream);
137
+
138
+ if (!OP_CQE_SEEN_P(stream->op)) {
139
+ stream->op->flags &= ~OP_F_ASYNC;
140
+ VALUE ret = um_yield(stream->machine);
141
+ stream->op->flags |= OP_F_ASYNC;
142
+ if (!OP_CQE_SEEN_P(stream->op)) RAISE_IF_EXCEPTION(ret);
143
+ RB_GC_GUARD(ret);
144
+ }
145
+ }
146
+
147
+ int stream_get_more_segments_bp(struct um_stream *stream) {
148
+ size_t total_bytes = 0;
149
+ int more = false;
150
+ int enobufs = false;
151
+
152
+ while (1) {
153
+ if (unlikely(stream->eof)) return 0;
93
154
 
94
- abslen = stream->len - stream->pos;
155
+ stream_await_segments(stream);
156
+ enobufs = stream_process_segments(stream, &total_bytes, &more);
157
+ um_op_multishot_results_clear(stream->machine, stream->op);
158
+ if (unlikely(enobufs)) {
159
+ int should_restart = stream->pending_len < (stream->machine->bp_buffer_size * 4);
160
+
161
+ // If multiple stream ops are happening at the same time, they'll all get
162
+ // ENOBUFS! We track the commit threshold in the op in order to prevent
163
+ // running bp_handle_enobufs() more than once.
164
+
165
+ if (should_restart) {
166
+ if (stream->op->bp_commit_threshold == stream->machine->bp_commit_threshold)
167
+ bp_handle_enobufs(stream->machine);
168
+ stream_multishot_op_start(stream);
169
+ }
170
+ else {
171
+ um_op_release(stream->machine, stream->op);
172
+ stream->op = NULL;
173
+ }
174
+
175
+ if (total_bytes) return total_bytes;
176
+ }
177
+ else {
178
+ if (more)
179
+ stream->op->flags &= ~OP_F_CQE_SEEN;
180
+ if (total_bytes || stream->eof) return total_bytes;
95
181
  }
96
182
  }
183
+ }
97
184
 
98
- char *start = RSTRING_PTR(stream->buffer) + stream->pos;
99
- stream->pos += abslen;
185
+ int stream_get_more_segments_ssl(struct um_stream *stream) {
186
+ if (!stream->working_buffer)
187
+ stream->working_buffer = bp_buffer_checkout(stream->machine);
100
188
 
101
- if (NIL_P(buf)) return rb_utf8_str_new(start, abslen);
189
+ char *ptr = stream->working_buffer->buf + stream->working_buffer->pos;
190
+ size_t maxlen = stream->working_buffer->len - stream->working_buffer->pos;
191
+ int res = um_ssl_read_raw(stream->machine, stream->target, ptr, maxlen);
192
+ if (res == 0) return 0;
193
+ if (res < 0) rb_raise(eUMError, "Failed to read segment");
102
194
 
103
- str_copy_bytes(buf, start, abslen);
104
- return buf;
195
+ struct um_segment *segment = bp_buffer_consume(stream->machine, stream->working_buffer, res);
196
+ if ((size_t)res == maxlen) {
197
+ bp_buffer_checkin(stream->machine, stream->working_buffer);
198
+ stream->working_buffer = NULL;
199
+ }
200
+ stream_add_segment(stream, segment);
201
+ return 1;
105
202
  }
106
203
 
107
- VALUE stream_skip(struct um_stream *stream, size_t len) {
108
- while (stream->len - stream->pos < len)
109
- if (!stream_read_more(stream)) {
110
- return Qnil;
204
+ int stream_get_more_segments(struct um_stream *stream) {
205
+ switch (stream->mode) {
206
+ case STREAM_BP_READ:
207
+ case STREAM_BP_RECV:
208
+ return stream_get_more_segments_bp(stream);
209
+ case STREAM_SSL:
210
+ return stream_get_more_segments_ssl(stream);
211
+ default:
212
+ rb_raise(eUMError, "Invalid stream mode");
213
+ }
214
+ }
215
+
216
+ ///////////////////////////////////////////////////////////////////////////////////////
217
+
218
+
219
+ VALUE stream_consume_string(struct um_stream *stream, VALUE out_buffer, size_t len, size_t inc, int safe_inc) {
220
+ VALUE str = Qnil;
221
+ if (!NIL_P(out_buffer)) {
222
+ str = out_buffer;
223
+ size_t str_len = RSTRING_LEN(str);
224
+ if (str_len < len)
225
+ rb_str_resize(str, len);
226
+ else if (str_len > len)
227
+ rb_str_set_len(str, len);
228
+ }
229
+ else
230
+ str = rb_str_new(NULL, len);
231
+ char *str_ptr = RSTRING_PTR(str);
232
+ while (len) {
233
+ char *segment_ptr = stream->head->ptr + stream->pos;
234
+ size_t segment_len = stream->head->len - stream->pos;
235
+ size_t cpy_len = (segment_len <= len) ? segment_len : len;
236
+ memcpy(str_ptr, segment_ptr, cpy_len);
237
+
238
+ len -= cpy_len;
239
+ stream->pos += cpy_len;
240
+ stream->pending_len -= cpy_len;
241
+ str_ptr += cpy_len;
242
+ if (stream->pos == stream->head->len) {
243
+ struct um_segment *consumed = stream->head;
244
+ stream->head = consumed->next;
245
+ if (!stream->head) stream->tail = NULL;
246
+ um_segment_checkin(stream->machine, consumed);
247
+ stream->pos = 0;
111
248
  }
249
+ }
112
250
 
113
- stream->pos += len;
114
- return NUM2INT(len);
251
+ while (inc) {
252
+ size_t segment_len = stream->head->len - stream->pos;
253
+ size_t inc_len = (segment_len <= inc) ? segment_len : inc;
254
+ inc -= inc_len;
255
+ stream->pos += inc_len;
256
+ stream->pending_len -= inc_len;
257
+ if (stream->pos == stream->head->len) {
258
+ struct um_segment *consumed = stream->head;
259
+ stream->head = consumed->next;
260
+ um_segment_checkin(stream->machine, consumed);
261
+ if (!stream->head) {
262
+ stream->tail = NULL;
263
+ if (inc && safe_inc) {
264
+ if (!stream_get_more_segments(stream)) break;
265
+ }
266
+ }
267
+ stream->pos = 0;
268
+ }
269
+ }
270
+ return str;
271
+ RB_GC_GUARD(str);
115
272
  }
116
273
 
117
- VALUE resp_get_line(struct um_stream *stream, VALUE out_buffer) {
118
- char *start = RSTRING_PTR(stream->buffer) + stream->pos;
274
+ // inline void stream_advance(struct um_stream *stream, size_t inc) {
275
+ // while (inc) {
276
+ // size_t segment_len = stream->head->len - stream->pos;
277
+ // size_t inc_len = (segment_len <= inc) ? segment_len : inc;
278
+ // inc -= inc_len;
279
+ // stream->pos += inc_len;
280
+ // if (stream->pos == stream->head->len) {
281
+ // struct um_segment *consumed = stream->head;
282
+ // stream->head = consumed->next;
283
+ // um_segment_checkin(stream->machine, consumed);
284
+ // if (!stream->head) {
285
+ // stream->tail = NULL;
286
+ // if (!stream_get_more_segments(stream)) return;
287
+ // }
288
+ // stream->pos = 0;
289
+ // }
290
+ // }
291
+ // }
292
+
293
+ VALUE stream_get_line(struct um_stream *stream, VALUE out_buffer, size_t maxlen) {
294
+ if (unlikely(stream->eof && !stream->head)) return Qnil;
295
+ if (!stream->tail && !stream_get_more_segments(stream)) return Qnil;
296
+
297
+ struct um_segment *last = NULL;
298
+ struct um_segment *current = stream->head;
299
+ size_t remaining_len = maxlen;
300
+ size_t total_len = 0;
301
+ size_t inc = 1;
302
+ size_t pos = stream->pos;
303
+
119
304
  while (true) {
120
- char * lf_ptr = memchr(start, '\r', stream->len - stream->pos);
305
+ size_t segment_len = current->len - pos;
306
+ size_t search_len = segment_len;
307
+ if (maxlen && (search_len > remaining_len)) search_len = remaining_len;
308
+ char *start = current->ptr + pos;
309
+ char *lf_ptr = memchr(start, '\n', search_len);
310
+
121
311
  if (lf_ptr) {
122
- ulong len = lf_ptr - start;
123
- stream->pos += len + 2;
124
-
125
- if (NIL_P(out_buffer)) {
126
- VALUE str = rb_interned_str(start, len + 1);
127
- rb_str_set_len(str, len);
128
- RSTRING_PTR(str)[len] = 0;
129
- RB_GC_GUARD(str);
130
- return str;
312
+ size_t len = lf_ptr - start;
313
+
314
+ total_len += len;
315
+
316
+ // search for \r
317
+ if (total_len) {
318
+ if (len) {
319
+ if (start[len - 1] == '\r') {
320
+ total_len -= 1;
321
+ inc = 2;
322
+ }
323
+ }
324
+ else {
325
+ if (last && (((char *)last->ptr)[last->len - 1] == '\r')) {
326
+ total_len -= 1;
327
+ inc = 2;
328
+ }
329
+ }
131
330
  }
132
331
 
133
- str_copy_bytes(out_buffer, start, len);
134
- return out_buffer;
332
+ return stream_consume_string(stream, out_buffer, total_len, inc, false);
135
333
  }
334
+ else {
335
+ // not found, early return if segment len exceeds maxlen
336
+ if (maxlen && segment_len >= maxlen) return Qnil;
136
337
 
137
- if (stream_read_more(stream))
138
- // buffer ptr and pos may have changed after reading
139
- start = RSTRING_PTR(stream->buffer) + stream->pos;
140
- else
141
- return Qnil;
338
+ total_len += segment_len;
339
+ remaining_len -= segment_len;
340
+ }
341
+
342
+ if (!current->next) {
343
+ if (!stream_get_more_segments(stream)) {
344
+ return Qnil;
345
+ }
346
+ }
347
+
348
+ last = current;
349
+ current = current->next;
350
+ pos = 0;
142
351
  }
143
352
  }
144
353
 
145
- VALUE resp_get_string(struct um_stream *stream, ulong len, VALUE out_buffer) {
146
- ulong read_len = len + 2;
354
+ VALUE stream_get_string(struct um_stream *stream, VALUE out_buffer, ssize_t len, size_t inc, int safe_inc) {
355
+ if (unlikely(stream->eof && !stream->head)) return Qnil;
356
+ if (!stream->tail && !stream_get_more_segments(stream)) return Qnil;
147
357
 
148
- while (stream->len - stream->pos < read_len)
149
- if (!stream_read_more(stream)) return Qnil;
358
+ struct um_segment *current = stream->head;
359
+ size_t abs_len = labs(len);
360
+ size_t remaining_len = abs_len;
361
+ size_t total_len = 0;
362
+ size_t pos = stream->pos;
150
363
 
151
- char *start = RSTRING_PTR(stream->buffer) + stream->pos;
152
- stream->pos += read_len;
364
+ while (true) {
365
+ size_t segment_len = current->len - pos;
366
+ if (abs_len && segment_len > remaining_len) {
367
+ segment_len = remaining_len;
368
+ }
369
+ total_len += segment_len;
370
+ if (abs_len) {
371
+ remaining_len -= segment_len;
372
+ if (!remaining_len)
373
+ return stream_consume_string(stream, out_buffer, total_len, inc, safe_inc);
374
+ }
375
+
376
+ if (!current->next) {
377
+ if (len <= 0)
378
+ return stream_consume_string(stream, out_buffer, total_len, inc, safe_inc);
379
+
380
+ if (!stream_get_more_segments(stream))
381
+ return Qnil;
382
+ }
383
+ current = current->next;
384
+ pos = 0;
385
+ }
386
+ }
387
+
388
+ VALUE resp_get_line(struct um_stream *stream, VALUE out_buffer) {
389
+ if (unlikely(stream->eof && !stream->head)) return Qnil;
390
+ if (!stream->tail && !stream_get_more_segments(stream)) return Qnil;
391
+
392
+ struct um_segment *current = stream->head;
393
+ size_t total_len = 0;
394
+ size_t pos = stream->pos;
395
+
396
+ while (true) {
397
+ size_t segment_len = current->len - pos;
398
+ char *start = current->ptr + pos;
399
+ char *lf_ptr = memchr(start, '\r', segment_len);
400
+ if (lf_ptr) {
401
+ size_t len = lf_ptr - start;
402
+ total_len += len;
403
+ return stream_consume_string(stream, out_buffer, total_len, 2, true);
404
+ }
405
+ else
406
+ total_len += segment_len;
153
407
 
154
- if (NIL_P(out_buffer)) return rb_utf8_str_new(start, len);
408
+ if (!current->next)
409
+ if (!stream_get_more_segments(stream)) return Qnil;
155
410
 
156
- str_copy_bytes(out_buffer, start, len);
157
- return out_buffer;
411
+ current = current->next;
412
+ }
413
+ }
414
+
415
+ inline VALUE resp_get_string(struct um_stream *stream, ulong len, VALUE out_buffer) {
416
+ return stream_get_string(stream, out_buffer, len, 2, true);
158
417
  }
159
418
 
160
419
  inline ulong resp_parse_length_field(const char *ptr, int len) {
161
- return strtoul(ptr + 1, NULL, 10);
420
+ ulong acc = 0;
421
+ for(int i = 1; i < len; i++)
422
+ acc = acc * 10 + (ptr[i] - '0');
423
+ return acc;
162
424
  }
163
425
 
164
426
  VALUE resp_decode_hash(struct um_stream *stream, VALUE out_buffer, ulong len) {
@@ -180,8 +442,7 @@ VALUE resp_decode_array(struct um_stream *stream, VALUE out_buffer, ulong len) {
180
442
  VALUE array = rb_ary_new2(len);
181
443
 
182
444
  for (ulong i = 0; i < len; i++) {
183
- VALUE buf = rb_str_new(NULL, 100);
184
- VALUE value = resp_decode(stream, buf);
445
+ VALUE value = resp_decode(stream, out_buffer);
185
446
  rb_ary_push(array, value);
186
447
  RB_GC_GUARD(value);
187
448
  }
@@ -191,11 +452,11 @@ VALUE resp_decode_array(struct um_stream *stream, VALUE out_buffer, ulong len) {
191
452
  }
192
453
 
193
454
  static inline VALUE resp_decode_simple_string(char *ptr, ulong len) {
194
- return rb_interned_str(ptr + 1, len - 1);
455
+ return rb_str_new(ptr + 1, len - 1);
195
456
  }
196
457
 
197
- static inline VALUE resp_decode_string(struct um_stream *stream, ulong len) {
198
- return resp_get_string(stream, len, Qnil);
458
+ static inline VALUE resp_decode_string(struct um_stream *stream, VALUE out_buffer, ulong len) {
459
+ return resp_get_string(stream, len, out_buffer);
199
460
  }
200
461
 
201
462
  static inline VALUE resp_decode_string_with_encoding(struct um_stream *stream, VALUE out_buffer, ulong len) {
@@ -221,7 +482,7 @@ static inline VALUE resp_decode_simple_error(char *ptr, ulong len) {
221
482
  static ID ID_new = 0;
222
483
  if (!ID_new) ID_new = rb_intern("new");
223
484
 
224
- VALUE msg = rb_interned_str(ptr + 1, len - 1);
485
+ VALUE msg = rb_str_new(ptr + 1, len - 1);
225
486
  VALUE err = rb_funcall(eStreamRESPError, ID_new, 1, msg);
226
487
  RB_GC_GUARD(msg);
227
488
  return err;
@@ -231,7 +492,7 @@ static inline VALUE resp_decode_error(struct um_stream *stream, VALUE out_buffer
231
492
  static ID ID_new = 0;
232
493
  if (!ID_new) ID_new = rb_intern("new");
233
494
 
234
- VALUE msg = resp_decode_string(stream, len);
495
+ VALUE msg = resp_decode_string(stream, out_buffer, len);
235
496
  VALUE err = rb_funcall(eStreamRESPError, ID_new, 1, msg);
236
497
  RB_GC_GUARD(msg);
237
498
  return err;
@@ -262,7 +523,7 @@ VALUE resp_decode(struct um_stream *stream, VALUE out_buffer) {
262
523
  return resp_decode_simple_string(ptr, len);
263
524
  case '$': // string
264
525
  data_len = resp_parse_length_field(ptr, len);
265
- return resp_decode_string(stream, data_len);
526
+ return resp_decode_string(stream, out_buffer, data_len);
266
527
  case '=': // string with encoding
267
528
  data_len = resp_parse_length_field(ptr, len);
268
529
  return resp_decode_string_with_encoding(stream, out_buffer, data_len);
@@ -404,34 +665,3 @@ void resp_encode(struct um_write_buffer *buf, VALUE obj) {
404
665
  um_raise_internal_error("Can't encode object");
405
666
  }
406
667
  }
407
-
408
- void resp_encode_cmd(struct um_write_buffer *buf, int argc, VALUE *argv) {
409
- char tmp1[48];
410
- char tmp2[60];
411
-
412
- sprintf(tmp1, "*%d\r\n", argc);
413
- write_buffer_append_cstr(buf, tmp1);
414
- for (int i = 0; i < argc; i++) {
415
- switch (TYPE(argv[i])) {
416
- case T_FIXNUM:
417
- sprintf(tmp1, "%ld", NUM2LONG(argv[i]));
418
- sprintf(tmp2, "$%ld\r\n%s\r\n", strlen(tmp1), (char *)tmp1);
419
- write_buffer_append_cstr(buf, tmp2);
420
- break;
421
- case T_FLOAT:
422
- sprintf(tmp1, "%lg", NUM2DBL(argv[i]));
423
- sprintf(tmp2, "$%ld\r\n%s\r\n", strlen(tmp1), (char *)tmp1);
424
- write_buffer_append_cstr(buf, tmp2);
425
- break;
426
- case T_STRING:
427
- write_buffer_append_resp_bulk_string(buf, argv[i]);
428
- break;
429
- case T_SYMBOL:
430
- write_buffer_append_resp_bulk_string(buf, rb_sym_to_s(argv[i]));
431
- break;
432
- default:
433
- um_raise_internal_error("Can't encode object");
434
- }
435
- }
436
- return;
437
- }