nio4r 1.2.1-java → 2.0.0-java

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +0 -1
  3. data/.rubocop.yml +31 -38
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +15 -14
  6. data/CHANGES.md +75 -42
  7. data/Gemfile +10 -5
  8. data/Guardfile +10 -0
  9. data/LICENSE.txt +1 -1
  10. data/README.md +57 -161
  11. data/Rakefile +2 -1
  12. data/examples/echo_server.rb +1 -0
  13. data/ext/libev/Changes +4 -13
  14. data/ext/libev/ev.c +101 -74
  15. data/ext/libev/ev.h +3 -3
  16. data/ext/libev/ev_epoll.c +6 -3
  17. data/ext/libev/ev_kqueue.c +8 -4
  18. data/ext/libev/ev_poll.c +6 -3
  19. data/ext/libev/ev_port.c +8 -4
  20. data/ext/libev/ev_select.c +4 -2
  21. data/ext/nio4r/bytebuffer.c +421 -0
  22. data/ext/nio4r/extconf.rb +2 -10
  23. data/ext/nio4r/monitor.c +93 -46
  24. data/ext/nio4r/nio4r.h +11 -13
  25. data/ext/nio4r/org/nio4r/ByteBuffer.java +295 -0
  26. data/ext/nio4r/org/nio4r/Monitor.java +164 -0
  27. data/ext/nio4r/org/nio4r/Nio4r.java +22 -391
  28. data/ext/nio4r/org/nio4r/Selector.java +278 -0
  29. data/ext/nio4r/selector.c +55 -53
  30. data/lib/nio.rb +4 -3
  31. data/lib/nio/bytebuffer.rb +222 -0
  32. data/lib/nio/monitor.rb +64 -4
  33. data/lib/nio/selector.rb +52 -20
  34. data/lib/nio/version.rb +1 -1
  35. data/nio4r.gemspec +25 -19
  36. data/spec/nio/acceptables_spec.rb +6 -4
  37. data/spec/nio/bytebuffer_spec.rb +349 -0
  38. data/spec/nio/monitor_spec.rb +122 -79
  39. data/spec/nio/selectables/pipe_spec.rb +5 -1
  40. data/spec/nio/selectables/ssl_socket_spec.rb +15 -12
  41. data/spec/nio/selectables/tcp_socket_spec.rb +42 -31
  42. data/spec/nio/selectables/udp_socket_spec.rb +2 -0
  43. data/spec/nio/selector_spec.rb +10 -4
  44. data/spec/spec_helper.rb +24 -3
  45. data/spec/support/selectable_examples.rb +7 -5
  46. data/tasks/extension.rake +2 -0
  47. data/tasks/rspec.rake +2 -0
  48. data/tasks/rubocop.rake +2 -0
  49. metadata +21 -14
  50. data/.rubocop_todo.yml +0 -35
data/ext/nio4r/extconf.rb CHANGED
@@ -1,15 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "mkmf"
2
4
 
3
5
  have_header("unistd.h")
4
6
 
5
- if have_func("rb_thread_blocking_region")
6
- $defs << "-DHAVE_RB_THREAD_BLOCKING_REGION"
7
- end
8
-
9
- if have_func("rb_thread_call_without_gvl")
10
- $defs << "-DHAVE_RB_THEREAD_CALL_WITHOUT_GVL"
11
- end
12
-
13
7
  $defs << "-DEV_USE_SELECT" if have_header("sys/select.h")
14
8
 
15
9
  $defs << "-DEV_USE_POLL" if have_header("poll.h")
@@ -24,8 +18,6 @@ $defs << "-DEV_USE_PORT" if have_header("port.h")
24
18
 
25
19
  $defs << "-DHAVE_SYS_RESOURCE_H" if have_header("sys/resource.h")
26
20
 
27
- $defs << "-DHAVE_RUBYSIG_H" if RUBY_VERSION.to_f < 1.9
28
-
29
21
  dir_config "nio4r_ext"
30
22
  create_makefile "nio4r_ext"
31
23
 
data/ext/nio4r/monitor.c CHANGED
@@ -15,12 +15,13 @@ static void NIO_Monitor_free(struct NIO_Monitor *monitor);
15
15
 
16
16
  /* Methods */
17
17
  static VALUE NIO_Monitor_initialize(VALUE self, VALUE selector, VALUE io, VALUE interests);
18
- static VALUE NIO_Monitor_set_interests(VALUE self, VALUE interests);
19
-
20
18
  static VALUE NIO_Monitor_close(int argc, VALUE *argv, VALUE self);
21
19
  static VALUE NIO_Monitor_is_closed(VALUE self);
22
20
  static VALUE NIO_Monitor_io(VALUE self);
23
21
  static VALUE NIO_Monitor_interests(VALUE self);
22
+ static VALUE NIO_Monitor_set_interests(VALUE self, VALUE interests);
23
+ static VALUE NIO_Monitor_add_interest(VALUE self, VALUE interest);
24
+ static VALUE NIO_Monitor_remove_interest(VALUE self, VALUE interest);
24
25
  static VALUE NIO_Monitor_selector(VALUE self);
25
26
  static VALUE NIO_Monitor_is_readable(VALUE self);
26
27
  static VALUE NIO_Monitor_is_writable(VALUE self);
@@ -28,11 +29,9 @@ static VALUE NIO_Monitor_value(VALUE self);
28
29
  static VALUE NIO_Monitor_set_value(VALUE self, VALUE obj);
29
30
  static VALUE NIO_Monitor_readiness(VALUE self);
30
31
 
31
- #if HAVE_RB_IO_T
32
- rb_io_t *fptr;
33
- #else
34
- OpenFile *fptr;
35
- #endif
32
+ /* Internal C functions */
33
+ static int NIO_Monitor_symbol2interest(VALUE interests);
34
+ static void NIO_Monitor_update_interests(VALUE self, int interests);
36
35
 
37
36
  /* Monitor control how a channel is being waited for by a monitor */
38
37
  void Init_NIO_Monitor()
@@ -42,11 +41,13 @@ void Init_NIO_Monitor()
42
41
  rb_define_alloc_func(cNIO_Monitor, NIO_Monitor_allocate);
43
42
 
44
43
  rb_define_method(cNIO_Monitor, "initialize", NIO_Monitor_initialize, 3);
45
- rb_define_method(cNIO_Monitor, "interests=", NIO_Monitor_set_interests, 1);
46
44
  rb_define_method(cNIO_Monitor, "close", NIO_Monitor_close, -1);
47
45
  rb_define_method(cNIO_Monitor, "closed?", NIO_Monitor_is_closed, 0);
48
46
  rb_define_method(cNIO_Monitor, "io", NIO_Monitor_io, 0);
49
47
  rb_define_method(cNIO_Monitor, "interests", NIO_Monitor_interests, 0);
48
+ rb_define_method(cNIO_Monitor, "interests=", NIO_Monitor_set_interests, 1);
49
+ rb_define_method(cNIO_Monitor, "add_interest", NIO_Monitor_add_interest, 1);
50
+ rb_define_method(cNIO_Monitor, "remove_interest", NIO_Monitor_remove_interest, 1);
50
51
  rb_define_method(cNIO_Monitor, "selector", NIO_Monitor_selector, 0);
51
52
  rb_define_method(cNIO_Monitor, "value", NIO_Monitor_value, 0);
52
53
  rb_define_method(cNIO_Monitor, "value=", NIO_Monitor_set_value, 1);
@@ -77,12 +78,7 @@ static VALUE NIO_Monitor_initialize(VALUE self, VALUE io, VALUE interests, VALUE
77
78
  struct NIO_Monitor *monitor;
78
79
  struct NIO_Selector *selector;
79
80
  ID interests_id;
80
-
81
- #if HAVE_RB_IO_T
82
- rb_io_t *fptr;
83
- #else
84
- OpenFile *fptr;
85
- #endif
81
+ rb_io_t *fptr;
86
82
 
87
83
  interests_id = SYM2ID(interests);
88
84
 
@@ -120,38 +116,6 @@ static VALUE NIO_Monitor_initialize(VALUE self, VALUE io, VALUE interests, VALUE
120
116
  return Qnil;
121
117
  }
122
118
 
123
- static VALUE NIO_Monitor_set_interests(VALUE self, VALUE interests)
124
- {
125
- struct NIO_Monitor *monitor;
126
- ID interests_id;
127
-
128
- if(NIO_Monitor_is_closed(self) == Qtrue) {
129
- rb_raise(rb_eTypeError, "monitor is already closed");
130
- }
131
-
132
- interests_id = SYM2ID(interests);
133
- Data_Get_Struct(self, struct NIO_Monitor, monitor);
134
-
135
- if(interests_id == rb_intern("r")) {
136
- monitor->interests = EV_READ;
137
- } else if(interests_id == rb_intern("w")) {
138
- monitor->interests = EV_WRITE;
139
- } else if(interests_id == rb_intern("rw")) {
140
- monitor->interests = EV_READ | EV_WRITE;
141
- } else {
142
- rb_raise(rb_eArgError, "invalid interest type %s (must be :r, :w, or :rw)",
143
- RSTRING_PTR(rb_funcall(interests, rb_intern("inspect"), 0, 0)));
144
- }
145
-
146
- ev_io_stop(monitor->selector->ev_loop, &monitor->ev_io);
147
- ev_io_set(&monitor->ev_io, monitor->ev_io.fd, monitor->interests);
148
- ev_io_start(monitor->selector->ev_loop, &monitor->ev_io);
149
-
150
- rb_ivar_set(self, rb_intern("interests"), interests);
151
-
152
- return interests;
153
- }
154
-
155
119
  static VALUE NIO_Monitor_close(int argc, VALUE *argv, VALUE self)
156
120
  {
157
121
  VALUE deregister, selector;
@@ -197,6 +161,33 @@ static VALUE NIO_Monitor_interests(VALUE self)
197
161
  return rb_ivar_get(self, rb_intern("interests"));
198
162
  }
199
163
 
164
+ static VALUE NIO_Monitor_set_interests(VALUE self, VALUE interests)
165
+ {
166
+ NIO_Monitor_update_interests(self, NIO_Monitor_symbol2interest(interests));
167
+
168
+ return rb_ivar_get(self, rb_intern("interests"));
169
+ }
170
+
171
+ static VALUE NIO_Monitor_add_interest(VALUE self, VALUE interest) {
172
+ struct NIO_Monitor *monitor;
173
+ Data_Get_Struct(self, struct NIO_Monitor, monitor);
174
+
175
+ monitor->interests |= NIO_Monitor_symbol2interest(interest);
176
+ NIO_Monitor_update_interests(self, monitor->interests);
177
+
178
+ return rb_ivar_get(self, rb_intern("interests"));
179
+ }
180
+
181
+ static VALUE NIO_Monitor_remove_interest(VALUE self, VALUE interest) {
182
+ struct NIO_Monitor *monitor;
183
+ Data_Get_Struct(self, struct NIO_Monitor, monitor);
184
+
185
+ monitor->interests &= ~NIO_Monitor_symbol2interest(interest);
186
+ NIO_Monitor_update_interests(self, monitor->interests);
187
+
188
+ return rb_ivar_get(self, rb_intern("interests"));
189
+ }
190
+
200
191
  static VALUE NIO_Monitor_selector(VALUE self)
201
192
  {
202
193
  return rb_ivar_get(self, rb_intern("selector"));
@@ -251,3 +242,59 @@ static VALUE NIO_Monitor_is_writable(VALUE self)
251
242
  return Qfalse;
252
243
  }
253
244
  }
245
+
246
+ /* Internal C functions */
247
+
248
+ static int NIO_Monitor_symbol2interest(VALUE interests)
249
+ {
250
+ ID interests_id;
251
+ interests_id = SYM2ID(interests);
252
+
253
+ if(interests_id == rb_intern("r")) {
254
+ return EV_READ;
255
+ } else if(interests_id == rb_intern("w")) {
256
+ return EV_WRITE;
257
+ } else if(interests_id == rb_intern("rw")) {
258
+ return EV_READ | EV_WRITE;
259
+ } else {
260
+ rb_raise(rb_eArgError, "invalid interest type %s (must be :r, :w, or :rw)",
261
+ RSTRING_PTR(rb_funcall(interests, rb_intern("inspect"), 0, 0)));
262
+ }
263
+ }
264
+
265
+ static void NIO_Monitor_update_interests(VALUE self, int interests)
266
+ {
267
+ ID interests_id;
268
+ struct NIO_Monitor *monitor;
269
+ Data_Get_Struct(self, struct NIO_Monitor, monitor);
270
+
271
+ if(NIO_Monitor_is_closed(self) == Qtrue) {
272
+ rb_raise(rb_eEOFError, "monitor is closed");
273
+ }
274
+
275
+ if(interests) {
276
+ switch(interests) {
277
+ case EV_READ:
278
+ interests_id = rb_intern("r");
279
+ break;
280
+ case EV_WRITE:
281
+ interests_id = rb_intern("w");
282
+ break;
283
+ case EV_READ | EV_WRITE:
284
+ interests_id = rb_intern("rw");
285
+ break;
286
+ default:
287
+ rb_raise(rb_eRuntimeError, "bogus NIO_Monitor_update_interests! (%d)", interests);
288
+ }
289
+
290
+ rb_ivar_set(self, rb_intern("interests"), ID2SYM(interests_id));
291
+ } else {
292
+ rb_ivar_set(self, rb_intern("interests"), Qnil);
293
+ }
294
+
295
+ monitor->interests = interests;
296
+
297
+ ev_io_stop(monitor->selector->ev_loop, &monitor->ev_io);
298
+ ev_io_set(&monitor->ev_io, monitor->ev_io.fd, monitor->interests);
299
+ ev_io_start(monitor->selector->ev_loop, &monitor->ev_io);
300
+ }
data/ext/nio4r/nio4r.h CHANGED
@@ -7,11 +7,7 @@
7
7
  #define NIO4R_H
8
8
 
9
9
  #include "ruby.h"
10
- #if HAVE_RUBY_IO_H
11
- # include "ruby/io.h"
12
- #else
13
- # include "rubyio.h"
14
- #endif
10
+ #include "ruby/io.h"
15
11
  #include "libev.h"
16
12
 
17
13
  struct NIO_Selector
@@ -20,9 +16,10 @@ struct NIO_Selector
20
16
  struct ev_timer timer; /* for timeouts */
21
17
  struct ev_io wakeup;
22
18
 
23
- int wakeup_reader, wakeup_writer;
24
- int closed, selecting;
25
19
  int ready_count;
20
+ int closed, selecting;
21
+ int wakeup_reader, wakeup_writer;
22
+ volatile int wakeup_fired;
26
23
 
27
24
  VALUE ready_array;
28
25
  };
@@ -41,16 +38,17 @@ struct NIO_Monitor
41
38
  struct NIO_Selector *selector;
42
39
  };
43
40
 
41
+ struct NIO_ByteBuffer
42
+ {
43
+ char *buffer;
44
+ int position, limit, capacity, mark;
45
+ };
46
+
47
+
44
48
  #ifdef GetReadFile
45
49
  # define FPTR_TO_FD(fptr) (fileno(GetReadFile(fptr)))
46
50
  #else
47
-
48
- #if !HAVE_RB_IO_T || (RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8)
49
- # define FPTR_TO_FD(fptr) fileno(fptr->f)
50
- #else
51
51
  # define FPTR_TO_FD(fptr) fptr->fd
52
- #endif /* !HAVE_RB_IO_T */
53
-
54
52
  #endif /* GetReadFile */
55
53
 
56
54
  /* Thunk between libev callbacks in NIO::Monitors and NIO::Selectors */
@@ -0,0 +1,295 @@
1
+ package org.nio4r;
2
+
3
+ import java.io.IOException;
4
+ import java.nio.channels.Channel;
5
+ import java.nio.channels.SelectableChannel;
6
+ import java.nio.channels.ReadableByteChannel;
7
+ import java.nio.channels.WritableByteChannel;
8
+ import java.nio.BufferOverflowException;
9
+ import java.nio.BufferUnderflowException;
10
+ import java.nio.InvalidMarkException;
11
+
12
+ import org.jruby.Ruby;
13
+ import org.jruby.RubyClass;
14
+ import org.jruby.RubyIO;
15
+ import org.jruby.RubyNumeric;
16
+ import org.jruby.RubyObject;
17
+ import org.jruby.RubyString;
18
+ import org.jruby.anno.JRubyMethod;
19
+ import org.jruby.exceptions.RaiseException;
20
+ import org.jruby.runtime.ThreadContext;
21
+ import org.jruby.runtime.builtin.IRubyObject;
22
+ import org.jruby.runtime.Block;
23
+
24
+ /*
25
+ created by Upekshej
26
+ */
27
+ public class ByteBuffer extends RubyObject {
28
+ private java.nio.ByteBuffer byteBuffer;
29
+
30
+ public static RaiseException newOverflowError(ThreadContext context, String message) {
31
+ RubyClass klass = context.runtime.getModule("NIO").getClass("ByteBuffer").getClass("OverflowError");
32
+ return context.runtime.newRaiseException(klass, message);
33
+ }
34
+
35
+ public static RaiseException newUnderflowError(ThreadContext context, String message) {
36
+ RubyClass klass = context.runtime.getModule("NIO").getClass("ByteBuffer").getClass("UnderflowError");
37
+ return context.runtime.newRaiseException(klass, message);
38
+ }
39
+
40
+ public static RaiseException newMarkUnsetError(ThreadContext context, String message) {
41
+ RubyClass klass = context.runtime.getModule("NIO").getClass("ByteBuffer").getClass("MarkUnsetError");
42
+ return context.runtime.newRaiseException(klass, message);
43
+ }
44
+
45
+ public ByteBuffer(final Ruby ruby, RubyClass rubyClass) {
46
+ super(ruby, rubyClass);
47
+ }
48
+
49
+ @JRubyMethod
50
+ public IRubyObject initialize(ThreadContext context, IRubyObject capacity) {
51
+ this.byteBuffer = java.nio.ByteBuffer.allocate(RubyNumeric.num2int(capacity));
52
+ return this;
53
+ }
54
+
55
+ @JRubyMethod
56
+ public IRubyObject clear(ThreadContext context) {
57
+ this.byteBuffer.clear();
58
+ return this;
59
+ }
60
+
61
+ @JRubyMethod(name = "position")
62
+ public IRubyObject getPosition(ThreadContext context) {
63
+ return context.getRuntime().newFixnum(this.byteBuffer.position());
64
+ }
65
+
66
+ @JRubyMethod(name = "position=")
67
+ public IRubyObject setPosition(ThreadContext context, IRubyObject newPosition) {
68
+ int pos = RubyNumeric.num2int(newPosition);
69
+
70
+ if(pos < 0) {
71
+ throw context.runtime.newArgumentError("negative position given");
72
+ }
73
+
74
+ if(pos > this.byteBuffer.limit()) {
75
+ throw context.runtime.newArgumentError("specified position exceeds limit");
76
+ }
77
+
78
+ try {
79
+ this.byteBuffer.position(pos);
80
+ return newPosition;
81
+ } catch(IllegalArgumentException e) {
82
+ throw context.runtime.newArgumentError(e.getLocalizedMessage());
83
+ }
84
+ }
85
+
86
+ @JRubyMethod(name = "limit")
87
+ public IRubyObject getLimit(ThreadContext context) {
88
+ return context.getRuntime().newFixnum(this.byteBuffer.limit());
89
+ }
90
+
91
+ @JRubyMethod(name = "limit=")
92
+ public IRubyObject setLimit(ThreadContext context, IRubyObject newLimit) {
93
+ int lim = RubyNumeric.num2int(newLimit);
94
+
95
+ if(lim < 0) {
96
+ throw context.runtime.newArgumentError("negative limit given");
97
+ }
98
+
99
+ if(lim > this.byteBuffer.capacity()) {
100
+ throw context.runtime.newArgumentError("specified limit exceeds capacity");
101
+ }
102
+
103
+ try {
104
+ this.byteBuffer.limit(lim);
105
+ return newLimit;
106
+ } catch(IllegalArgumentException e) {
107
+ throw context.runtime.newArgumentError(e.getLocalizedMessage());
108
+ }
109
+ }
110
+
111
+ @JRubyMethod(name = {"capacity", "size"})
112
+ public IRubyObject capacity(ThreadContext context) {
113
+ return context.getRuntime().newFixnum(this.byteBuffer.capacity());
114
+ }
115
+
116
+ @JRubyMethod
117
+ public IRubyObject remaining(ThreadContext context) {
118
+ return context.getRuntime().newFixnum(this.byteBuffer.remaining());
119
+ }
120
+
121
+ @JRubyMethod(name = "full?")
122
+ public IRubyObject isFull(ThreadContext context) {
123
+ if (this.byteBuffer.hasRemaining()) {
124
+ return context.getRuntime().getFalse();
125
+ } else {
126
+ return context.getRuntime().getTrue();
127
+ }
128
+ }
129
+
130
+ @JRubyMethod
131
+ public IRubyObject get(ThreadContext context) {
132
+ return this.get(context, context.getRuntime().newFixnum(this.byteBuffer.remaining()));
133
+ }
134
+
135
+ @JRubyMethod
136
+ public IRubyObject get(ThreadContext context, IRubyObject length) {
137
+ int len = RubyNumeric.num2int(length);
138
+ byte[] bytes = new byte[len];
139
+
140
+ try {
141
+ this.byteBuffer.get(bytes);
142
+ } catch(BufferUnderflowException e) {
143
+ throw ByteBuffer.newUnderflowError(context, "not enough data in buffer");
144
+ }
145
+
146
+ return RubyString.newString(context.getRuntime(), bytes);
147
+ }
148
+
149
+ @JRubyMethod(name = "[]")
150
+ public IRubyObject fetch(ThreadContext context, IRubyObject index) {
151
+ int i = RubyNumeric.num2int(index);
152
+
153
+ if(i < 0) {
154
+ throw context.runtime.newArgumentError("negative index given");
155
+ }
156
+
157
+ if(i >= this.byteBuffer.limit()) {
158
+ throw context.runtime.newArgumentError("index exceeds limit");
159
+ }
160
+
161
+ return context.getRuntime().newFixnum(this.byteBuffer.get(i));
162
+ }
163
+
164
+ @JRubyMethod(name = "<<")
165
+ public IRubyObject put(ThreadContext context, IRubyObject str) {
166
+ String string = str.asJavaString();
167
+
168
+ try {
169
+ this.byteBuffer.put(string.getBytes());
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
+ }