nio4r 2.5.7 → 2.7.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +2 -0
  3. data/{CHANGES.md → changes.md} +48 -0
  4. data/ext/libev/ev_iouring.c +2 -2
  5. data/ext/nio4r/bytebuffer.c +75 -38
  6. data/ext/nio4r/extconf.rb +19 -1
  7. data/ext/nio4r/monitor.c +47 -22
  8. data/ext/nio4r/nio4r.h +1 -5
  9. data/ext/nio4r/org/nio4r/ByteBuffer.java +1 -1
  10. data/ext/nio4r/org/nio4r/Monitor.java +2 -2
  11. data/ext/nio4r/org/nio4r/Selector.java +2 -2
  12. data/ext/nio4r/selector.c +72 -48
  13. data/lib/nio/bytebuffer.rb +6 -0
  14. data/lib/nio/monitor.rb +7 -0
  15. data/lib/nio/selector.rb +15 -0
  16. data/lib/nio/version.rb +6 -1
  17. data/lib/nio.rb +9 -0
  18. data/lib/nio4r.rb +7 -0
  19. data/license.md +80 -0
  20. data/readme.md +91 -0
  21. data.tar.gz.sig +0 -0
  22. metadata +95 -74
  23. metadata.gz.sig +0 -0
  24. data/.github/workflows/workflow.yml +0 -47
  25. data/.gitignore +0 -21
  26. data/.rspec +0 -4
  27. data/.rubocop.yml +0 -100
  28. data/Gemfile +0 -19
  29. data/README.md +0 -133
  30. data/Rakefile +0 -8
  31. data/examples/echo_server.rb +0 -47
  32. data/logo.png +0 -0
  33. data/nio4r.gemspec +0 -42
  34. data/rakelib/extension.rake +0 -15
  35. data/rakelib/rspec.rake +0 -9
  36. data/rakelib/rubocop.rake +0 -5
  37. data/spec/nio/acceptables_spec.rb +0 -32
  38. data/spec/nio/bytebuffer_spec.rb +0 -354
  39. data/spec/nio/monitor_spec.rb +0 -162
  40. data/spec/nio/selectables/pipe_spec.rb +0 -47
  41. data/spec/nio/selectables/ssl_socket_spec.rb +0 -194
  42. data/spec/nio/selectables/tcp_socket_spec.rb +0 -101
  43. data/spec/nio/selectables/udp_socket_spec.rb +0 -48
  44. data/spec/nio/selector_spec.rb +0 -240
  45. data/spec/spec_helper.rb +0 -20
  46. data/spec/support/selectable_examples.rb +0 -85
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "spec_helper"
4
-
5
- RSpec.describe "NIO acceptables" do
6
- shared_context "an NIO acceptable" do
7
- let(:selector) { NIO::Selector.new }
8
-
9
- it "selects for read readiness" do
10
- waiting_monitor = selector.register(unacceptable_subject, :r)
11
- ready_monitor = selector.register(acceptable_subject, :r)
12
-
13
- ready_monitors = selector.select
14
- expect(ready_monitors).to include ready_monitor
15
- expect(ready_monitors).not_to include waiting_monitor
16
- end
17
- end
18
-
19
- describe TCPServer do
20
- let :acceptable_subject do
21
- server = TCPServer.new("127.0.0.1", 0)
22
- TCPSocket.open("127.0.0.1", server.local_address.ip_port)
23
- server
24
- end
25
-
26
- let :unacceptable_subject do
27
- TCPServer.new("127.0.0.1", 0)
28
- end
29
-
30
- it_behaves_like "an NIO acceptable"
31
- end
32
- end
@@ -1,354 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "spec_helper"
4
-
5
- RSpec.describe NIO::ByteBuffer do
6
- let(:capacity) { 256 }
7
- let(:example_string) { "Testing 1 2 3..." }
8
- subject(:bytebuffer) { described_class.new(capacity) }
9
-
10
- describe "#initialize" do
11
- it "raises TypeError if given a bogus argument" do
12
- expect { described_class.new(:symbols_are_bogus) }.to raise_error(TypeError)
13
- end
14
- end
15
-
16
- describe "#clear" do
17
- it "clears the buffer" do
18
- bytebuffer << example_string
19
- bytebuffer.clear
20
-
21
- expect(bytebuffer.remaining).to eq capacity
22
- end
23
- end
24
-
25
- describe "#position" do
26
- it "defaults to zero" do
27
- expect(bytebuffer.position).to be_zero
28
- end
29
- end
30
-
31
- describe "#position=" do
32
- let(:example_position) { 42 }
33
-
34
- it "sets the buffer's position to a valid value" do
35
- expect(bytebuffer.position).to be_zero
36
- bytebuffer.position = example_position
37
- expect(bytebuffer.position).to eq example_position
38
- end
39
-
40
- it "raises ArgumentError if the specified position is less than zero" do
41
- expect { bytebuffer.position = -1 }.to raise_error(ArgumentError)
42
- end
43
-
44
- it "raises ArgumentError if the specified position exceeds the limit" do
45
- expect { bytebuffer.position = capacity + 1 }.to raise_error(ArgumentError)
46
- end
47
- end
48
-
49
- describe "#limit" do
50
- it "defaults to the buffer's capacity" do
51
- expect(bytebuffer.limit).to eq capacity
52
- end
53
- end
54
-
55
- describe "#limit=" do
56
- it "sets the buffer's limit to a valid value" do
57
- bytebuffer.flip
58
- expect(bytebuffer.limit).to be_zero
59
-
60
- new_limit = capacity / 2
61
- bytebuffer.limit = new_limit
62
- expect(bytebuffer.limit).to eq new_limit
63
- end
64
-
65
- it "preserves position and mark if they're less than the new limit" do
66
- bytebuffer << "four"
67
- bytebuffer.mark
68
- bytebuffer << "more"
69
-
70
- bytebuffer.limit = capacity / 2
71
- expect(bytebuffer.position).to eq 8
72
- bytebuffer.reset
73
- expect(bytebuffer.position).to eq 4
74
- end
75
-
76
- it "sets position to the new limit if the previous position is beyond the limit" do
77
- bytebuffer << "four"
78
- bytebuffer.limit = 2
79
- expect(bytebuffer.position).to eq 2
80
- end
81
-
82
- it "clears the mark if the new limit is before the current mark" do
83
- bytebuffer << "four"
84
- bytebuffer.mark
85
- bytebuffer.limit = 2
86
- expect { bytebuffer.reset }.to raise_error(NIO::ByteBuffer::MarkUnsetError)
87
- end
88
-
89
- it "raises ArgumentError if specified limit is less than zero" do
90
- expect { bytebuffer.limit = -1 }.to raise_error(ArgumentError)
91
- end
92
-
93
- it "raises ArgumentError if specified limit exceeds capacity" do
94
- expect { bytebuffer.limit = capacity }.not_to raise_error
95
- expect { bytebuffer.limit = capacity + 1 }.to raise_error(ArgumentError)
96
- end
97
- end
98
-
99
- describe "#capacity" do
100
- it "has the requested capacity" do
101
- expect(bytebuffer.capacity).to eq capacity
102
- end
103
- end
104
-
105
- describe "#remaining" do
106
- it "calculates the number of bytes remaining" do
107
- expect(bytebuffer.remaining).to eq capacity
108
- bytebuffer << example_string
109
- expect(bytebuffer.remaining).to eq(capacity - example_string.length)
110
- end
111
- end
112
-
113
- describe "#full?" do
114
- it "returns false when there is space remaining in the buffer" do
115
- expect(bytebuffer).not_to be_full
116
- end
117
-
118
- it "returns true when the buffer is full" do
119
- bytebuffer << "X" * capacity
120
- expect(bytebuffer).to be_full
121
- end
122
- end
123
-
124
- describe "#get" do
125
- it "reads all remaining data if no length is given" do
126
- bytebuffer << example_string
127
- bytebuffer.flip
128
-
129
- expect(bytebuffer.get).to eq example_string
130
- end
131
-
132
- it "reads zeroes from a newly initialized buffer" do
133
- expect(bytebuffer.get(capacity)).to eq("\0" * capacity)
134
- end
135
-
136
- it "advances position as data is read" do
137
- bytebuffer << "First"
138
- bytebuffer << "Second"
139
- bytebuffer << "Third"
140
- bytebuffer.flip
141
-
142
- expect(bytebuffer.position).to be_zero
143
- expect(bytebuffer.get(10)).to eq "FirstSecon"
144
- expect(bytebuffer.position).to eq 10
145
- end
146
-
147
- it "raises NIO::ByteBuffer::UnderflowError if there is not enough data in the buffer" do
148
- bytebuffer << example_string
149
- bytebuffer.flip
150
-
151
- expect { bytebuffer.get(example_string.length + 1) }.to raise_error(NIO::ByteBuffer::UnderflowError)
152
- expect(bytebuffer.get(example_string.length)).to eq example_string
153
- end
154
- end
155
-
156
- describe "#[]" do
157
- it "obtains bytes at a given index without altering position" do
158
- bytebuffer << example_string
159
- expect(bytebuffer[7]).to eq example_string.bytes[7]
160
- expect(bytebuffer.position).to eq example_string.length
161
- end
162
-
163
- it "raises ArgumentError if the index is less than zero" do
164
- expect { bytebuffer[-1] }.to raise_error(ArgumentError)
165
- end
166
-
167
- it "raises ArgumentError if the index exceeds the limit" do
168
- bytebuffer << example_string
169
- bytebuffer.flip
170
- expect(bytebuffer[bytebuffer.limit - 1]).to eq example_string.bytes.last
171
- expect { bytebuffer[bytebuffer.limit] }.to raise_error(ArgumentError)
172
- end
173
- end
174
-
175
- describe "#<<" do
176
- it "adds strings to the buffer" do
177
- bytebuffer << example_string
178
- expect(bytebuffer.position).to eq example_string.length
179
- expect(bytebuffer.limit).to eq capacity
180
- end
181
-
182
- it "raises TypeError if given a non-String type" do
183
- expect { bytebuffer << 42 }.to raise_error(TypeError)
184
- expect { bytebuffer << nil }.to raise_error(TypeError)
185
- end
186
-
187
- it "raises NIO::ByteBuffer::OverflowError if the buffer is full" do
188
- bytebuffer << "X" * (capacity - 1)
189
- expect { bytebuffer << "X" }.not_to raise_error
190
- expect { bytebuffer << "X" }.to raise_error(NIO::ByteBuffer::OverflowError)
191
- end
192
- end
193
-
194
- describe "#flip" do
195
- it "flips the bytebuffer" do
196
- bytebuffer << example_string
197
- expect(bytebuffer.position).to eql example_string.length
198
-
199
- expect(bytebuffer.flip).to eq bytebuffer
200
-
201
- expect(bytebuffer.position).to be_zero
202
- expect(bytebuffer.limit).to eq example_string.length
203
- expect(bytebuffer.get).to eq example_string
204
- end
205
-
206
- it "sets remaining to the previous position" do
207
- bytebuffer << example_string
208
- previous_position = bytebuffer.position
209
- expect(bytebuffer.remaining).to eq(capacity - previous_position)
210
- expect(bytebuffer.flip.remaining).to eq previous_position
211
- end
212
-
213
- it "sets limit to the previous position" do
214
- bytebuffer << example_string
215
- expect(bytebuffer.limit).to eql(capacity)
216
-
217
- previous_position = bytebuffer.position
218
- expect(bytebuffer.flip.limit).to eql previous_position
219
- end
220
- end
221
-
222
- describe "#rewind" do
223
- it "rewinds the buffer leaving the limit intact" do
224
- bytebuffer << example_string
225
- expect(bytebuffer.rewind).to eq bytebuffer
226
-
227
- expect(bytebuffer.position).to be_zero
228
- expect(bytebuffer.limit).to eq capacity
229
- end
230
- end
231
-
232
- describe "#mark" do
233
- it "returns self" do
234
- expect(bytebuffer.mark).to eql bytebuffer
235
- end
236
- end
237
-
238
- describe "#reset" do
239
- it "returns to a previously marked position" do
240
- bytebuffer << "First"
241
- expected_position = bytebuffer.position
242
-
243
- expect(bytebuffer.mark).to eq bytebuffer
244
- bytebuffer << "Second"
245
- expect(bytebuffer.position).not_to eq expected_position
246
- expect(bytebuffer.reset.position).to eq expected_position
247
- end
248
-
249
- it "raises NIO::ByteBuffer::MarkUnsetError unless mark has been set" do
250
- expect { bytebuffer.reset }.to raise_error(NIO::ByteBuffer::MarkUnsetError)
251
- end
252
- end
253
-
254
- describe "#compact" do
255
- let(:first_string) { "CompactMe" }
256
- let(:second_string) { "Leftover" }
257
-
258
- it "copies data from the current position to the beginning of the buffer" do
259
- bytebuffer << first_string << second_string
260
- bytebuffer.position = first_string.length
261
- bytebuffer.limit = first_string.length + second_string.length
262
- bytebuffer.compact
263
-
264
- expect(bytebuffer.position).to eq second_string.length
265
- expect(bytebuffer.limit).to eq capacity
266
- expect(bytebuffer.flip.get).to eq second_string
267
- end
268
- end
269
-
270
- describe "#each" do
271
- it "iterates over data in the buffer" do
272
- bytebuffer << example_string
273
- bytebuffer.flip
274
-
275
- bytes = []
276
- bytebuffer.each { |byte| bytes << byte }
277
- expect(bytes).to eq example_string.bytes
278
- end
279
- end
280
-
281
- describe "#inspect" do
282
- it "inspects the buffer offsets" do
283
- regex = /\A#<NIO::ByteBuffer:.*? @position=0 @limit=#{capacity} @capacity=#{capacity}>\z/
284
- expect(bytebuffer.inspect).to match(regex)
285
- end
286
- end
287
-
288
- context "I/O" do
289
- let(:addr) { "127.0.0.1" }
290
- let(:server) { TCPServer.new(addr, 0) }
291
- let(:port) { server.local_address.ip_port }
292
- let(:client) { TCPSocket.new(addr, port) }
293
- let(:peer) { server_thread.value }
294
-
295
- let(:server_thread) do
296
- server
297
-
298
- thread = Thread.new { server.accept }
299
- Thread.pass while thread.status && thread.status != "sleep"
300
-
301
- thread
302
- end
303
-
304
- before do
305
- server_thread
306
- client
307
- end
308
-
309
- after do
310
- server_thread.kill if server_thread.alive?
311
-
312
- server.close rescue nil
313
- client.close rescue nil
314
- peer.close rescue nil
315
- end
316
-
317
- describe "#read_from" do
318
- it "reads data into the buffer" do
319
- client.write(example_string)
320
- expect(bytebuffer.read_from(peer)).to eq example_string.length
321
- bytebuffer.flip
322
-
323
- expect(bytebuffer.get).to eq example_string
324
- end
325
-
326
- it "raises NIO::ByteBuffer::OverflowError if the buffer is already full" do
327
- client.write(example_string)
328
- bytebuffer << "X" * capacity
329
- expect { bytebuffer.read_from(peer) }.to raise_error(NIO::ByteBuffer::OverflowError)
330
- end
331
-
332
- it "returns 0 if no data is available" do
333
- expect(bytebuffer.read_from(peer)).to eq 0
334
- end
335
- end
336
-
337
- describe "#write_to" do
338
- it "writes data from the buffer" do
339
- bytebuffer << example_string
340
- bytebuffer.flip
341
-
342
- expect(bytebuffer.write_to(client)).to eq example_string.length
343
- client.close
344
-
345
- expect(peer.read(example_string.length)).to eq example_string
346
- end
347
-
348
- it "raises NIO::ByteBuffer::UnderflowError if the buffer is out of data" do
349
- bytebuffer.flip
350
- expect { bytebuffer.write_to(peer) }.to raise_error(NIO::ByteBuffer::UnderflowError)
351
- end
352
- end
353
- end
354
- end
@@ -1,162 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "spec_helper"
4
- require "socket"
5
-
6
- RSpec.describe NIO::Monitor do
7
- let(:addr) { "127.0.0.1" }
8
-
9
- let(:reader) { TCPServer.new(addr, 0) }
10
- let(:port) { reader.local_address.ip_port }
11
- let(:writer) { TCPSocket.new(addr, port) }
12
-
13
- let(:selector) { NIO::Selector.new }
14
-
15
- subject(:monitor) { selector.register(writer, :rw) }
16
- subject(:peer) { selector.register(reader, :r) }
17
-
18
- before { reader }
19
- before { writer }
20
- after { reader.close }
21
- after { writer.close }
22
- after { selector.close }
23
-
24
- describe "#interests" do
25
- it "knows its interests" do
26
- expect(peer.interests).to eq(:r)
27
- expect(monitor.interests).to eq(:rw)
28
- end
29
- end
30
-
31
- describe "#interests=" do
32
- it "can set interests to nil" do
33
- expect(monitor.interests).not_to eq(nil)
34
- monitor.interests = nil
35
- expect(monitor.interests).to eq(nil)
36
- end
37
-
38
- it "changes the interest set" do
39
- expect(monitor.interests).not_to eq(:w)
40
- monitor.interests = :w
41
- expect(monitor.interests).to eq(:w)
42
- end
43
-
44
- it "raises EOFError if interests are changed after the monitor is closed" do
45
- monitor.close
46
- expect { monitor.interests = :rw }.to raise_error(EOFError)
47
- end
48
- end
49
-
50
- describe "#add_interest" do
51
- it "sets a new interest if it isn't currently registered" do
52
- monitor.interests = :r
53
- expect(monitor.interests).to eq(:r)
54
-
55
- expect(monitor.add_interest(:w)).to eq(:rw)
56
- expect(monitor.interests).to eq(:rw)
57
- end
58
-
59
- it "acts idempotently" do
60
- monitor.interests = :r
61
- expect(monitor.interests).to eq(:r)
62
-
63
- expect(monitor.add_interest(:r)).to eq(:r)
64
- expect(monitor.interests).to eq(:r)
65
- end
66
-
67
- it "raises ArgumentError if given a bogus option" do
68
- expect { monitor.add_interest(:derp) }.to raise_error(ArgumentError)
69
- end
70
- end
71
-
72
- describe "#remove_interest" do
73
- it "removes an interest from the set" do
74
- expect(monitor.interests).to eq(:rw)
75
-
76
- expect(monitor.remove_interest(:r)).to eq(:w)
77
- expect(monitor.interests).to eq(:w)
78
- end
79
-
80
- it "can clear the last interest" do
81
- monitor.interests = :w
82
- expect(monitor.interests).to eq(:w)
83
-
84
- expect(monitor.remove_interest(:w)).to be_nil
85
- expect(monitor.interests).to be_nil
86
- end
87
-
88
- it "acts idempotently" do
89
- monitor.interests = :w
90
- expect(monitor.interests).to eq(:w)
91
-
92
- expect(monitor.remove_interest(:r)).to eq(:w)
93
- expect(monitor.interests).to eq(:w)
94
- end
95
-
96
- it "raises ArgumentError if given a bogus option" do
97
- expect { monitor.add_interest(:derp) }.to raise_error(ArgumentError)
98
- end
99
- end
100
-
101
- describe "#io" do
102
- it "knows its IO object" do
103
- expect(monitor.io).to eq(writer)
104
- end
105
- end
106
-
107
- describe "#selector" do
108
- it "knows its selector" do
109
- expect(monitor.selector).to eq(selector)
110
- end
111
- end
112
-
113
- describe "#value=" do
114
- it "stores arbitrary values" do
115
- monitor.value = 42
116
- expect(monitor.value).to eq(42)
117
- end
118
- end
119
-
120
- describe "#readiness" do
121
- it "knows what operations IO objects are ready for" do
122
- # For whatever odd reason this breaks unless we eagerly evaluate monitor
123
- reader_peer = peer
124
- writer_peer = monitor
125
-
126
- selected = selector.select(0)
127
- expect(selected).to include(writer_peer)
128
-
129
- expect(writer_peer.readiness).to eq(:w)
130
- expect(writer_peer).not_to be_readable
131
- expect(writer_peer).to be_writable
132
-
133
- writer << "testing 1 2 3"
134
-
135
- selected = selector.select(0)
136
- expect(selected).to include(reader_peer)
137
-
138
- expect(reader_peer.readiness).to eq(:r)
139
- expect(reader_peer).to be_readable
140
- expect(reader_peer).not_to be_writable
141
- end
142
- end
143
-
144
- describe "#close" do
145
- it "closes" do
146
- expect(monitor).not_to be_closed
147
- expect(selector.registered?(writer)).to be_truthy
148
-
149
- monitor.close
150
- expect(monitor).to be_closed
151
- expect(selector.registered?(writer)).to be_falsey
152
- end
153
-
154
- it "closes even if the selector has been shutdown" do
155
- expect(monitor).not_to be_closed
156
- selector.close # forces shutdown
157
- expect(monitor).not_to be_closed
158
- monitor.close
159
- expect(monitor).to be_closed
160
- end
161
- end
162
- end
@@ -1,47 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "spec_helper"
4
-
5
- RSpec.describe "IO.pipe" do
6
- let(:pair) { IO.pipe }
7
-
8
- let :unreadable_subject do
9
- pair.first
10
- end
11
-
12
- let :readable_subject do
13
- pipe, peer = pair
14
- peer << "data"
15
- pipe
16
- end
17
-
18
- let :writable_subject do
19
- pair.last
20
- end
21
-
22
- let :unwritable_subject do
23
- _reader, pipe = pair
24
-
25
- # HACK: On OS X 10.8, this str must be larger than PIPE_BUF. Otherwise,
26
- # the write is atomic and select() will return writable but write()
27
- # will throw EAGAIN if there is too little space to write the string
28
- # TODO: Use FFI to lookup the platform-specific size of PIPE_BUF
29
- str = "JUNK IN THE TUBES" * 10_000
30
- cntr = 0
31
- begin
32
- pipe.write_nonblock str
33
- cntr += 1
34
- t = select [], [pipe], [], 0
35
- rescue Errno::EPIPE
36
- break
37
- rescue IO::EWOULDBLOCKWaitWritable
38
- skip "windows - can't test due to 'select' not showing correct status"
39
- break
40
- end while t && t[1].include?(pipe) && cntr < 20
41
-
42
- pipe
43
- end
44
-
45
- it_behaves_like "an NIO selectable"
46
- it_behaves_like "an NIO selectable stream"
47
- end