nio4r 1.2.1 → 2.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
![nio4r](https://raw.github.com/celluloid/nio4r/master/logo.png)
|
2
|
-
|
1
|
+
# ![nio4r](https://raw.github.com/celluloid/nio4r/master/logo.png)
|
2
|
+
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/nio4r.svg)](http://rubygems.org/gems/nio4r)
|
4
4
|
[![Build Status](https://secure.travis-ci.org/celluloid/nio4r.svg?branch=master)](http://travis-ci.org/celluloid/nio4r)
|
5
5
|
[![Code Climate](https://codeclimate.com/github/celluloid/nio4r.svg)](https://codeclimate.com/github/celluloid/nio4r)
|
6
6
|
[![Coverage Status](https://coveralls.io/repos/celluloid/nio4r/badge.svg?branch=master)](https://coveralls.io/r/celluloid/nio4r)
|
7
7
|
[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](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
|