nio4r 2.5.8 → 2.7.4

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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/{CHANGES.md → changes.md} +48 -0
  4. data/ext/nio4r/bytebuffer.c +75 -38
  5. data/ext/nio4r/extconf.rb +19 -1
  6. data/ext/nio4r/monitor.c +47 -22
  7. data/ext/nio4r/nio4r.h +1 -5
  8. data/ext/nio4r/nio4r_ext.c +4 -0
  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 +3 -0
  22. metadata +96 -75
  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 -18
  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