nio4r 0.2.0 → 2.7.5

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 (60) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/ext/libev/Changes +232 -3
  4. data/ext/libev/LICENSE +2 -1
  5. data/ext/libev/README +11 -10
  6. data/ext/libev/ev.c +2249 -473
  7. data/ext/libev/ev.h +165 -135
  8. data/ext/libev/ev_epoll.c +68 -36
  9. data/ext/libev/ev_iouring.c +694 -0
  10. data/ext/libev/ev_kqueue.c +44 -18
  11. data/ext/libev/ev_linuxaio.c +620 -0
  12. data/ext/libev/ev_poll.c +28 -20
  13. data/ext/libev/ev_port.c +23 -10
  14. data/ext/libev/ev_select.c +18 -12
  15. data/ext/libev/ev_vars.h +65 -19
  16. data/ext/libev/ev_win32.c +16 -7
  17. data/ext/libev/ev_wrap.h +236 -160
  18. data/ext/nio4r/.clang-format +16 -0
  19. data/ext/nio4r/bytebuffer.c +465 -0
  20. data/ext/nio4r/extconf.rb +44 -35
  21. data/ext/nio4r/libev.h +3 -4
  22. data/ext/nio4r/monitor.c +186 -54
  23. data/ext/nio4r/nio4r.h +17 -23
  24. data/ext/nio4r/nio4r_ext.c +11 -3
  25. data/ext/nio4r/org/nio4r/ByteBuffer.java +295 -0
  26. data/ext/nio4r/org/nio4r/Monitor.java +176 -0
  27. data/ext/nio4r/org/nio4r/Nio4r.java +104 -0
  28. data/ext/nio4r/org/nio4r/Selector.java +297 -0
  29. data/ext/nio4r/selector.c +350 -182
  30. data/lib/nio/bytebuffer.rb +235 -0
  31. data/lib/nio/monitor.rb +100 -8
  32. data/lib/nio/selector.rb +110 -44
  33. data/lib/nio/version.rb +8 -1
  34. data/lib/nio.rb +47 -16
  35. data/lib/nio4r.rb +7 -0
  36. data/license.md +80 -0
  37. data/readme.md +91 -0
  38. data/releases.md +343 -0
  39. data.tar.gz.sig +2 -0
  40. metadata +114 -79
  41. metadata.gz.sig +0 -0
  42. data/.gitignore +0 -20
  43. data/.rspec +0 -4
  44. data/.travis.yml +0 -7
  45. data/CHANGES.md +0 -10
  46. data/Gemfile +0 -4
  47. data/LICENSE.txt +0 -20
  48. data/README.md +0 -171
  49. data/Rakefile +0 -9
  50. data/examples/echo_server.rb +0 -38
  51. data/ext/libev/README.embed +0 -3
  52. data/ext/libev/test_libev_win32.c +0 -123
  53. data/lib/nio/jruby/monitor.rb +0 -42
  54. data/lib/nio/jruby/selector.rb +0 -135
  55. data/nio4r.gemspec +0 -22
  56. data/spec/nio/monitor_spec.rb +0 -46
  57. data/spec/nio/selector_spec.rb +0 -269
  58. data/spec/spec_helper.rb +0 -3
  59. data/tasks/extension.rake +0 -10
  60. data/tasks/rspec.rake +0 -7
@@ -0,0 +1,295 @@
1
+ package org.nio4r;
2
+
3
+ import java.io.IOException;
4
+ import java.io.Serializable;
5
+ import java.nio.channels.Channel;
6
+ import java.nio.channels.SelectableChannel;
7
+ import java.nio.channels.ReadableByteChannel;
8
+ import java.nio.channels.WritableByteChannel;
9
+ import java.nio.BufferOverflowException;
10
+ import java.nio.BufferUnderflowException;
11
+ import java.nio.InvalidMarkException;
12
+
13
+ import org.jruby.Ruby;
14
+ import org.jruby.RubyClass;
15
+ import org.jruby.RubyIO;
16
+ import org.jruby.RubyNumeric;
17
+ import org.jruby.RubyObject;
18
+ import org.jruby.RubyString;
19
+ import org.jruby.anno.JRubyMethod;
20
+ import org.jruby.exceptions.RaiseException;
21
+ import org.jruby.runtime.ThreadContext;
22
+ import org.jruby.runtime.builtin.IRubyObject;
23
+ import org.jruby.runtime.Block;
24
+
25
+ /*
26
+ created by Upekshej
27
+ */
28
+ public class ByteBuffer extends RubyObject {
29
+ private static final long serialVersionUID = -6903439483039149324L;
30
+ private transient java.nio.ByteBuffer byteBuffer;
31
+
32
+ public static RaiseException newOverflowError(ThreadContext context, String message) {
33
+ RubyClass klass = context.runtime.getModule("NIO").getClass("ByteBuffer").getClass("OverflowError");
34
+ return context.runtime.newRaiseException(klass, message);
35
+ }
36
+
37
+ public static RaiseException newUnderflowError(ThreadContext context, String message) {
38
+ RubyClass klass = context.runtime.getModule("NIO").getClass("ByteBuffer").getClass("UnderflowError");
39
+ return context.runtime.newRaiseException(klass, message);
40
+ }
41
+
42
+ public static RaiseException newMarkUnsetError(ThreadContext context, String message) {
43
+ RubyClass klass = context.runtime.getModule("NIO").getClass("ByteBuffer").getClass("MarkUnsetError");
44
+ return context.runtime.newRaiseException(klass, message);
45
+ }
46
+
47
+ public ByteBuffer(final Ruby ruby, RubyClass rubyClass) {
48
+ super(ruby, rubyClass);
49
+ }
50
+
51
+ @JRubyMethod
52
+ public IRubyObject initialize(ThreadContext context, IRubyObject capacity) {
53
+ this.byteBuffer = java.nio.ByteBuffer.allocate(RubyNumeric.num2int(capacity));
54
+ return this;
55
+ }
56
+
57
+ @JRubyMethod
58
+ public IRubyObject clear(ThreadContext context) {
59
+ this.byteBuffer.clear();
60
+ return this;
61
+ }
62
+
63
+ @JRubyMethod(name = "position")
64
+ public IRubyObject getPosition(ThreadContext context) {
65
+ return context.getRuntime().newFixnum(this.byteBuffer.position());
66
+ }
67
+
68
+ @JRubyMethod(name = "position=")
69
+ public IRubyObject setPosition(ThreadContext context, IRubyObject newPosition) {
70
+ int pos = RubyNumeric.num2int(newPosition);
71
+
72
+ if(pos < 0) {
73
+ throw context.runtime.newArgumentError("negative position given");
74
+ }
75
+
76
+ if(pos > this.byteBuffer.limit()) {
77
+ throw context.runtime.newArgumentError("specified position exceeds limit");
78
+ }
79
+
80
+ try {
81
+ this.byteBuffer.position(pos);
82
+ return newPosition;
83
+ } catch(IllegalArgumentException e) {
84
+ throw context.runtime.newArgumentError(e.getLocalizedMessage());
85
+ }
86
+ }
87
+
88
+ @JRubyMethod(name = "limit")
89
+ public IRubyObject getLimit(ThreadContext context) {
90
+ return context.getRuntime().newFixnum(this.byteBuffer.limit());
91
+ }
92
+
93
+ @JRubyMethod(name = "limit=")
94
+ public IRubyObject setLimit(ThreadContext context, IRubyObject newLimit) {
95
+ int lim = RubyNumeric.num2int(newLimit);
96
+
97
+ if(lim < 0) {
98
+ throw context.runtime.newArgumentError("negative limit given");
99
+ }
100
+
101
+ if(lim > this.byteBuffer.capacity()) {
102
+ throw context.runtime.newArgumentError("specified limit exceeds capacity");
103
+ }
104
+
105
+ try {
106
+ this.byteBuffer.limit(lim);
107
+ return newLimit;
108
+ } catch(IllegalArgumentException e) {
109
+ throw context.runtime.newArgumentError(e.getLocalizedMessage());
110
+ }
111
+ }
112
+
113
+ @JRubyMethod(name = {"capacity", "size"})
114
+ public IRubyObject capacity(ThreadContext context) {
115
+ return context.getRuntime().newFixnum(this.byteBuffer.capacity());
116
+ }
117
+
118
+ @JRubyMethod
119
+ public IRubyObject remaining(ThreadContext context) {
120
+ return context.getRuntime().newFixnum(this.byteBuffer.remaining());
121
+ }
122
+
123
+ @JRubyMethod(name = "full?")
124
+ public IRubyObject isFull(ThreadContext context) {
125
+ if (this.byteBuffer.hasRemaining()) {
126
+ return context.getRuntime().getFalse();
127
+ } else {
128
+ return context.getRuntime().getTrue();
129
+ }
130
+ }
131
+
132
+ @JRubyMethod
133
+ public IRubyObject get(ThreadContext context) {
134
+ return this.get(context, context.getRuntime().newFixnum(this.byteBuffer.remaining()));
135
+ }
136
+
137
+ @JRubyMethod
138
+ public IRubyObject get(ThreadContext context, IRubyObject length) {
139
+ int len = RubyNumeric.num2int(length);
140
+ byte[] bytes = new byte[len];
141
+
142
+ try {
143
+ this.byteBuffer.get(bytes);
144
+ } catch(BufferUnderflowException e) {
145
+ throw ByteBuffer.newUnderflowError(context, "not enough data in buffer");
146
+ }
147
+
148
+ return RubyString.newString(context.getRuntime(), bytes);
149
+ }
150
+
151
+ @JRubyMethod(name = "[]")
152
+ public IRubyObject fetch(ThreadContext context, IRubyObject index) {
153
+ int i = RubyNumeric.num2int(index);
154
+
155
+ if(i < 0) {
156
+ throw context.runtime.newArgumentError("negative index given");
157
+ }
158
+
159
+ if(i >= this.byteBuffer.limit()) {
160
+ throw context.runtime.newArgumentError("index exceeds limit");
161
+ }
162
+
163
+ return context.getRuntime().newFixnum(this.byteBuffer.get(i));
164
+ }
165
+
166
+ @JRubyMethod(name = "<<")
167
+ public IRubyObject put(ThreadContext context, IRubyObject str) {
168
+ try {
169
+ this.byteBuffer.put(str.convertToString().getByteList().bytes());
170
+ } catch(BufferOverflowException e) {
171
+ throw ByteBuffer.newOverflowError(context, "buffer is full");
172
+ }
173
+
174
+ return this;
175
+ }
176
+
177
+ @JRubyMethod(name = "read_from")
178
+ public IRubyObject readFrom(ThreadContext context, IRubyObject io) {
179
+ Ruby runtime = context.runtime;
180
+ Channel channel = RubyIO.convertToIO(context, io).getChannel();
181
+
182
+ if(!this.byteBuffer.hasRemaining()) {
183
+ throw ByteBuffer.newOverflowError(context, "buffer is full");
184
+ }
185
+
186
+ if(!(channel instanceof ReadableByteChannel) || !(channel instanceof SelectableChannel)) {
187
+ throw runtime.newArgumentError("unsupported IO object: " + io.getType().toString());
188
+ }
189
+
190
+ try {
191
+ ((SelectableChannel)channel).configureBlocking(false);
192
+ } catch(IOException ie) {
193
+ throw runtime.newIOError(ie.getLocalizedMessage());
194
+ }
195
+
196
+ try {
197
+ int bytesRead = ((ReadableByteChannel)channel).read(this.byteBuffer);
198
+
199
+ if(bytesRead >= 0) {
200
+ return runtime.newFixnum(bytesRead);
201
+ } else {
202
+ throw runtime.newEOFError();
203
+ }
204
+ } catch(IOException ie) {
205
+ throw runtime.newIOError(ie.getLocalizedMessage());
206
+ }
207
+ }
208
+
209
+ @JRubyMethod(name = "write_to")
210
+ public IRubyObject writeTo(ThreadContext context, IRubyObject io) {
211
+ Ruby runtime = context.runtime;
212
+ Channel channel = RubyIO.convertToIO(context, io).getChannel();
213
+
214
+ if(!this.byteBuffer.hasRemaining()) {
215
+ throw ByteBuffer.newUnderflowError(context, "not enough data in buffer");
216
+ }
217
+
218
+ if(!(channel instanceof WritableByteChannel) || !(channel instanceof SelectableChannel)) {
219
+ throw runtime.newArgumentError("unsupported IO object: " + io.getType().toString());
220
+ }
221
+
222
+ try {
223
+ ((SelectableChannel)channel).configureBlocking(false);
224
+ } catch(IOException ie) {
225
+ throw runtime.newIOError(ie.getLocalizedMessage());
226
+ }
227
+
228
+ try {
229
+ int bytesWritten = ((WritableByteChannel)channel).write(this.byteBuffer);
230
+
231
+ if(bytesWritten >= 0) {
232
+ return runtime.newFixnum(bytesWritten);
233
+ } else {
234
+ throw runtime.newEOFError();
235
+ }
236
+ } catch(IOException ie) {
237
+ throw runtime.newIOError(ie.getLocalizedMessage());
238
+ }
239
+ }
240
+
241
+ @JRubyMethod
242
+ public IRubyObject flip(ThreadContext context) {
243
+ this.byteBuffer.flip();
244
+ return this;
245
+ }
246
+
247
+ @JRubyMethod
248
+ public IRubyObject rewind(ThreadContext context) {
249
+ this.byteBuffer.rewind();
250
+ return this;
251
+ }
252
+
253
+ @JRubyMethod
254
+ public IRubyObject mark(ThreadContext context) {
255
+ this.byteBuffer.mark();
256
+ return this;
257
+ }
258
+
259
+ @JRubyMethod
260
+ public IRubyObject reset(ThreadContext context) {
261
+ try {
262
+ this.byteBuffer.reset();
263
+ return this;
264
+ } catch(InvalidMarkException ie) {
265
+ throw ByteBuffer.newMarkUnsetError(context, "mark has not been set");
266
+ }
267
+ }
268
+
269
+ @JRubyMethod
270
+ public IRubyObject compact(ThreadContext context) {
271
+ this.byteBuffer.compact();
272
+ return this;
273
+ }
274
+
275
+ @JRubyMethod
276
+ public IRubyObject each(ThreadContext context, Block block) {
277
+ for(int i = 0; i < this.byteBuffer.limit(); i++) {
278
+ block.call(context, context.getRuntime().newFixnum(this.byteBuffer.get(i)));
279
+ }
280
+
281
+ return this;
282
+ }
283
+
284
+ @JRubyMethod
285
+ public IRubyObject inspect(ThreadContext context) {
286
+ return context.runtime.newString(String.format(
287
+ "#<%s:0x%x @position=%d @limit=%d @capacity=%d>",
288
+ this.getType().toString(),
289
+ System.identityHashCode(this),
290
+ this.byteBuffer.position(),
291
+ this.byteBuffer.limit(),
292
+ this.byteBuffer.capacity()
293
+ ));
294
+ }
295
+ }
@@ -0,0 +1,176 @@
1
+ package org.nio4r;
2
+
3
+ import java.nio.channels.Channel;
4
+ import java.nio.channels.SelectableChannel;
5
+ import java.nio.channels.SelectionKey;
6
+
7
+ import org.jruby.Ruby;
8
+ import org.jruby.RubyClass;
9
+ import org.jruby.RubyIO;
10
+ import org.jruby.RubyObject;
11
+ import org.jruby.anno.JRubyMethod;
12
+ import org.jruby.runtime.ThreadContext;
13
+ import org.jruby.runtime.builtin.IRubyObject;
14
+
15
+ public class Monitor extends RubyObject {
16
+ private static final long serialVersionUID = -3733782997115074794L;
17
+ private transient SelectionKey key;
18
+ private RubyIO io;
19
+ private transient IRubyObject interests, selector, value, closed;
20
+
21
+ public Monitor(final Ruby ruby, RubyClass rubyClass) {
22
+ super(ruby, rubyClass);
23
+ }
24
+
25
+ @JRubyMethod
26
+ public IRubyObject initialize(ThreadContext context, IRubyObject selectable, IRubyObject interests, IRubyObject selector) {
27
+ this.io = RubyIO.convertToIO(context, selectable);
28
+ this.interests = interests;
29
+ this.selector = selector;
30
+
31
+ this.value = context.nil;
32
+ this.closed = context.getRuntime().getFalse();
33
+
34
+ return context.nil;
35
+ }
36
+
37
+ public void setSelectionKey(SelectionKey key) {
38
+ this.key = key;
39
+ key.attach(this);
40
+ }
41
+
42
+ @JRubyMethod
43
+ public IRubyObject io(ThreadContext context) {
44
+ return io;
45
+ }
46
+
47
+ @JRubyMethod
48
+ public IRubyObject selector(ThreadContext context) {
49
+ return selector;
50
+ }
51
+
52
+ @JRubyMethod(name = "interests")
53
+ public IRubyObject getInterests(ThreadContext context) {
54
+ return interests;
55
+ }
56
+
57
+ @JRubyMethod(name = "interests=")
58
+ public IRubyObject setInterests(ThreadContext context, IRubyObject interests) {
59
+ if(this.closed == context.getRuntime().getTrue()) {
60
+ throw context.getRuntime().newEOFError("monitor is closed");
61
+ }
62
+
63
+ Ruby ruby = context.getRuntime();
64
+ SelectableChannel channel = (SelectableChannel)io.getChannel();
65
+
66
+ if(interests != context.nil) {
67
+ key.interestOps(Nio4r.symbolToInterestOps(ruby, channel, interests));
68
+ } else {
69
+ key.interestOps(0);
70
+ }
71
+
72
+ this.interests = interests;
73
+
74
+ return this.interests;
75
+ }
76
+
77
+ @JRubyMethod(name = "add_interest")
78
+ public IRubyObject addInterest(ThreadContext context, IRubyObject interest) {
79
+ if(this.closed == context.getRuntime().getTrue()) {
80
+ throw context.getRuntime().newEOFError("monitor is closed");
81
+ }
82
+
83
+ Ruby ruby = context.getRuntime();
84
+ SelectableChannel channel = (SelectableChannel)io.getChannel();
85
+ int newInterestOps = key.interestOps() | Nio4r.symbolToInterestOps(ruby, channel, interest);
86
+
87
+ key.interestOps(newInterestOps);
88
+ this.interests = Nio4r.interestOpsToSymbol(ruby, newInterestOps);
89
+
90
+ return this.interests;
91
+ }
92
+
93
+ @JRubyMethod(name = "remove_interest")
94
+ public IRubyObject removeInterest(ThreadContext context, IRubyObject interest) {
95
+ if(this.closed == context.getRuntime().getTrue()) {
96
+ throw context.getRuntime().newEOFError("monitor is closed");
97
+ }
98
+
99
+ Ruby ruby = context.getRuntime();
100
+ SelectableChannel channel = (SelectableChannel)io.getChannel();
101
+ int newInterestOps = key.interestOps() & ~Nio4r.symbolToInterestOps(ruby, channel, interest);
102
+
103
+ key.interestOps(newInterestOps);
104
+ this.interests = Nio4r.interestOpsToSymbol(ruby, newInterestOps);
105
+
106
+ return this.interests;
107
+ }
108
+
109
+ @JRubyMethod
110
+ public IRubyObject readiness(ThreadContext context) {
111
+ if(!key.isValid())
112
+ return this.interests;
113
+ return Nio4r.interestOpsToSymbol(context.getRuntime(), key.readyOps());
114
+ }
115
+
116
+ @JRubyMethod(name = "readable?")
117
+ public IRubyObject isReadable(ThreadContext context) {
118
+ Ruby runtime = context.getRuntime();
119
+ if (!this.key.isValid())
120
+ return runtime.getTrue();
121
+ int readyOps = this.key.readyOps();
122
+
123
+ if((readyOps & SelectionKey.OP_READ) != 0 || (readyOps & SelectionKey.OP_ACCEPT) != 0) {
124
+ return runtime.getTrue();
125
+ } else {
126
+ return runtime.getFalse();
127
+ }
128
+ }
129
+
130
+ @JRubyMethod(name = {"writable?", "writeable?"})
131
+ public IRubyObject writable(ThreadContext context) {
132
+ Ruby runtime = context.getRuntime();
133
+ if (!this.key.isValid())
134
+ return runtime.getTrue();
135
+ int readyOps = this.key.readyOps();
136
+
137
+ if((readyOps & SelectionKey.OP_WRITE) != 0 || (readyOps & SelectionKey.OP_CONNECT) != 0) {
138
+ return runtime.getTrue();
139
+ } else {
140
+ return runtime.getFalse();
141
+ }
142
+ }
143
+
144
+ @JRubyMethod(name = "value")
145
+ public IRubyObject getValue(ThreadContext context) {
146
+ return this.value;
147
+ }
148
+
149
+ @JRubyMethod(name = "value=")
150
+ public IRubyObject setValue(ThreadContext context, IRubyObject obj) {
151
+ this.value = obj;
152
+ return context.nil;
153
+ }
154
+
155
+ @JRubyMethod
156
+ public IRubyObject close(ThreadContext context) {
157
+ return close(context, context.getRuntime().getTrue());
158
+ }
159
+
160
+ @JRubyMethod
161
+ public IRubyObject close(ThreadContext context, IRubyObject deregister) {
162
+ Ruby runtime = context.getRuntime();
163
+ this.closed = runtime.getTrue();
164
+
165
+ if(deregister == runtime.getTrue()) {
166
+ selector.callMethod(context, "deregister", io);
167
+ }
168
+
169
+ return context.nil;
170
+ }
171
+
172
+ @JRubyMethod(name = "closed?")
173
+ public IRubyObject isClosed(ThreadContext context) {
174
+ return this.closed;
175
+ }
176
+ }
@@ -0,0 +1,104 @@
1
+ package org.nio4r;
2
+
3
+ import java.nio.channels.SelectableChannel;
4
+ import java.nio.channels.SelectionKey;
5
+ import java.nio.channels.SocketChannel;
6
+
7
+ import org.jruby.Ruby;
8
+ import org.jruby.RubyClass;
9
+ import org.jruby.RubyModule;
10
+ import org.jruby.runtime.ObjectAllocator;
11
+ import org.jruby.runtime.load.Library;
12
+ import org.jruby.runtime.builtin.IRubyObject;
13
+
14
+ import org.nio4r.ByteBuffer;
15
+ import org.nio4r.Monitor;
16
+ import org.nio4r.Selector;
17
+
18
+ public class Nio4r implements Library {
19
+ private Ruby ruby;
20
+
21
+ public void load(final Ruby ruby, boolean bln) {
22
+ this.ruby = ruby;
23
+
24
+ RubyModule nio = ruby.defineModule("NIO");
25
+
26
+ RubyClass selector = ruby.defineClassUnder("Selector", ruby.getObject(), new ObjectAllocator() {
27
+ public IRubyObject allocate(Ruby ruby, RubyClass rc) {
28
+ return new Selector(ruby, rc);
29
+ }
30
+ }, nio);
31
+
32
+ selector.defineAnnotatedMethods(Selector.class);
33
+
34
+ RubyClass monitor = ruby.defineClassUnder("Monitor", ruby.getObject(), new ObjectAllocator() {
35
+ public IRubyObject allocate(Ruby ruby, RubyClass rc) {
36
+ return new Monitor(ruby, rc);
37
+ }
38
+ }, nio);
39
+
40
+ monitor.defineAnnotatedMethods(Monitor.class);
41
+
42
+ RubyClass byteBuffer = ruby.defineClassUnder("ByteBuffer", ruby.getObject(), new ObjectAllocator() {
43
+ public IRubyObject allocate(Ruby ruby, RubyClass rc) {
44
+ return new ByteBuffer(ruby, rc);
45
+ }
46
+ }, nio);
47
+
48
+ byteBuffer.defineAnnotatedMethods(ByteBuffer.class);
49
+ byteBuffer.includeModule(ruby.getEnumerable());
50
+
51
+ ruby.defineClassUnder("OverflowError", ruby.getIOError(), ruby.getIOError().getAllocator(), byteBuffer);
52
+ ruby.defineClassUnder("UnderflowError", ruby.getIOError(), ruby.getIOError().getAllocator(), byteBuffer);
53
+ ruby.defineClassUnder("MarkUnsetError", ruby.getIOError(), ruby.getIOError().getAllocator(), byteBuffer);
54
+ }
55
+
56
+ public static int symbolToInterestOps(Ruby ruby, SelectableChannel channel, IRubyObject interest) {
57
+ if(interest == ruby.newSymbol("r")) {
58
+ if((channel.validOps() & SelectionKey.OP_ACCEPT) != 0) {
59
+ return SelectionKey.OP_ACCEPT;
60
+ } else {
61
+ return SelectionKey.OP_READ;
62
+ }
63
+ } else if(interest == ruby.newSymbol("w")) {
64
+ if(channel instanceof SocketChannel && !((SocketChannel)channel).isConnected()) {
65
+ return SelectionKey.OP_CONNECT;
66
+ } else {
67
+ return SelectionKey.OP_WRITE;
68
+ }
69
+ } else if(interest == ruby.newSymbol("rw")) {
70
+ int interestOps = 0;
71
+
72
+ /* nio4r emulates the POSIX behavior, which is sloppy about allowed modes */
73
+ if((channel.validOps() & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0) {
74
+ interestOps |= symbolToInterestOps(ruby, channel, ruby.newSymbol("r"));
75
+ }
76
+
77
+ if((channel.validOps() & (SelectionKey.OP_WRITE | SelectionKey.OP_CONNECT)) != 0) {
78
+ interestOps |= symbolToInterestOps(ruby, channel, ruby.newSymbol("w"));
79
+ }
80
+
81
+ return interestOps;
82
+ } else {
83
+ throw ruby.newArgumentError("invalid interest type: " + interest);
84
+ }
85
+ }
86
+
87
+ public static IRubyObject interestOpsToSymbol(Ruby ruby, int interestOps) {
88
+ switch(interestOps) {
89
+ case SelectionKey.OP_READ:
90
+ case SelectionKey.OP_ACCEPT:
91
+ return ruby.newSymbol("r");
92
+ case SelectionKey.OP_WRITE:
93
+ case SelectionKey.OP_CONNECT:
94
+ return ruby.newSymbol("w");
95
+ case SelectionKey.OP_READ | SelectionKey.OP_CONNECT:
96
+ case SelectionKey.OP_READ | SelectionKey.OP_WRITE:
97
+ return ruby.newSymbol("rw");
98
+ case 0:
99
+ return ruby.getNil();
100
+ default:
101
+ throw ruby.newArgumentError("unknown interest op combination");
102
+ }
103
+ }
104
+ }