nio4r 1.2.1-java → 2.0.0-java

Sign up to get free protection for your applications and to get access to all the features.
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
+ }