uringmachine 0.11 → 0.12
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/TODO.md +24 -0
- data/examples/bm_http_parse.rb +112 -37
- data/ext/um/um.h +2 -4
- data/ext/um/um_stream.c +64 -13
- data/ext/um/um_stream_class.c +8 -48
- data/lib/uringmachine/version.rb +1 -1
- data/test/test_stream.rb +71 -20
- data/test/test_um.rb +1 -1
- data/uringmachine.gemspec +1 -0
- metadata +15 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1f8224da7817436bd74a52e650362c9b77d5dbc8877c0fa1cefd1c52e57ceb03
|
4
|
+
data.tar.gz: c7bb88c42bf59a9d1f105e2356c4f71f0fec49c7cbbe662744465ee3b34d5141
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 39d930e9f4d8a17676c28e4bf24f38b585dbd0cd124316272778abb285391be4bb9ecf14452d19568ffa8f6a0144c6a98b2e3ee1f50d58ec7c5101333f5de5e7
|
7
|
+
data.tar.gz: 95468f71d402a2a8abf675dbbae6e94b4e1919c5552f0b831b7387016d3fb24271756585cf66283130ed3440818ccc94f504d73a46d2ab8f9faa4607b0cc822b
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
# 2025-06-03 Version 0.12
|
2
|
+
|
3
|
+
- Add buffer, maxlen params to `Stream#get_line`
|
4
|
+
- Add buffer param to `Stream#get_string`
|
5
|
+
- Remove `Stream#resp_get_line`, `Stream#resp_get_string` methods
|
6
|
+
|
7
|
+
# 2025-06-02 Version 0.11.1
|
8
|
+
|
9
|
+
- Fix `UM::Stream` behaviour on GC
|
10
|
+
|
1
11
|
# 2025-06-02 Version 0.11
|
2
12
|
|
3
13
|
- Implement `UM::Stream` class for read streams
|
data/TODO.md
CHANGED
@@ -22,3 +22,27 @@
|
|
22
22
|
When doing a `call`, we need to provide a mailbox for the response. can this be
|
23
23
|
automatic?
|
24
24
|
|
25
|
+
# streams
|
26
|
+
|
27
|
+
We're still missing:
|
28
|
+
|
29
|
+
- limit on line length in `get_line`
|
30
|
+
- ability to supply buffer to `get_line` and `get_string`
|
31
|
+
- allow read to eof, maybe with `read_to_eof`
|
32
|
+
|
33
|
+
For the sake of performance, simplicity and explicitness, we change the API as follows:
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
stream.get_line(buf, limit)
|
37
|
+
# the defaults:
|
38
|
+
stream.get_line(nil, -1)
|
39
|
+
|
40
|
+
stream.get_string(len, buf)
|
41
|
+
# defaults:
|
42
|
+
stream.get_string(len, nil)
|
43
|
+
|
44
|
+
# and
|
45
|
+
stream.read_to_eof(buf)
|
46
|
+
# defaults:
|
47
|
+
stream.read_to_eof(nil)
|
48
|
+
```
|
data/examples/bm_http_parse.rb
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'bundler/inline'
|
3
|
+
# require 'bundler/inline'
|
4
4
|
|
5
|
-
gemfile do
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
5
|
+
# gemfile do
|
6
|
+
# source 'https://rubygems.org'
|
7
|
+
# gem 'uringmachine', path: '..'
|
8
|
+
# gem 'benchmark-ips'
|
9
|
+
# gem 'http_parser.rb'
|
10
|
+
# end
|
11
11
|
|
12
|
-
require '
|
12
|
+
require 'bundler/setup'
|
13
13
|
require 'uringmachine'
|
14
|
+
require 'benchmark/ips'
|
14
15
|
require 'http/parser'
|
15
16
|
|
16
17
|
$machine = UM.new
|
@@ -19,6 +20,8 @@ HTTP_MSG = "GET /foo/bar HTTP/1.1\r\nServer: foobar.com\r\nFoo: bar\r\n\r\n"
|
|
19
20
|
|
20
21
|
$count = 0
|
21
22
|
|
23
|
+
STDOUT.sync = true
|
24
|
+
|
22
25
|
def parse_http_parser
|
23
26
|
current_fiber = Fiber.current
|
24
27
|
$count += 1
|
@@ -45,10 +48,16 @@ def parse_http_parser
|
|
45
48
|
end
|
46
49
|
|
47
50
|
$machine.write(w.fileno, HTTP_MSG)
|
48
|
-
$machine.yield
|
51
|
+
ret = $machine.yield
|
52
|
+
ret
|
53
|
+
rescue Exception => e
|
54
|
+
p e: e
|
55
|
+
exit
|
49
56
|
ensure
|
50
|
-
|
51
|
-
|
57
|
+
r.close rescue nil
|
58
|
+
w.close rescue nil
|
59
|
+
# $machine.close(r.fileno) rescue nil
|
60
|
+
# $machine.close(w.fileno) rescue nil
|
52
61
|
end
|
53
62
|
|
54
63
|
require 'stringio'
|
@@ -100,50 +109,116 @@ def parse_headers(fd)
|
|
100
109
|
end
|
101
110
|
|
102
111
|
def parse_http_stringio
|
103
|
-
|
104
|
-
|
112
|
+
rfd, wfd = UM.pipe
|
113
|
+
queue = UM::Queue.new
|
105
114
|
|
106
115
|
$machine.spin do
|
107
|
-
headers = parse_headers(
|
108
|
-
$machine.
|
116
|
+
headers = parse_headers(rfd)
|
117
|
+
$machine.push(queue, headers)
|
109
118
|
rescue Exception => e
|
110
119
|
p e
|
111
120
|
puts e.backtrace.join("\n")
|
112
121
|
exit!
|
113
122
|
end
|
114
123
|
|
115
|
-
$machine.write(
|
116
|
-
$machine.
|
124
|
+
$machine.write(wfd, HTTP_MSG)
|
125
|
+
$machine.close(wfd)
|
126
|
+
$machine.shift(queue)
|
117
127
|
ensure
|
118
|
-
$machine.close(
|
119
|
-
$machine.close(
|
128
|
+
($machine.close(rfd) rescue nil) if rfd
|
129
|
+
($machine.close(wfd) rescue nil) if wfd
|
130
|
+
end
|
131
|
+
|
132
|
+
def stream_parse_headers(fd)
|
133
|
+
stream = UM::Stream.new($machine, fd)
|
134
|
+
|
135
|
+
buf = String.new(capacity: 65536)
|
136
|
+
headers = stream_get_request_line(stream, buf)
|
137
|
+
return nil if !headers
|
138
|
+
|
139
|
+
while true
|
140
|
+
line = stream.get_line(buf, 0)
|
141
|
+
break if line.empty?
|
142
|
+
|
143
|
+
m = line.match(RE_HEADER_LINE)
|
144
|
+
raise "Invalid header" if !m
|
145
|
+
|
146
|
+
headers[m[1]] = m[2]
|
147
|
+
end
|
148
|
+
|
149
|
+
headers
|
120
150
|
end
|
121
151
|
|
122
|
-
|
123
|
-
|
124
|
-
# exit
|
152
|
+
def stream_get_request_line(stream, buf)
|
153
|
+
line = stream.get_line(buf, 0)
|
125
154
|
|
126
|
-
|
155
|
+
m = line.match(RE_REQUEST_LINE)
|
156
|
+
return nil if !m
|
157
|
+
|
158
|
+
{
|
159
|
+
'method' => m[1].downcase,
|
160
|
+
'path' => m[2],
|
161
|
+
'protocol' => m[3].downcase
|
162
|
+
}
|
163
|
+
end
|
164
|
+
|
165
|
+
def parse_http_stream
|
166
|
+
rfd, wfd = UM.pipe
|
167
|
+
queue = UM::Queue.new
|
168
|
+
|
169
|
+
$machine.spin do
|
170
|
+
headers = stream_parse_headers(rfd)
|
171
|
+
$machine.push(queue, headers)
|
172
|
+
rescue Exception => e
|
173
|
+
p e
|
174
|
+
puts e.backtrace.join("\n")
|
175
|
+
exit!
|
176
|
+
end
|
177
|
+
|
178
|
+
$machine.write(wfd, HTTP_MSG)
|
179
|
+
$machine.shift(queue)
|
180
|
+
ensure
|
181
|
+
($machine.close(rfd) rescue nil) if rfd
|
182
|
+
($machine.close(wfd) rescue nil) if wfd
|
183
|
+
end
|
184
|
+
|
185
|
+
def compare_allocs
|
186
|
+
GC.disable
|
187
|
+
x = 1000
|
188
|
+
p(
|
189
|
+
alloc_http_parser: alloc_count { x.times { parse_http_parser } },
|
190
|
+
alloc_stringio: alloc_count { x.times { parse_http_stringio } },
|
191
|
+
alloc_stream: alloc_count { x.times { parse_http_stream } }
|
192
|
+
)
|
193
|
+
ensure
|
194
|
+
GC.enable
|
195
|
+
end
|
196
|
+
|
197
|
+
def object_count
|
198
|
+
counts = ObjectSpace.count_objects
|
199
|
+
counts[:TOTAL] - counts[:FREE]
|
200
|
+
end
|
127
201
|
|
128
202
|
def alloc_count
|
129
|
-
|
203
|
+
GC.start
|
204
|
+
count0 = object_count
|
130
205
|
yield
|
131
|
-
|
206
|
+
# GC.start
|
207
|
+
count1 = object_count
|
132
208
|
count1 - count0
|
133
209
|
end
|
134
210
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
alloc_stringio: alloc_count { X.times { parse_http_stringio } }
|
139
|
-
)
|
140
|
-
exit
|
211
|
+
def benchmark
|
212
|
+
Benchmark.ips do |x|
|
213
|
+
x.config(:time => 5, :warmup => 3)
|
141
214
|
|
142
|
-
|
143
|
-
|
215
|
+
x.report("http_parser") { parse_http_parser }
|
216
|
+
x.report("stringio") { parse_http_stringio }
|
217
|
+
x.report("stream") { parse_http_stream }
|
144
218
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
x.compare!
|
219
|
+
x.compare!
|
220
|
+
end
|
149
221
|
end
|
222
|
+
|
223
|
+
compare_allocs
|
224
|
+
benchmark
|
data/ext/um/um.h
CHANGED
@@ -270,10 +270,8 @@ VALUE um_queue_pop(struct um *machine, struct um_queue *queue);
|
|
270
270
|
VALUE um_queue_unshift(struct um *machine, struct um_queue *queue, VALUE value);
|
271
271
|
VALUE um_queue_shift(struct um *machine, struct um_queue *queue);
|
272
272
|
|
273
|
-
|
274
|
-
|
275
|
-
VALUE resp_get_line(struct um_stream *stream, VALUE out_buffer);
|
276
|
-
VALUE resp_get_string(struct um_stream *stream, ulong len, VALUE out_buffer);
|
273
|
+
VALUE stream_get_line(struct um_stream *stream, VALUE buf, ssize_t maxlen);
|
274
|
+
VALUE stream_get_string(struct um_stream *stream, VALUE buf, ssize_t len);
|
277
275
|
VALUE resp_decode(struct um_stream *stream, VALUE out_buffer);
|
278
276
|
void resp_encode(struct um_write_buffer *buf, VALUE obj);
|
279
277
|
|
data/ext/um/um_stream.c
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#include "um.h"
|
2
|
+
#include <stdlib.h>
|
2
3
|
|
3
4
|
static inline void stream_check_truncate_buffer(struct um_stream *stream) {
|
4
5
|
if ((stream->pos == stream->len) && (stream->len >= 1 << 12)) {
|
@@ -40,10 +41,67 @@ int stream_read_more(struct um_stream *stream) {
|
|
40
41
|
return 1;
|
41
42
|
}
|
42
43
|
|
43
|
-
//
|
44
|
+
// ensures given string can hold at least given len bytes (+trailing null)
|
44
45
|
static inline void str_expand(VALUE str, size_t len) {
|
45
|
-
|
46
|
-
|
46
|
+
rb_str_resize(str, len);
|
47
|
+
}
|
48
|
+
|
49
|
+
static inline void str_copy_bytes(VALUE dest, const char *src, ssize_t len) {
|
50
|
+
str_expand(dest, len + 1);
|
51
|
+
char *dest_ptr = RSTRING_PTR(dest);
|
52
|
+
memcpy(dest_ptr, src, len);
|
53
|
+
dest_ptr[len] = 0;
|
54
|
+
rb_str_set_len(dest, len);
|
55
|
+
}
|
56
|
+
|
57
|
+
VALUE stream_get_line(struct um_stream *stream, VALUE buf, ssize_t maxlen) {
|
58
|
+
char *start = RSTRING_PTR(stream->buffer) + stream->pos;
|
59
|
+
while (true) {
|
60
|
+
ssize_t pending_len = stream->len - stream->pos;
|
61
|
+
ssize_t search_len = pending_len;
|
62
|
+
ssize_t absmax_len = labs(maxlen);
|
63
|
+
int should_limit_len = (absmax_len > 0) && (search_len > maxlen);
|
64
|
+
if (should_limit_len) search_len = absmax_len;
|
65
|
+
|
66
|
+
char * lf_ptr = memchr(start, '\n', search_len);
|
67
|
+
if (lf_ptr) {
|
68
|
+
ssize_t len = lf_ptr - start;
|
69
|
+
if (len && (start[len - 1] == '\r')) len -= 1;
|
70
|
+
|
71
|
+
stream->pos += lf_ptr - start + 1;
|
72
|
+
if (NIL_P(buf)) return rb_utf8_str_new(start, len);
|
73
|
+
|
74
|
+
str_copy_bytes(buf, start, len);
|
75
|
+
return buf;
|
76
|
+
}
|
77
|
+
else if (should_limit_len && pending_len > search_len)
|
78
|
+
// maxlen
|
79
|
+
return Qnil;
|
80
|
+
|
81
|
+
if (!stream_read_more(stream))
|
82
|
+
return Qnil;
|
83
|
+
else
|
84
|
+
// update start ptr (it might have changed after reading)
|
85
|
+
start = RSTRING_PTR(stream->buffer) + stream->pos;
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
VALUE stream_get_string(struct um_stream *stream, VALUE buf, ssize_t len) {
|
90
|
+
size_t abslen = labs(len);
|
91
|
+
while (stream->len - stream->pos < abslen)
|
92
|
+
if (!stream_read_more(stream)) {
|
93
|
+
if (len > 0) return Qnil;
|
94
|
+
|
95
|
+
abslen = stream->len - stream->pos;
|
96
|
+
}
|
97
|
+
|
98
|
+
char *start = RSTRING_PTR(stream->buffer) + stream->pos;
|
99
|
+
stream->pos += abslen;
|
100
|
+
|
101
|
+
if (NIL_P(buf)) return rb_utf8_str_new(start, abslen);
|
102
|
+
|
103
|
+
str_copy_bytes(buf, start, len);
|
104
|
+
return buf;
|
47
105
|
}
|
48
106
|
|
49
107
|
VALUE resp_get_line(struct um_stream *stream, VALUE out_buffer) {
|
@@ -58,14 +116,11 @@ VALUE resp_get_line(struct um_stream *stream, VALUE out_buffer) {
|
|
58
116
|
VALUE str = rb_str_new(start, len + 1);
|
59
117
|
rb_str_set_len(str, len);
|
60
118
|
RSTRING_PTR(str)[len] = 0;
|
119
|
+
RB_GC_GUARD(str);
|
61
120
|
return str;
|
62
121
|
}
|
63
122
|
|
64
|
-
|
65
|
-
char *dest_ptr = RSTRING_PTR(out_buffer);
|
66
|
-
memcpy(dest_ptr, start, len);
|
67
|
-
dest_ptr[len] = 0; // add null at end
|
68
|
-
rb_str_set_len(out_buffer, len);
|
123
|
+
str_copy_bytes(out_buffer, start, len);
|
69
124
|
return out_buffer;
|
70
125
|
}
|
71
126
|
|
@@ -88,11 +143,7 @@ VALUE resp_get_string(struct um_stream *stream, ulong len, VALUE out_buffer) {
|
|
88
143
|
|
89
144
|
if (NIL_P(out_buffer)) return rb_utf8_str_new(start, len);
|
90
145
|
|
91
|
-
|
92
|
-
char *dest_ptr = RSTRING_PTR(out_buffer);
|
93
|
-
memcpy(dest_ptr, start, len);
|
94
|
-
dest_ptr[len] = 0; // add null at end
|
95
|
-
rb_str_set_len(out_buffer, len);
|
146
|
+
str_copy_bytes(out_buffer, start, len);
|
96
147
|
return out_buffer;
|
97
148
|
}
|
98
149
|
|
data/ext/um/um_stream_class.c
CHANGED
@@ -37,6 +37,8 @@ static VALUE Stream_allocate(VALUE klass) {
|
|
37
37
|
VALUE Stream_initialize(VALUE self, VALUE machine, VALUE fd) {
|
38
38
|
struct um_stream *stream = RTYPEDDATA_DATA(self);
|
39
39
|
|
40
|
+
stream->self = self;
|
41
|
+
|
40
42
|
stream->machine = RTYPEDDATA_DATA(machine);
|
41
43
|
stream->fd = NUM2ULONG(fd);
|
42
44
|
stream->buffer = rb_utf8_str_new_literal("");
|
@@ -50,57 +52,18 @@ VALUE Stream_initialize(VALUE self, VALUE machine, VALUE fd) {
|
|
50
52
|
return self;
|
51
53
|
}
|
52
54
|
|
53
|
-
VALUE Stream_get_line(VALUE self) {
|
54
|
-
struct um_stream *stream = RTYPEDDATA_DATA(self);
|
55
|
-
if (unlikely(stream->eof)) return Qnil;
|
56
|
-
|
57
|
-
char *start = RSTRING_PTR(stream->buffer) + stream->pos;
|
58
|
-
while (true) {
|
59
|
-
char * lf_ptr = memchr(start, '\n', stream->len - stream->pos);
|
60
|
-
if (lf_ptr) {
|
61
|
-
ulong len = lf_ptr - start;
|
62
|
-
if (len && (start[len - 1] == '\r')) len -= 1;
|
63
|
-
|
64
|
-
VALUE str = rb_str_new(start, len);
|
65
|
-
stream->pos += lf_ptr - start + 1;
|
66
|
-
return str;
|
67
|
-
}
|
68
|
-
|
69
|
-
if (!stream_read_more(stream)) return Qnil;
|
70
|
-
}
|
71
|
-
}
|
72
|
-
|
73
|
-
VALUE Stream_get_string(VALUE self, VALUE len) {
|
74
|
-
struct um_stream *stream = RTYPEDDATA_DATA(self);
|
75
|
-
if (unlikely(stream->eof)) return Qnil;
|
76
|
-
|
77
|
-
ulong ulen = NUM2ULONG(len);
|
78
|
-
|
79
|
-
while (stream->len - stream->pos < ulen)
|
80
|
-
if (!stream_read_more(stream)) return Qnil;
|
81
|
-
|
82
|
-
char *start = RSTRING_PTR(stream->buffer) + stream->pos;
|
83
|
-
VALUE str = rb_utf8_str_new(start, ulen);
|
84
|
-
stream->pos += ulen;
|
85
|
-
return str;
|
86
|
-
}
|
87
|
-
|
88
|
-
VALUE Stream_resp_get_line(VALUE self) {
|
55
|
+
VALUE Stream_get_line(VALUE self, VALUE buf, VALUE limit) {
|
89
56
|
struct um_stream *stream = RTYPEDDATA_DATA(self);
|
90
57
|
if (unlikely(stream->eof)) return Qnil;
|
91
58
|
|
92
|
-
|
93
|
-
RB_GC_GUARD(line);
|
94
|
-
return line;
|
59
|
+
return stream_get_line(stream, buf, NUM2LONG(limit));
|
95
60
|
}
|
96
61
|
|
97
|
-
VALUE
|
62
|
+
VALUE Stream_get_string(VALUE self, VALUE buf, VALUE len) {
|
98
63
|
struct um_stream *stream = RTYPEDDATA_DATA(self);
|
99
64
|
if (unlikely(stream->eof)) return Qnil;
|
100
65
|
|
101
|
-
|
102
|
-
RB_GC_GUARD(str);
|
103
|
-
return str;
|
66
|
+
return stream_get_string(stream, buf, NUM2LONG(len));
|
104
67
|
}
|
105
68
|
|
106
69
|
VALUE Stream_resp_decode(VALUE self) {
|
@@ -128,11 +91,8 @@ void Init_Stream(void) {
|
|
128
91
|
|
129
92
|
rb_define_method(cStream, "initialize", Stream_initialize, 2);
|
130
93
|
|
131
|
-
rb_define_method(cStream, "get_line", Stream_get_line,
|
132
|
-
rb_define_method(cStream, "get_string", Stream_get_string,
|
133
|
-
|
134
|
-
rb_define_method(cStream, "resp_get_line", Stream_resp_get_line, 0);
|
135
|
-
rb_define_method(cStream, "resp_get_string", Stream_resp_get_string, 1);
|
94
|
+
rb_define_method(cStream, "get_line", Stream_get_line, 2);
|
95
|
+
rb_define_method(cStream, "get_string", Stream_get_string, 2);
|
136
96
|
|
137
97
|
rb_define_method(cStream, "resp_decode", Stream_resp_decode, 0);
|
138
98
|
|
data/lib/uringmachine/version.rb
CHANGED
data/test/test_stream.rb
CHANGED
@@ -15,41 +15,92 @@ class StreamTest < StreamBaseTest
|
|
15
15
|
machine.write(@wfd, "foo\nbar\r\nbaz")
|
16
16
|
machine.close(@wfd)
|
17
17
|
|
18
|
-
assert_equal 'foo', @stream.get_line
|
19
|
-
assert_equal 'bar', @stream.get_line
|
20
|
-
assert_nil @stream.get_line
|
18
|
+
assert_equal 'foo', @stream.get_line(nil, 0)
|
19
|
+
assert_equal 'bar', @stream.get_line(nil, 0)
|
20
|
+
assert_nil @stream.get_line(nil, 0)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_get_line_with_buf
|
24
|
+
machine.write(@wfd, "foo\nbar\r\nbaz")
|
25
|
+
machine.close(@wfd)
|
26
|
+
|
27
|
+
buf = +''
|
28
|
+
ret = @stream.get_line(buf, 0)
|
29
|
+
assert_equal 'foo', buf
|
30
|
+
assert_equal ret, buf
|
31
|
+
|
32
|
+
ret = @stream.get_line(buf, 0)
|
33
|
+
assert_equal 'bar', buf
|
34
|
+
assert_equal ret, buf
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_get_line_with_positive_maxlen
|
38
|
+
machine.write(@wfd, "foobar\r\n")
|
39
|
+
machine.close(@wfd)
|
40
|
+
|
41
|
+
buf = +''
|
42
|
+
ret = @stream.get_line(buf, 3)
|
43
|
+
assert_nil ret
|
44
|
+
assert_equal '', buf
|
45
|
+
|
46
|
+
# verify that stream pos has not changed
|
47
|
+
ret = @stream.get_line(buf, 0)
|
48
|
+
assert_equal 'foobar', buf
|
49
|
+
assert_equal ret, buf
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_get_line_with_negative_maxlen
|
53
|
+
machine.write(@wfd, "foobar\r\n")
|
54
|
+
machine.close(@wfd)
|
55
|
+
|
56
|
+
buf = +''
|
57
|
+
ret = @stream.get_line(buf, -3)
|
58
|
+
assert_nil ret
|
59
|
+
assert_equal '', buf
|
60
|
+
|
61
|
+
# verify that stream pos has not changed
|
62
|
+
ret = @stream.get_line(buf, 0)
|
63
|
+
assert_equal 'foobar', buf
|
64
|
+
assert_equal ret, buf
|
21
65
|
end
|
22
66
|
|
23
67
|
def test_get_string
|
24
68
|
machine.write(@wfd, "foobarbazblahzzz")
|
25
69
|
machine.close(@wfd)
|
26
70
|
|
27
|
-
assert_equal 'foobar', @stream.get_string(6)
|
28
|
-
assert_equal 'baz', @stream.get_string(3)
|
29
|
-
assert_equal 'blah', @stream.get_string(4)
|
30
|
-
assert_nil @stream.get_string(4)
|
71
|
+
assert_equal 'foobar', @stream.get_string(nil, 6)
|
72
|
+
assert_equal 'baz', @stream.get_string(nil, 3)
|
73
|
+
assert_equal 'blah', @stream.get_string(nil, 4)
|
74
|
+
assert_nil @stream.get_string(nil, 4)
|
31
75
|
end
|
32
|
-
end
|
33
76
|
|
34
|
-
|
35
|
-
|
36
|
-
machine.write(@wfd, "foo\r\nbarbar\r\nbaz\n")
|
77
|
+
def test_get_string_with_buf
|
78
|
+
machine.write(@wfd, "foobarbazblahzzz")
|
37
79
|
machine.close(@wfd)
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
80
|
+
|
81
|
+
buf = +''
|
82
|
+
ret = @stream.get_string(buf, 6)
|
83
|
+
assert_equal 'foobar', buf
|
84
|
+
assert_equal ret, buf
|
85
|
+
|
86
|
+
ret = @stream.get_string(buf, 3)
|
87
|
+
assert_equal 'baz', buf
|
88
|
+
assert_equal ret, buf
|
42
89
|
end
|
43
90
|
|
44
|
-
def
|
45
|
-
machine.write(@wfd, "
|
91
|
+
def test_get_string_with_negative_len
|
92
|
+
machine.write(@wfd, "foobar")
|
46
93
|
machine.close(@wfd)
|
47
94
|
|
48
|
-
|
49
|
-
assert_equal '
|
50
|
-
|
95
|
+
ret = @stream.get_string(nil, -12)
|
96
|
+
assert_equal 'foobar', ret
|
97
|
+
|
98
|
+
ret = @stream.get_string(nil, -4)
|
99
|
+
assert_nil ret
|
51
100
|
end
|
101
|
+
end
|
52
102
|
|
103
|
+
class StreamRespTest < StreamBaseTest
|
53
104
|
def test_resp_decode
|
54
105
|
machine.write(@wfd, "+foo bar\r\n")
|
55
106
|
assert_equal "foo bar", @stream.resp_decode
|
data/test/test_um.rb
CHANGED
data/uringmachine.gemspec
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: uringmachine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.12'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
@@ -51,6 +51,20 @@ dependencies:
|
|
51
51
|
- - '='
|
52
52
|
- !ruby/object:Gem::Version
|
53
53
|
version: 2.14.0
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: http_parser.rb
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - '='
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 0.8.0
|
61
|
+
type: :development
|
62
|
+
prerelease: false
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - '='
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 0.8.0
|
54
68
|
email: sharon@noteflakes.com
|
55
69
|
executables: []
|
56
70
|
extensions:
|