nio4r 2.0.0.pre-java → 2.1.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 +9 -19
- data/CHANGES.md +94 -42
- data/Gemfile +11 -3
- data/Guardfile +10 -0
- data/LICENSE.txt +1 -1
- data/README.md +43 -136
- data/Rakefile +2 -0
- data/examples/echo_server.rb +1 -0
- data/ext/libev/Changes +9 -13
- data/ext/libev/ev.c +100 -74
- data/ext/libev/ev.h +4 -9
- 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 +265 -257
- data/ext/nio4r/extconf.rb +3 -9
- data/ext/nio4r/monitor.c +93 -46
- data/ext/nio4r/nio4r.h +6 -16
- data/ext/nio4r/org/nio4r/ByteBuffer.java +193 -209
- data/ext/nio4r/org/nio4r/Monitor.java +164 -0
- data/ext/nio4r/org/nio4r/Nio4r.java +13 -391
- data/ext/nio4r/org/nio4r/Selector.java +278 -0
- data/ext/nio4r/selector.c +72 -64
- data/lib/nio.rb +3 -3
- data/lib/nio/bytebuffer.rb +179 -132
- data/lib/nio/monitor.rb +64 -4
- data/lib/nio/selector.rb +36 -13
- 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 +323 -51
- 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 +18 -15
- 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,7 +18,7 @@ $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
|
-
|
21
|
+
CONFIG["optflags"] << " -fno-strict-aliasing"
|
28
22
|
|
29
23
|
dir_config "nio4r_ext"
|
30
24
|
create_makefile "nio4r_ext"
|
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,22 +7,19 @@
|
|
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
|
18
14
|
{
|
19
|
-
|
15
|
+
ev_loop *ev_loop;
|
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
|
};
|
@@ -43,22 +40,15 @@ struct NIO_Monitor
|
|
43
40
|
|
44
41
|
struct NIO_ByteBuffer
|
45
42
|
{
|
46
|
-
int size, offset, limit, position, mark;
|
47
43
|
char *buffer;
|
48
|
-
|
44
|
+
int position, limit, capacity, mark;
|
49
45
|
};
|
50
46
|
|
51
47
|
|
52
48
|
#ifdef GetReadFile
|
53
49
|
# define FPTR_TO_FD(fptr) (fileno(GetReadFile(fptr)))
|
54
50
|
#else
|
55
|
-
|
56
|
-
#if !HAVE_RB_IO_T || (RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8)
|
57
|
-
# define FPTR_TO_FD(fptr) fileno(fptr->f)
|
58
|
-
#else
|
59
51
|
# define FPTR_TO_FD(fptr) fptr->fd
|
60
|
-
#endif /* !HAVE_RB_IO_T */
|
61
|
-
|
62
52
|
#endif /* GetReadFile */
|
63
53
|
|
64
54
|
/* Thunk between libev callbacks in NIO::Monitors and NIO::Selectors */
|
@@ -1,311 +1,295 @@
|
|
1
1
|
package org.nio4r;
|
2
2
|
|
3
|
-
import
|
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;
|
4
18
|
import org.jruby.anno.JRubyMethod;
|
5
|
-
import org.jruby.
|
19
|
+
import org.jruby.exceptions.RaiseException;
|
6
20
|
import org.jruby.runtime.ThreadContext;
|
7
21
|
import org.jruby.runtime.builtin.IRubyObject;
|
8
|
-
|
9
|
-
import java.io.File;
|
10
|
-
import java.io.FileInputStream;
|
11
|
-
import java.io.FileOutputStream;
|
12
|
-
import java.nio.channels.FileChannel;
|
13
|
-
import java.util.ArrayList;
|
22
|
+
import org.jruby.runtime.Block;
|
14
23
|
|
15
24
|
/*
|
16
25
|
created by Upekshej
|
17
26
|
*/
|
18
27
|
public class ByteBuffer extends RubyObject {
|
19
|
-
|
20
28
|
private java.nio.ByteBuffer byteBuffer;
|
21
|
-
private String currentWritePath = "";
|
22
|
-
private String currentReadPath = "";
|
23
29
|
|
24
|
-
|
25
|
-
|
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
|
+
}
|
26
34
|
|
27
|
-
|
28
|
-
|
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
|
+
}
|
29
44
|
|
30
45
|
public ByteBuffer(final Ruby ruby, RubyClass rubyClass) {
|
31
46
|
super(ruby, rubyClass);
|
32
47
|
}
|
33
48
|
|
34
49
|
@JRubyMethod
|
35
|
-
public IRubyObject initialize(ThreadContext context, IRubyObject
|
36
|
-
|
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
|
+
}
|
37
60
|
|
38
|
-
|
39
|
-
|
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");
|
40
72
|
}
|
41
73
|
|
42
|
-
if
|
43
|
-
|
44
|
-
int arrayOffset = RubyNumeric.num2int(offset);
|
45
|
-
int arrayLimit = RubyNumeric.num2int(length);
|
46
|
-
byteBuffer = java.nio.ByteBuffer.wrap(value.asJavaString().getBytes(), arrayOffset, arrayLimit);
|
47
|
-
} else {
|
48
|
-
byteBuffer = java.nio.ByteBuffer.wrap(value.asJavaString().getBytes());
|
49
|
-
}
|
50
|
-
} else if (value instanceof RubyInteger) {
|
51
|
-
int allocationSize = RubyNumeric.num2int(value);
|
52
|
-
byteBuffer = java.nio.ByteBuffer.allocate(allocationSize);
|
53
|
-
} else {
|
54
|
-
throw ruby.newTypeError("expected String or Integer for value");
|
74
|
+
if(pos > this.byteBuffer.limit()) {
|
75
|
+
throw context.runtime.newArgumentError("specified position exceeds limit");
|
55
76
|
}
|
56
77
|
|
57
|
-
|
78
|
+
try {
|
79
|
+
this.byteBuffer.position(pos);
|
80
|
+
return newPosition;
|
81
|
+
} catch(IllegalArgumentException e) {
|
82
|
+
throw context.runtime.newArgumentError(e.getLocalizedMessage());
|
83
|
+
}
|
58
84
|
}
|
59
85
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
* @return
|
65
|
-
*/
|
66
|
-
@JRubyMethod(name = "<<")
|
67
|
-
public IRubyObject put(ThreadContext context, IRubyObject str) {
|
68
|
-
String string = str.asJavaString();
|
86
|
+
@JRubyMethod(name = "limit")
|
87
|
+
public IRubyObject getLimit(ThreadContext context) {
|
88
|
+
return context.getRuntime().newFixnum(this.byteBuffer.limit());
|
89
|
+
}
|
69
90
|
|
70
|
-
|
71
|
-
|
72
|
-
|
91
|
+
@JRubyMethod(name = "limit=")
|
92
|
+
public IRubyObject setLimit(ThreadContext context, IRubyObject newLimit) {
|
93
|
+
int lim = RubyNumeric.num2int(newLimit);
|
73
94
|
|
74
|
-
|
75
|
-
|
76
|
-
|
95
|
+
if(lim < 0) {
|
96
|
+
throw context.runtime.newArgumentError("negative limit given");
|
97
|
+
}
|
77
98
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
ArrayList<Byte> temp = new ArrayList<Byte>();
|
99
|
+
if(lim > this.byteBuffer.capacity()) {
|
100
|
+
throw context.runtime.newArgumentError("specified limit exceeds capacity");
|
101
|
+
}
|
82
102
|
|
83
|
-
|
84
|
-
|
103
|
+
try {
|
104
|
+
this.byteBuffer.limit(lim);
|
105
|
+
return newLimit;
|
106
|
+
} catch(IllegalArgumentException e) {
|
107
|
+
throw context.runtime.newArgumentError(e.getLocalizedMessage());
|
85
108
|
}
|
109
|
+
}
|
86
110
|
|
87
|
-
|
111
|
+
@JRubyMethod(name = {"capacity", "size"})
|
112
|
+
public IRubyObject capacity(ThreadContext context) {
|
113
|
+
return context.getRuntime().newFixnum(this.byteBuffer.capacity());
|
88
114
|
}
|
89
115
|
|
90
|
-
@JRubyMethod
|
91
|
-
public IRubyObject
|
92
|
-
|
116
|
+
@JRubyMethod
|
117
|
+
public IRubyObject remaining(ThreadContext context) {
|
118
|
+
return context.getRuntime().newFixnum(this.byteBuffer.remaining());
|
119
|
+
}
|
93
120
|
|
94
|
-
|
95
|
-
|
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();
|
96
127
|
}
|
128
|
+
}
|
97
129
|
|
98
|
-
|
99
|
-
|
130
|
+
@JRubyMethod
|
131
|
+
public IRubyObject get(ThreadContext context) {
|
132
|
+
return this.get(context, context.getRuntime().newFixnum(this.byteBuffer.remaining()));
|
133
|
+
}
|
100
134
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
135
|
+
@JRubyMethod
|
136
|
+
public IRubyObject get(ThreadContext context, IRubyObject length) {
|
137
|
+
int len = RubyNumeric.num2int(length);
|
138
|
+
byte[] bytes = new byte[len];
|
105
139
|
|
106
|
-
|
140
|
+
try {
|
141
|
+
this.byteBuffer.get(bytes);
|
142
|
+
} catch(BufferUnderflowException e) {
|
143
|
+
throw ByteBuffer.newUnderflowError(context, "not enough data in buffer");
|
107
144
|
}
|
108
145
|
|
109
|
-
return RubyString.
|
146
|
+
return RubyString.newString(context.getRuntime(), bytes);
|
110
147
|
}
|
111
148
|
|
112
|
-
|
113
|
-
|
149
|
+
@JRubyMethod(name = "[]")
|
150
|
+
public IRubyObject fetch(ThreadContext context, IRubyObject index) {
|
151
|
+
int i = RubyNumeric.num2int(index);
|
114
152
|
|
115
|
-
|
116
|
-
|
153
|
+
if(i < 0) {
|
154
|
+
throw context.runtime.newArgumentError("negative index given");
|
117
155
|
}
|
118
156
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
@JRubyMethod(name = "write_to")
|
123
|
-
public IRubyObject writeTo(ThreadContext context, IRubyObject f) {
|
124
|
-
try {
|
125
|
-
File file = (File) JavaUtil.unwrapJavaObject(f);
|
157
|
+
if(i >= this.byteBuffer.limit()) {
|
158
|
+
throw context.runtime.newArgumentError("index exceeds limit");
|
159
|
+
}
|
126
160
|
|
127
|
-
|
128
|
-
|
129
|
-
if (currentWriteFileChannel != null) currentWriteFileChannel.close();
|
130
|
-
if (fileOutputStream != null) fileOutputStream.close();
|
161
|
+
return context.getRuntime().newFixnum(this.byteBuffer.get(i));
|
162
|
+
}
|
131
163
|
|
132
|
-
|
133
|
-
|
134
|
-
|
164
|
+
@JRubyMethod(name = "<<")
|
165
|
+
public IRubyObject put(ThreadContext context, IRubyObject str) {
|
166
|
+
String string = str.asJavaString();
|
135
167
|
|
136
|
-
|
137
|
-
|
138
|
-
|
168
|
+
try {
|
169
|
+
this.byteBuffer.put(string.getBytes());
|
170
|
+
} catch(BufferOverflowException e) {
|
171
|
+
throw ByteBuffer.newOverflowError(context, "buffer is full");
|
139
172
|
}
|
140
173
|
|
141
174
|
return this;
|
142
175
|
}
|
143
176
|
|
144
177
|
@JRubyMethod(name = "read_from")
|
145
|
-
public IRubyObject readFrom(ThreadContext context, IRubyObject
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
if (!isTheSameFile(file, true)) {
|
150
|
-
inChannel.close();
|
151
|
-
currentReadChannel.close();
|
152
|
-
currentReadPath = file.getAbsolutePath();
|
153
|
-
currentReadChannel = new FileInputStream(file);
|
154
|
-
inChannel = currentReadChannel.getChannel();
|
155
|
-
}
|
178
|
+
public IRubyObject readFrom(ThreadContext context, IRubyObject io) {
|
179
|
+
Ruby runtime = context.runtime;
|
180
|
+
Channel channel = RubyIO.convertToIO(context, io).getChannel();
|
156
181
|
|
157
|
-
|
158
|
-
|
159
|
-
throw new IllegalArgumentException("read error: " + e.getLocalizedMessage());
|
182
|
+
if(!this.byteBuffer.hasRemaining()) {
|
183
|
+
throw ByteBuffer.newOverflowError(context, "buffer is full");
|
160
184
|
}
|
161
185
|
|
162
|
-
|
163
|
-
|
186
|
+
if(!(channel instanceof ReadableByteChannel) || !(channel instanceof SelectableChannel)) {
|
187
|
+
throw runtime.newArgumentError("unsupported IO object: " + io.getType().toString());
|
188
|
+
}
|
164
189
|
|
165
|
-
|
166
|
-
|
167
|
-
|
190
|
+
try {
|
191
|
+
((SelectableChannel)channel).configureBlocking(false);
|
192
|
+
} catch(IOException ie) {
|
193
|
+
throw runtime.newIOError(ie.getLocalizedMessage());
|
168
194
|
}
|
169
195
|
|
170
|
-
|
171
|
-
|
196
|
+
try {
|
197
|
+
int bytesRead = ((ReadableByteChannel)channel).read(this.byteBuffer);
|
172
198
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
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
|
+
}
|
177
207
|
}
|
178
208
|
|
179
|
-
@JRubyMethod(name = "
|
180
|
-
public IRubyObject
|
181
|
-
|
182
|
-
|
183
|
-
}
|
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();
|
184
213
|
|
185
|
-
|
186
|
-
|
214
|
+
if(!this.byteBuffer.hasRemaining()) {
|
215
|
+
throw ByteBuffer.newUnderflowError(context, "not enough data in buffer");
|
216
|
+
}
|
187
217
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
return context.getRuntime().newFixnum(offset);
|
192
|
-
}
|
218
|
+
if(!(channel instanceof WritableByteChannel) || !(channel instanceof SelectableChannel)) {
|
219
|
+
throw runtime.newArgumentError("unsupported IO object: " + io.getType().toString());
|
220
|
+
}
|
193
221
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
* @param ob : The RubyObject which needs to be check
|
199
|
-
* @return
|
200
|
-
*/
|
201
|
-
@JRubyMethod(name = "equals?")
|
202
|
-
public IRubyObject equals(ThreadContext context, IRubyObject obj) {
|
203
|
-
Object o = JavaUtil.convertRubyToJava(obj);
|
204
|
-
|
205
|
-
if(!(o instanceof ByteBuffer)) {
|
206
|
-
return context.getRuntime().getFalse();
|
222
|
+
try {
|
223
|
+
((SelectableChannel)channel).configureBlocking(false);
|
224
|
+
} catch(IOException ie) {
|
225
|
+
throw runtime.newIOError(ie.getLocalizedMessage());
|
207
226
|
}
|
208
227
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
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());
|
213
238
|
}
|
214
239
|
}
|
215
240
|
|
216
|
-
/**
|
217
|
-
* Flip capability provided by the java nio.ByteBuffer
|
218
|
-
* buf.put(magic); // Prepend header
|
219
|
-
* in.read(buf); // Read data into rest of buffer
|
220
|
-
* buf.flip(); // Flip buffer
|
221
|
-
* out.write(buf); // Write header + data to channel
|
222
|
-
*
|
223
|
-
* @param context
|
224
|
-
* @return
|
225
|
-
*/
|
226
241
|
@JRubyMethod
|
227
242
|
public IRubyObject flip(ThreadContext context) {
|
228
|
-
byteBuffer.flip();
|
243
|
+
this.byteBuffer.flip();
|
229
244
|
return this;
|
230
245
|
}
|
231
246
|
|
232
|
-
/**
|
233
|
-
* Rewinds the buffer. Usage in java is like
|
234
|
-
* out.write(buf); // Write remaining data
|
235
|
-
* buf.rewind(); // Rewind buffer
|
236
|
-
* buf.get(array); // Copy data into array
|
237
|
-
*
|
238
|
-
* @param context
|
239
|
-
* @return
|
240
|
-
*/
|
241
247
|
@JRubyMethod
|
242
248
|
public IRubyObject rewind(ThreadContext context) {
|
243
|
-
byteBuffer.rewind();
|
244
|
-
return this;
|
245
|
-
}
|
246
|
-
|
247
|
-
@JRubyMethod
|
248
|
-
public IRubyObject reset(ThreadContext context) {
|
249
|
-
byteBuffer.reset();
|
249
|
+
this.byteBuffer.rewind();
|
250
250
|
return this;
|
251
251
|
}
|
252
252
|
|
253
253
|
@JRubyMethod
|
254
254
|
public IRubyObject mark(ThreadContext context) {
|
255
|
-
byteBuffer.mark();
|
255
|
+
this.byteBuffer.mark();
|
256
256
|
return this;
|
257
257
|
}
|
258
258
|
|
259
|
-
/**
|
260
|
-
* Removes all the content in the byteBuffer
|
261
|
-
*
|
262
|
-
* @param context
|
263
|
-
* @return
|
264
|
-
*/
|
265
259
|
@JRubyMethod
|
266
|
-
public IRubyObject
|
267
|
-
|
268
|
-
|
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
|
+
}
|
269
267
|
}
|
270
268
|
|
271
269
|
@JRubyMethod
|
272
270
|
public IRubyObject compact(ThreadContext context) {
|
273
|
-
byteBuffer.compact();
|
271
|
+
this.byteBuffer.compact();
|
274
272
|
return this;
|
275
273
|
}
|
276
274
|
|
277
|
-
@JRubyMethod(name = "capacity")
|
278
|
-
public IRubyObject capacity(ThreadContext context) {
|
279
|
-
int cap = byteBuffer.capacity();
|
280
|
-
return context.getRuntime().newFixnum(cap);
|
281
|
-
}
|
282
|
-
|
283
275
|
@JRubyMethod
|
284
|
-
public IRubyObject
|
285
|
-
int
|
286
|
-
|
287
|
-
|
288
|
-
}
|
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
|
+
}
|
289
280
|
|
290
|
-
@JRubyMethod(name = "limit")
|
291
|
-
public IRubyObject limit(ThreadContext context, IRubyObject newLimit) {
|
292
|
-
int limit = RubyNumeric.num2int(newLimit);
|
293
|
-
byteBuffer.limit(limit);
|
294
281
|
return this;
|
295
282
|
}
|
296
283
|
|
297
|
-
@JRubyMethod
|
298
|
-
public IRubyObject
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
public java.nio.ByteBuffer getBuffer() {
|
309
|
-
return byteBuffer;
|
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
|
+
));
|
310
294
|
}
|
311
295
|
}
|