nio4r 1.2.1 → 2.0.0.pre
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/.travis.yml +27 -9
- data/Gemfile +4 -7
- data/README.md +43 -43
- data/Rakefile +0 -1
- data/examples/echo_server.rb +0 -0
- data/ext/libev/ev.c +1 -0
- data/ext/nio4r/bytebuffer.c +413 -0
- data/ext/nio4r/nio4r.h +8 -0
- data/ext/nio4r/nio4r_ext.c +2 -0
- data/ext/nio4r/org/nio4r/ByteBuffer.java +311 -0
- data/ext/nio4r/org/nio4r/Nio4r.java +9 -0
- data/ext/nio4r/selector.c +3 -1
- data/lib/nio/bytebuffer.rb +175 -0
- data/lib/nio/selector.rb +19 -10
- data/lib/nio/version.rb +1 -1
- data/lib/nio.rb +1 -0
- data/spec/nio/bytebuffer_spec.rb +77 -0
- metadata +9 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f6641deb5a7b32db8287d8856510a07dd33ec737
|
4
|
+
data.tar.gz: e414ccbb0aef8b0d8cf9ab63e09154753652766b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 37539315f05ec820ec9a5644acb178c49098e6384955ce234c7b5d4f137d8122d98a8486e9ebc419250057b4268d55f72f82ca28145c2ebf713af7823bd9a7fb
|
7
|
+
data.tar.gz: 1c151cb3ac3d8aef61665ebf4827b59712509d2482c1b26ad1af2853711e6888c8043306a312d4d84b89f511085c346ade0915e768307811bddabc2cc39c41ae
|
data/.travis.yml
CHANGED
@@ -1,26 +1,44 @@
|
|
1
1
|
language: ruby
|
2
2
|
sudo: false
|
3
|
+
cache: bundler
|
4
|
+
|
5
|
+
bundler_args: --without development
|
6
|
+
|
7
|
+
branches:
|
8
|
+
only:
|
9
|
+
- master
|
10
|
+
|
11
|
+
os:
|
12
|
+
- linux
|
13
|
+
- osx
|
3
14
|
|
4
15
|
rvm:
|
5
|
-
- 2.0
|
6
|
-
- 2.1
|
7
|
-
- 2.2
|
16
|
+
- 2.0
|
17
|
+
- 2.1
|
18
|
+
- 2.2
|
19
|
+
- 2.3.1
|
8
20
|
- ruby-head
|
9
|
-
- jruby
|
21
|
+
- jruby-9.1.5.0 # latest stable
|
10
22
|
- jruby-head
|
11
|
-
- rbx
|
23
|
+
- rbx
|
12
24
|
|
13
25
|
env:
|
14
|
-
|
15
|
-
|
26
|
+
global:
|
27
|
+
- JRUBY_OPTS="--dev -J-Djruby.launch.inproc=true -J-Xmx1024M"
|
28
|
+
matrix:
|
29
|
+
- NIO4R_PURE=false
|
30
|
+
- NIO4R_PURE=true
|
16
31
|
|
17
32
|
matrix:
|
18
33
|
fast_finish: true
|
19
34
|
allow_failures:
|
35
|
+
- os: osx # TODO: make tests pass reliably on OS X
|
20
36
|
- rvm: ruby-head
|
21
37
|
- rvm: jruby-head
|
22
|
-
- rvm: rbx
|
23
|
-
- rvm: jruby
|
38
|
+
- rvm: rbx
|
39
|
+
- rvm: jruby-1.7
|
40
|
+
env: NIO4R_PURE=true
|
41
|
+
- rvm: jruby-9.1
|
24
42
|
env: NIO4R_PURE=true
|
25
43
|
|
26
44
|
notifications:
|
data/Gemfile
CHANGED
@@ -4,12 +4,9 @@ gemspec
|
|
4
4
|
|
5
5
|
gem "jruby-openssl" if defined? JRUBY_VERSION
|
6
6
|
|
7
|
-
group :development do
|
7
|
+
group :development, :test do
|
8
8
|
gem "rake-compiler"
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
gem "rspec", "~> 3.0"
|
13
|
-
gem "rubocop", "0.36.0"
|
14
|
-
gem "coveralls", require: false
|
9
|
+
gem "rspec", "~> 3", require: false
|
10
|
+
gem "rubocop", "0.36.0", require: false
|
11
|
+
gem "coveralls", require: false
|
15
12
|
end
|
data/README.md
CHANGED
@@ -1,47 +1,52 @@
|
|
1
|
-

|
2
|
-
|
1
|
+
# 
|
2
|
+
|
3
3
|
[](http://rubygems.org/gems/nio4r)
|
4
4
|
[](http://travis-ci.org/celluloid/nio4r)
|
5
5
|
[](https://codeclimate.com/github/celluloid/nio4r)
|
6
6
|
[](https://coveralls.io/r/celluloid/nio4r)
|
7
7
|
[](https://github.com/celluloid/nio4r/blob/master/LICENSE.txt)
|
8
8
|
|
9
|
-
|
9
|
+
_NOTE: This is the 2.x **development** branch of nio4r. For the 1.x **stable**
|
10
|
+
branch (used by [Rails 5]), please see:_
|
11
|
+
|
12
|
+
https://github.com/celluloid/nio4r/tree/1-x-stable
|
13
|
+
|
14
|
+
**New I/O for Ruby (nio4r)**: cross-platform asynchronous I/O primitives for
|
15
|
+
scalable network clients and servers. Modeled after the Java NIO API, but
|
16
|
+
simplified for ease-of-use.
|
10
17
|
|
11
|
-
nio4r provides an abstract, cross-platform stateful I/O selector API for Ruby.
|
18
|
+
**nio4r** provides an abstract, cross-platform stateful I/O selector API for Ruby.
|
12
19
|
I/O selectors are the heart of "reactor"-based event loops, and monitor
|
13
20
|
multiple I/O objects for various types of readiness, e.g. ready for reading or
|
14
21
|
writing.
|
15
22
|
|
16
|
-
|
17
|
-
select API requires you to pass in arrays of all of the I/O objects you're
|
18
|
-
interested in every time. nio4r provides a more object-oriented API that lets
|
19
|
-
you register I/O objects with a selector then handle them when they're selected
|
20
|
-
for various types of events.
|
23
|
+
[Rails 5]: https://rubygems.org/gems/actioncable
|
21
24
|
|
22
|
-
|
25
|
+
## Projects using nio4r
|
23
26
|
|
24
|
-
|
27
|
+
* [ActionCable]: Rails 5 WebSocket protocol, uses nio4r for a WebSocket server
|
28
|
+
* [Celluloid::IO]: Actor-based concurrency framework, uses nio4r for async I/O
|
29
|
+
|
30
|
+
[ActionCable]: https://rubygems.org/gems/actioncable
|
31
|
+
[Celluloid::IO]: https://github.com/celluloid/celluloid-io
|
32
|
+
|
33
|
+
## Goals
|
25
34
|
|
26
35
|
* Expose high-level interfaces for stateful IO selectors
|
27
36
|
* Keep the API small to maximize both portability and performance across many
|
28
37
|
different OSes and Ruby VMs
|
29
38
|
* Provide inherently thread-safe facilities for working with IO objects
|
30
39
|
|
31
|
-
|
32
|
-
monitor multiple IO objects from a single Celluloid actor.
|
33
|
-
|
34
|
-
Supported Platforms
|
35
|
-
-------------------
|
40
|
+
## Supported platforms
|
36
41
|
|
37
|
-
|
42
|
+
* Ruby 2.0
|
43
|
+
* Ruby 2.1
|
44
|
+
* Ruby 2.2
|
45
|
+
* Ruby 2.3
|
46
|
+
* JRuby 9000
|
47
|
+
* Pure Ruby using Kernel.select
|
38
48
|
|
39
|
-
|
40
|
-
* JRuby 1.7.x
|
41
|
-
* Rubinius 2.x
|
42
|
-
* A pure Ruby implementation based on Kernel.select is also provided
|
43
|
-
|
44
|
-
Platform notes:
|
49
|
+
## Platform notes
|
45
50
|
|
46
51
|
* MRI/YARV and Rubinius implement nio4r with a C extension based on libev,
|
47
52
|
which provides a high performance binding to native IO APIs
|
@@ -49,8 +54,14 @@ Platform notes:
|
|
49
54
|
* A pure Ruby implementation is also provided for Ruby implementations which
|
50
55
|
don't implement the MRI C extension API
|
51
56
|
|
52
|
-
Usage
|
53
|
-
|
57
|
+
## Usage
|
58
|
+
|
59
|
+
If you're interested in using nio4r for a project but just getting started,
|
60
|
+
check out this blog post which provides some background and examples:
|
61
|
+
|
62
|
+
[A gentle introduction to nio4r: low-level portable asynchronous I/O for Ruby][blogpost]
|
63
|
+
|
64
|
+
[blogpost]: https://tonyarcieri.com/a-gentle-introduction-to-nio4r
|
54
65
|
|
55
66
|
### Selectors
|
56
67
|
|
@@ -152,10 +163,9 @@ For information on how to compose nio4r selectors inside of event loops,
|
|
152
163
|
please read the [Flow Control Guide on the
|
153
164
|
Wiki](https://github.com/celluloid/nio4r/wiki/Basic-Flow-Control)
|
154
165
|
|
155
|
-
Concurrency
|
156
|
-
-----------
|
166
|
+
## Concurrency
|
157
167
|
|
158
|
-
nio4r provides internal locking to ensure that it's safe to use from multiple
|
168
|
+
**nio4r** provides internal locking to ensure that it's safe to use from multiple
|
159
169
|
concurrent threads. Only one thread can select on a NIO::Selector at a given
|
160
170
|
time, and while a thread is selecting other threads are blocked from
|
161
171
|
registering or deregistering IO objects. Once a pending select has completed,
|
@@ -166,28 +176,18 @@ middle of an NIO::Selector#select operation. This lets other threads that need
|
|
166
176
|
to communicate immediately with the selector unblock it so it can process
|
167
177
|
other events that it's not presently selecting on.
|
168
178
|
|
169
|
-
|
170
|
-
-----------------
|
179
|
+
## Non-goals
|
171
180
|
|
172
|
-
nio4r is not a full-featured event framework like EventMachine or Cool.io.
|
181
|
+
**nio4r** is not a full-featured event framework like [EventMachine] or [Cool.io].
|
173
182
|
Instead, nio4r is the sort of thing you might write a library like that on
|
174
183
|
top of. nio4r provides a minimal API such that individual Ruby implementers
|
175
184
|
may choose to produce optimized versions for their platform, without having
|
176
185
|
to maintain a large codebase.
|
177
186
|
|
178
|
-
|
179
|
-
|
180
|
-
* 200 lines of Ruby code
|
181
|
-
* 700 lines of "custom" C code (not counting libev)
|
182
|
-
* 400 lines of Java code
|
183
|
-
|
184
|
-
nio4r is also not a replacement for Kinder Gentler IO (KGIO), a set of
|
185
|
-
advanced Ruby IO APIs. At some point in the future nio4r might provide a
|
186
|
-
cross-platform implementation that uses KGIO on CRubies, and Java NIO on JRuby,
|
187
|
-
however this is not the case today.
|
187
|
+
[EventMachine]: https://github.com/eventmachine/eventmachine
|
188
|
+
[Cool.io]: https://coolio.github.io/
|
188
189
|
|
189
|
-
License
|
190
|
-
-------
|
190
|
+
## License
|
191
191
|
|
192
192
|
Copyright (c) 2011-2016 Tony Arcieri. Distributed under the MIT License.
|
193
193
|
See LICENSE.txt for further details.
|
data/Rakefile
CHANGED
data/examples/echo_server.rb
CHANGED
File without changes
|
data/ext/libev/ev.c
CHANGED
@@ -0,0 +1,413 @@
|
|
1
|
+
#include "nio4r.h"
|
2
|
+
|
3
|
+
static VALUE mNIO = Qnil;
|
4
|
+
static VALUE cNIO_ByteBuffer = Qnil;
|
5
|
+
|
6
|
+
/* Allocator/deallocator */
|
7
|
+
static VALUE NIO_ByteBuffer_allocate(VALUE klass);
|
8
|
+
static void NIO_ByteBuffer_mark(struct NIO_ByteBuffer *byteBuffer);
|
9
|
+
static void NIO_ByteBuffer_free(struct NIO_ByteBuffer *byteBuffer);
|
10
|
+
|
11
|
+
/* Methods */
|
12
|
+
static VALUE NIO_ByteBuffer_initialize(VALUE self, VALUE value, VALUE offset, VALUE length);
|
13
|
+
static VALUE NIO_ByteBuffer_put(VALUE self, VALUE string);
|
14
|
+
static VALUE NIO_ByteBuffer_get(VALUE self);
|
15
|
+
static VALUE NIO_ByteBuffer_readnext(VALUE self, VALUE amount);
|
16
|
+
static VALUE NIO_ByteBuffer_writeTo(VALUE self, VALUE file);
|
17
|
+
static VALUE NIO_ByteBuffer_readFrom(VALUE self, VALUE file);
|
18
|
+
static VALUE NIO_ByteBuffer_remaining(VALUE self);
|
19
|
+
static VALUE NIO_ByteBuffer_hasRemaining(VALUE self);
|
20
|
+
static VALUE NIO_ByteBuffer_getOffset(VALUE self);
|
21
|
+
static VALUE NIO_ByteBuffer_equals(VALUE self, VALUE other);
|
22
|
+
static VALUE NIO_ByteBuffer_flip(VALUE self);
|
23
|
+
static VALUE NIO_ByteBuffer_rewind(VALUE self);
|
24
|
+
static VALUE NIO_ByteBuffer_reset(VALUE self);
|
25
|
+
static VALUE NIO_ByteBuffer_markBuffer(VALUE self);
|
26
|
+
static VALUE NIO_ByteBuffer_clear(VALUE self);
|
27
|
+
static VALUE NIO_ByteBuffer_compact(VALUE self);
|
28
|
+
static VALUE NIO_ByteBuffer_capacity(VALUE self);
|
29
|
+
static VALUE NIO_ByteBuffer_position(VALUE self, VALUE newPosition);
|
30
|
+
static VALUE NIO_ByteBuffer_setLimit(VALUE self, VALUE newLimit);
|
31
|
+
static VALUE NIO_ByteBuffer_getLimit(VALUE self);
|
32
|
+
static VALUE NIO_ByteBuffer_toString(VALUE self);
|
33
|
+
|
34
|
+
void Init_NIO_ByteBuffer()
|
35
|
+
{
|
36
|
+
mNIO = rb_define_module("NIO");
|
37
|
+
cNIO_ByteBuffer = rb_define_class_under(mNIO, "ByteBuffer", rb_cObject);
|
38
|
+
rb_define_alloc_func(cNIO_ByteBuffer, NIO_ByteBuffer_allocate);
|
39
|
+
|
40
|
+
rb_define_method(cNIO_ByteBuffer, "initialize", NIO_ByteBuffer_initialize, 3);
|
41
|
+
rb_define_method(cNIO_ByteBuffer, "<<", NIO_ByteBuffer_put, 1);
|
42
|
+
rb_define_method(cNIO_ByteBuffer, "get", NIO_ByteBuffer_get, 0);
|
43
|
+
rb_define_method(cNIO_ByteBuffer, "read_next", NIO_ByteBuffer_readnext, 1);
|
44
|
+
rb_define_method(cNIO_ByteBuffer, "write_to", NIO_ByteBuffer_writeTo, 1);
|
45
|
+
rb_define_method(cNIO_ByteBuffer, "read_from", NIO_ByteBuffer_readFrom, 1);
|
46
|
+
rb_define_method(cNIO_ByteBuffer, "remaining", NIO_ByteBuffer_remaining, 0);
|
47
|
+
rb_define_method(cNIO_ByteBuffer, "remaining?", NIO_ByteBuffer_hasRemaining, 0);
|
48
|
+
rb_define_method(cNIO_ByteBuffer, "offset?", NIO_ByteBuffer_getOffset, 0);
|
49
|
+
rb_define_method(cNIO_ByteBuffer, "equals", NIO_ByteBuffer_equals, 1);
|
50
|
+
rb_define_method(cNIO_ByteBuffer, "flip", NIO_ByteBuffer_flip, 0);
|
51
|
+
rb_define_method(cNIO_ByteBuffer, "rewind", NIO_ByteBuffer_rewind, 0);
|
52
|
+
rb_define_method(cNIO_ByteBuffer, "reset", NIO_ByteBuffer_reset, 0);
|
53
|
+
rb_define_method(cNIO_ByteBuffer, "mark", NIO_ByteBuffer_markBuffer, 0);
|
54
|
+
rb_define_method(cNIO_ByteBuffer, "clear", NIO_ByteBuffer_clear, 0);
|
55
|
+
rb_define_method(cNIO_ByteBuffer, "compact", NIO_ByteBuffer_compact, 0);
|
56
|
+
rb_define_method(cNIO_ByteBuffer, "capacity", NIO_ByteBuffer_capacity, 0);
|
57
|
+
rb_define_method(cNIO_ByteBuffer, "position", NIO_ByteBuffer_position, 1);
|
58
|
+
rb_define_method(cNIO_ByteBuffer, "limit", NIO_ByteBuffer_setLimit, 1);
|
59
|
+
rb_define_method(cNIO_ByteBuffer, "limit?", NIO_ByteBuffer_getLimit, 0);
|
60
|
+
rb_define_method(cNIO_ByteBuffer, "to_s", NIO_ByteBuffer_toString, 0);
|
61
|
+
}
|
62
|
+
|
63
|
+
static VALUE NIO_ByteBuffer_allocate(VALUE klass)
|
64
|
+
{
|
65
|
+
struct NIO_ByteBuffer *bytebuffer = (struct NIO_ByteBuffer *)xmalloc(sizeof(struct NIO_ByteBuffer));
|
66
|
+
return Data_Wrap_Struct(klass, NIO_ByteBuffer_mark, NIO_ByteBuffer_free, bytebuffer);
|
67
|
+
}
|
68
|
+
|
69
|
+
static void NIO_ByteBuffer_mark(struct NIO_ByteBuffer *buffer)
|
70
|
+
{
|
71
|
+
}
|
72
|
+
|
73
|
+
static void NIO_ByteBuffer_free(struct NIO_ByteBuffer *buffer)
|
74
|
+
{
|
75
|
+
xfree(buffer);
|
76
|
+
}
|
77
|
+
|
78
|
+
static VALUE NIO_ByteBuffer_initialize(VALUE self, VALUE value, VALUE i_offset, VALUE i_length)
|
79
|
+
{
|
80
|
+
//Value can be either.
|
81
|
+
//NUM -> Size of the buffer
|
82
|
+
//STRING -> Data to be stored on the buffer
|
83
|
+
struct NIO_ByteBuffer *byteBuffer;
|
84
|
+
Data_Get_Struct(self, struct NIO_ByteBuffer, byteBuffer);
|
85
|
+
|
86
|
+
switch (TYPE(value)) {
|
87
|
+
case T_FIXNUM:
|
88
|
+
byteBuffer->size = NUM2INT(value);
|
89
|
+
byteBuffer->buffer = malloc(sizeof(char) * byteBuffer->size);
|
90
|
+
break;
|
91
|
+
case T_STRING:
|
92
|
+
byteBuffer->size = RSTRING_LEN(value);
|
93
|
+
byteBuffer->buffer = StringValuePtr(value);
|
94
|
+
//buffer = RSTRING_PTR(str);
|
95
|
+
break;
|
96
|
+
default:
|
97
|
+
/* raise exception */
|
98
|
+
rb_raise(rb_eTypeError, "not a valid input");
|
99
|
+
break;
|
100
|
+
}
|
101
|
+
|
102
|
+
byteBuffer->position = 0;
|
103
|
+
byteBuffer->offset = 0;
|
104
|
+
byteBuffer->limit = byteBuffer->size - 1;
|
105
|
+
byteBuffer->self = self;
|
106
|
+
|
107
|
+
if(i_offset != Qnil && TYPE(i_offset) == T_FIXNUM) {
|
108
|
+
byteBuffer->offset = NUM2INT(i_offset);
|
109
|
+
byteBuffer->position = byteBuffer->offset;
|
110
|
+
|
111
|
+
if(i_length != Qnil && TYPE(i_length) == T_FIXNUM) {
|
112
|
+
int length = NUM2INT(i_length);
|
113
|
+
|
114
|
+
if(byteBuffer->offset + length < byteBuffer->size) {
|
115
|
+
byteBuffer->limit = byteBuffer->offset + length;
|
116
|
+
} else {
|
117
|
+
rb_raise(rb_eRuntimeError, "Invalid Arguiments Exception");
|
118
|
+
}
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
if(byteBuffer->size == 0) {
|
123
|
+
rb_raise(rb_eRuntimeError, "Invalid Arguiments Exception");
|
124
|
+
}
|
125
|
+
|
126
|
+
return self;
|
127
|
+
}
|
128
|
+
|
129
|
+
static VALUE NIO_ByteBuffer_put(VALUE self, VALUE string)
|
130
|
+
{
|
131
|
+
struct NIO_ByteBuffer *byteBuffer;
|
132
|
+
Data_Get_Struct(self, struct NIO_ByteBuffer, byteBuffer);
|
133
|
+
|
134
|
+
if(TYPE(string) == T_STRING) {
|
135
|
+
char *temp = StringValuePtr(string);
|
136
|
+
int i = 0;
|
137
|
+
int limit = RSTRING_LEN(string);
|
138
|
+
|
139
|
+
for(byteBuffer->position; i < limit; byteBuffer->position++) {
|
140
|
+
byteBuffer->buffer[byteBuffer->position] = temp[i++];
|
141
|
+
}
|
142
|
+
}
|
143
|
+
|
144
|
+
return self;
|
145
|
+
}
|
146
|
+
|
147
|
+
static VALUE NIO_ByteBuffer_get(VALUE self)
|
148
|
+
{
|
149
|
+
struct NIO_ByteBuffer *byteBuffer;
|
150
|
+
Data_Get_Struct(self, struct NIO_ByteBuffer, byteBuffer);
|
151
|
+
|
152
|
+
int remaining = NUM2INT(NIO_ByteBuffer_remaining(self));
|
153
|
+
|
154
|
+
if(remaining == 0) {
|
155
|
+
return rb_str_new2("");
|
156
|
+
}
|
157
|
+
|
158
|
+
char tempArray[remaining+1];
|
159
|
+
int i = 0;
|
160
|
+
|
161
|
+
for(byteBuffer->position; byteBuffer->position <= byteBuffer->limit; byteBuffer->position++) {
|
162
|
+
tempArray[i++] = byteBuffer->buffer[byteBuffer->position];
|
163
|
+
}
|
164
|
+
|
165
|
+
tempArray[remaining] = '\0';
|
166
|
+
return rb_str_new2(tempArray);
|
167
|
+
}
|
168
|
+
|
169
|
+
static VALUE NIO_ByteBuffer_readnext(VALUE self, VALUE amount)
|
170
|
+
{
|
171
|
+
int amnt = NUM2INT(amount);
|
172
|
+
if(amnt < 1) {
|
173
|
+
rb_raise(rb_eTypeError, "not a valid input");
|
174
|
+
}
|
175
|
+
|
176
|
+
if(amnt > NUM2INT(NIO_ByteBuffer_remaining(self))) {
|
177
|
+
rb_raise(rb_eTypeError, "Less number of elements remaining");
|
178
|
+
}
|
179
|
+
|
180
|
+
char tempArray[amnt+1];
|
181
|
+
int c = 0;
|
182
|
+
struct NIO_ByteBuffer *byteBuffer;
|
183
|
+
Data_Get_Struct(self, struct NIO_ByteBuffer, byteBuffer);
|
184
|
+
|
185
|
+
while(c < amnt) {
|
186
|
+
tempArray[c++] = byteBuffer->buffer[byteBuffer->position];
|
187
|
+
byteBuffer->position++;
|
188
|
+
}
|
189
|
+
|
190
|
+
tempArray[amnt] = '\0';
|
191
|
+
return rb_str_new2(tempArray);
|
192
|
+
}
|
193
|
+
|
194
|
+
static VALUE NIO_ByteBuffer_writeTo(VALUE self, VALUE io)
|
195
|
+
{
|
196
|
+
struct NIO_ByteBuffer *byteBuffer;
|
197
|
+
Data_Get_Struct(self, struct NIO_ByteBuffer, byteBuffer);
|
198
|
+
int size = byteBuffer->limit + 1 - byteBuffer->position;
|
199
|
+
|
200
|
+
#if HAVE_RB_IO_T
|
201
|
+
rb_io_t *fptr;
|
202
|
+
#else
|
203
|
+
OpenFile *fptr;
|
204
|
+
#endif
|
205
|
+
|
206
|
+
GetOpenFile(rb_convert_type(io, T_FILE, "IO", "to_io"), fptr);
|
207
|
+
rb_io_set_nonblock(fptr);
|
208
|
+
|
209
|
+
VALUE content = NIO_ByteBuffer_get(self);
|
210
|
+
char* contentAsPointer = StringValuePtr(content);
|
211
|
+
|
212
|
+
write(FPTR_TO_FD(fptr), contentAsPointer , size);
|
213
|
+
|
214
|
+
return self;
|
215
|
+
}
|
216
|
+
|
217
|
+
static VALUE NIO_ByteBuffer_readFrom(VALUE self, VALUE io)
|
218
|
+
{
|
219
|
+
struct NIO_ByteBuffer *byteBuffer;
|
220
|
+
Data_Get_Struct(self, struct NIO_ByteBuffer, byteBuffer);
|
221
|
+
int size = byteBuffer->limit + 1 - byteBuffer->position;
|
222
|
+
|
223
|
+
#if HAVE_RB_IO_T
|
224
|
+
rb_io_t *fptr;
|
225
|
+
#else
|
226
|
+
OpenFile *fptr;
|
227
|
+
#endif
|
228
|
+
|
229
|
+
GetOpenFile(rb_convert_type(io, T_FILE, "IO", "to_io"), fptr);
|
230
|
+
rb_io_set_nonblock(fptr);
|
231
|
+
|
232
|
+
while(NIO_ByteBuffer_hasRemaining(self) == Qtrue) {
|
233
|
+
char* nextByte;
|
234
|
+
read(FPTR_TO_FD(fptr), &nextByte, 1);
|
235
|
+
VALUE byte = rb_str_new2(nextByte);
|
236
|
+
NIO_ByteBuffer_put(self, byte);
|
237
|
+
}
|
238
|
+
|
239
|
+
return self;
|
240
|
+
}
|
241
|
+
|
242
|
+
static VALUE NIO_ByteBuffer_remaining(VALUE self)
|
243
|
+
{
|
244
|
+
struct NIO_ByteBuffer *byteBuffer;
|
245
|
+
Data_Get_Struct(self, struct NIO_ByteBuffer, byteBuffer);
|
246
|
+
|
247
|
+
return INT2NUM(byteBuffer->limit + 1 - byteBuffer->position);
|
248
|
+
}
|
249
|
+
|
250
|
+
static VALUE NIO_ByteBuffer_hasRemaining(VALUE self)
|
251
|
+
{
|
252
|
+
struct NIO_ByteBuffer *byteBuffer;
|
253
|
+
Data_Get_Struct(self, struct NIO_ByteBuffer, byteBuffer);
|
254
|
+
|
255
|
+
return ((byteBuffer->limit + 1 - byteBuffer->position) > 0) ? Qtrue : Qfalse;
|
256
|
+
}
|
257
|
+
|
258
|
+
static VALUE NIO_ByteBuffer_getOffset(VALUE self)
|
259
|
+
{
|
260
|
+
struct NIO_ByteBuffer *byteBuffer;
|
261
|
+
Data_Get_Struct(self, struct NIO_ByteBuffer, byteBuffer);
|
262
|
+
return INT2NUM(byteBuffer->offset);
|
263
|
+
}
|
264
|
+
|
265
|
+
static VALUE NIO_ByteBuffer_equals(VALUE self, VALUE other)
|
266
|
+
{
|
267
|
+
return self == other ? Qtrue : Qfalse;
|
268
|
+
}
|
269
|
+
|
270
|
+
static VALUE NIO_ByteBuffer_flip(VALUE self)
|
271
|
+
{
|
272
|
+
struct NIO_ByteBuffer *byteBuffer;
|
273
|
+
Data_Get_Struct(self, struct NIO_ByteBuffer, byteBuffer);
|
274
|
+
|
275
|
+
byteBuffer->limit = (byteBuffer->position > 0) ? byteBuffer->position - 1 : 0;
|
276
|
+
byteBuffer->position = 0;
|
277
|
+
byteBuffer->mark = -1;
|
278
|
+
|
279
|
+
return self;
|
280
|
+
}
|
281
|
+
|
282
|
+
static VALUE NIO_ByteBuffer_rewind(VALUE self)
|
283
|
+
{
|
284
|
+
struct NIO_ByteBuffer *byteBuffer;
|
285
|
+
Data_Get_Struct(self, struct NIO_ByteBuffer, byteBuffer);
|
286
|
+
|
287
|
+
byteBuffer->position = 0;
|
288
|
+
byteBuffer->mark = -1;
|
289
|
+
|
290
|
+
return self;
|
291
|
+
}
|
292
|
+
|
293
|
+
static VALUE NIO_ByteBuffer_reset(VALUE self)
|
294
|
+
{
|
295
|
+
struct NIO_ByteBuffer *byteBuffer;
|
296
|
+
Data_Get_Struct(self, struct NIO_ByteBuffer, byteBuffer);
|
297
|
+
|
298
|
+
if(byteBuffer->mark < 0){
|
299
|
+
rb_raise(rb_eRuntimeError, "Invalid Mark Exception");
|
300
|
+
} else {
|
301
|
+
byteBuffer->position = byteBuffer->mark;
|
302
|
+
}
|
303
|
+
|
304
|
+
return self;
|
305
|
+
}
|
306
|
+
|
307
|
+
static VALUE NIO_ByteBuffer_markBuffer(VALUE self)
|
308
|
+
{
|
309
|
+
struct NIO_ByteBuffer *byteBuffer;
|
310
|
+
Data_Get_Struct(self, struct NIO_ByteBuffer, byteBuffer);
|
311
|
+
|
312
|
+
byteBuffer->mark = byteBuffer->position;
|
313
|
+
return self;
|
314
|
+
}
|
315
|
+
|
316
|
+
static VALUE NIO_ByteBuffer_clear(VALUE self)
|
317
|
+
{
|
318
|
+
struct NIO_ByteBuffer *byteBuffer;
|
319
|
+
Data_Get_Struct(self, struct NIO_ByteBuffer, byteBuffer);
|
320
|
+
|
321
|
+
byteBuffer->position = 0;
|
322
|
+
byteBuffer->limit = byteBuffer->size - 1;
|
323
|
+
byteBuffer->mark = -1;
|
324
|
+
|
325
|
+
return self;
|
326
|
+
}
|
327
|
+
|
328
|
+
static VALUE NIO_ByteBuffer_compact(VALUE self)
|
329
|
+
{
|
330
|
+
struct NIO_ByteBuffer *byteBuffer;
|
331
|
+
Data_Get_Struct(self, struct NIO_ByteBuffer, byteBuffer);
|
332
|
+
|
333
|
+
if(NIO_ByteBuffer_hasRemaining(self) == Qtrue) {
|
334
|
+
//move content
|
335
|
+
int i = 0, j = byteBuffer->position;
|
336
|
+
for(j = byteBuffer->position; j <= byteBuffer->limit; j++) {
|
337
|
+
byteBuffer->buffer[i++] = byteBuffer->buffer[j];
|
338
|
+
}
|
339
|
+
|
340
|
+
byteBuffer->position = i;
|
341
|
+
byteBuffer->limit = byteBuffer->size - 1;
|
342
|
+
}
|
343
|
+
|
344
|
+
return self;
|
345
|
+
}
|
346
|
+
|
347
|
+
static VALUE NIO_ByteBuffer_capacity(VALUE self)
|
348
|
+
{
|
349
|
+
struct NIO_ByteBuffer *byteBuffer;
|
350
|
+
Data_Get_Struct(self, struct NIO_ByteBuffer, byteBuffer);
|
351
|
+
|
352
|
+
return INT2NUM(byteBuffer->size);
|
353
|
+
}
|
354
|
+
|
355
|
+
static VALUE NIO_ByteBuffer_position(VALUE self, VALUE newposition)
|
356
|
+
{
|
357
|
+
struct NIO_ByteBuffer *byteBuffer;
|
358
|
+
Data_Get_Struct(self, struct NIO_ByteBuffer, byteBuffer);
|
359
|
+
|
360
|
+
int newPosition = NUM2INT(newposition);
|
361
|
+
|
362
|
+
if(newPosition < 0 || newPosition > byteBuffer->limit) {
|
363
|
+
rb_raise(rb_eRuntimeError, "Illegal Argument Exception");
|
364
|
+
} else {
|
365
|
+
byteBuffer->position = newPosition;
|
366
|
+
|
367
|
+
if(byteBuffer->mark > newPosition) {
|
368
|
+
byteBuffer->mark = -1;
|
369
|
+
}
|
370
|
+
}
|
371
|
+
return self;
|
372
|
+
}
|
373
|
+
|
374
|
+
static VALUE NIO_ByteBuffer_setLimit(VALUE self, VALUE newlimit)
|
375
|
+
{
|
376
|
+
struct NIO_ByteBuffer *byteBuffer;
|
377
|
+
Data_Get_Struct(self, struct NIO_ByteBuffer, byteBuffer);
|
378
|
+
|
379
|
+
int newLimit = NUM2INT(newlimit);
|
380
|
+
|
381
|
+
if(newLimit < byteBuffer->size && newLimit >= 0)
|
382
|
+
{
|
383
|
+
byteBuffer->limit = newLimit;
|
384
|
+
|
385
|
+
if(byteBuffer->position > byteBuffer->limit) {
|
386
|
+
byteBuffer->position = newLimit;
|
387
|
+
}
|
388
|
+
|
389
|
+
if(byteBuffer->mark > byteBuffer->limit) {
|
390
|
+
byteBuffer->mark = -1;
|
391
|
+
}
|
392
|
+
} else {
|
393
|
+
rb_raise(rb_eRuntimeError, "Illegal Argument Exception");
|
394
|
+
}
|
395
|
+
|
396
|
+
return self;
|
397
|
+
}
|
398
|
+
|
399
|
+
static VALUE NIO_ByteBuffer_getLimit(VALUE self)
|
400
|
+
{
|
401
|
+
struct NIO_ByteBuffer *byteBuffer;
|
402
|
+
Data_Get_Struct(self, struct NIO_ByteBuffer, byteBuffer);
|
403
|
+
|
404
|
+
return INT2NUM(byteBuffer->limit);
|
405
|
+
}
|
406
|
+
|
407
|
+
static VALUE NIO_ByteBuffer_toString(VALUE self)
|
408
|
+
{
|
409
|
+
struct NIO_ByteBuffer *byteBuffer;
|
410
|
+
Data_Get_Struct(self, struct NIO_ByteBuffer, byteBuffer);
|
411
|
+
|
412
|
+
return rb_sprintf ("ByteBuffer [pos=%d lim=%d cap=%d]\n", byteBuffer->position, byteBuffer->limit, byteBuffer->size);
|
413
|
+
}
|
data/ext/nio4r/nio4r.h
CHANGED
@@ -41,6 +41,14 @@ struct NIO_Monitor
|
|
41
41
|
struct NIO_Selector *selector;
|
42
42
|
};
|
43
43
|
|
44
|
+
struct NIO_ByteBuffer
|
45
|
+
{
|
46
|
+
int size, offset, limit, position, mark;
|
47
|
+
char *buffer;
|
48
|
+
VALUE self;
|
49
|
+
};
|
50
|
+
|
51
|
+
|
44
52
|
#ifdef GetReadFile
|
45
53
|
# define FPTR_TO_FD(fptr) (fileno(GetReadFile(fptr)))
|
46
54
|
#else
|