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.
- checksums.yaml +4 -4
- data/.rspec +0 -1
- data/.rubocop.yml +31 -38
- data/.ruby-version +1 -0
- data/.travis.yml +15 -14
- data/CHANGES.md +75 -42
- data/Gemfile +10 -5
- data/Guardfile +10 -0
- data/LICENSE.txt +1 -1
- data/README.md +57 -161
- data/Rakefile +2 -1
- data/examples/echo_server.rb +1 -0
- data/ext/libev/Changes +4 -13
- data/ext/libev/ev.c +101 -74
- data/ext/libev/ev.h +3 -3
- data/ext/libev/ev_epoll.c +6 -3
- data/ext/libev/ev_kqueue.c +8 -4
- data/ext/libev/ev_poll.c +6 -3
- data/ext/libev/ev_port.c +8 -4
- data/ext/libev/ev_select.c +4 -2
- data/ext/nio4r/bytebuffer.c +421 -0
- data/ext/nio4r/extconf.rb +2 -10
- data/ext/nio4r/monitor.c +93 -46
- data/ext/nio4r/nio4r.h +11 -13
- data/ext/nio4r/org/nio4r/ByteBuffer.java +295 -0
- data/ext/nio4r/org/nio4r/Monitor.java +164 -0
- data/ext/nio4r/org/nio4r/Nio4r.java +22 -391
- data/ext/nio4r/org/nio4r/Selector.java +278 -0
- data/ext/nio4r/selector.c +55 -53
- data/lib/nio.rb +4 -3
- data/lib/nio/bytebuffer.rb +222 -0
- data/lib/nio/monitor.rb +64 -4
- data/lib/nio/selector.rb +52 -20
- data/lib/nio/version.rb +1 -1
- data/nio4r.gemspec +25 -19
- data/spec/nio/acceptables_spec.rb +6 -4
- data/spec/nio/bytebuffer_spec.rb +349 -0
- data/spec/nio/monitor_spec.rb +122 -79
- data/spec/nio/selectables/pipe_spec.rb +5 -1
- data/spec/nio/selectables/ssl_socket_spec.rb +15 -12
- data/spec/nio/selectables/tcp_socket_spec.rb +42 -31
- data/spec/nio/selectables/udp_socket_spec.rb +2 -0
- data/spec/nio/selector_spec.rb +10 -4
- data/spec/spec_helper.rb +24 -3
- data/spec/support/selectable_examples.rb +7 -5
- data/tasks/extension.rake +2 -0
- data/tasks/rspec.rake +2 -0
- data/tasks/rubocop.rake +2 -0
- metadata +21 -14
- 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
|
-
|
32
|
-
|
33
|
-
|
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
|
-
#
|
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
|
+
}
|