nio4r 1.2.1 → 2.5.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/workflow.yml +43 -0
  3. data/.gitignore +1 -0
  4. data/.rspec +0 -1
  5. data/.rubocop.yml +70 -31
  6. data/CHANGES.md +190 -42
  7. data/Gemfile +8 -4
  8. data/Guardfile +10 -0
  9. data/README.md +102 -147
  10. data/Rakefile +3 -4
  11. data/examples/echo_server.rb +3 -2
  12. data/ext/libev/Changes +44 -13
  13. data/ext/libev/README +2 -1
  14. data/ext/libev/ev.c +314 -225
  15. data/ext/libev/ev.h +90 -88
  16. data/ext/libev/ev_epoll.c +30 -16
  17. data/ext/libev/ev_kqueue.c +19 -9
  18. data/ext/libev/ev_linuxaio.c +642 -0
  19. data/ext/libev/ev_poll.c +19 -11
  20. data/ext/libev/ev_port.c +13 -6
  21. data/ext/libev/ev_select.c +4 -2
  22. data/ext/libev/ev_vars.h +14 -3
  23. data/ext/libev/ev_wrap.h +16 -0
  24. data/ext/nio4r/bytebuffer.c +429 -0
  25. data/ext/nio4r/extconf.rb +17 -30
  26. data/ext/nio4r/monitor.c +113 -49
  27. data/ext/nio4r/nio4r.h +11 -13
  28. data/ext/nio4r/org/nio4r/ByteBuffer.java +293 -0
  29. data/ext/nio4r/org/nio4r/Monitor.java +175 -0
  30. data/ext/nio4r/org/nio4r/Nio4r.java +22 -391
  31. data/ext/nio4r/org/nio4r/Selector.java +299 -0
  32. data/ext/nio4r/selector.c +155 -68
  33. data/lib/nio.rb +4 -4
  34. data/lib/nio/bytebuffer.rb +229 -0
  35. data/lib/nio/monitor.rb +73 -11
  36. data/lib/nio/selector.rb +64 -21
  37. data/lib/nio/version.rb +1 -1
  38. data/nio4r.gemspec +34 -20
  39. data/{tasks → rakelib}/extension.rake +4 -0
  40. data/{tasks → rakelib}/rspec.rake +2 -0
  41. data/{tasks → rakelib}/rubocop.rake +2 -0
  42. data/spec/nio/acceptables_spec.rb +5 -5
  43. data/spec/nio/bytebuffer_spec.rb +354 -0
  44. data/spec/nio/monitor_spec.rb +128 -79
  45. data/spec/nio/selectables/pipe_spec.rb +12 -3
  46. data/spec/nio/selectables/ssl_socket_spec.rb +61 -29
  47. data/spec/nio/selectables/tcp_socket_spec.rb +47 -34
  48. data/spec/nio/selectables/udp_socket_spec.rb +24 -7
  49. data/spec/nio/selector_spec.rb +65 -16
  50. data/spec/spec_helper.rb +12 -3
  51. data/spec/support/selectable_examples.rb +45 -18
  52. metadata +33 -23
  53. data/.rubocop_todo.yml +0 -35
  54. data/.travis.yml +0 -27
  55. data/LICENSE.txt +0 -20
  56. data/ext/libev/README.embed +0 -3
  57. data/ext/libev/test_libev_win32.c +0 -123
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * libev poll fd activity backend
3
3
  *
4
- * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmorp.de>
4
+ * Copyright (c) 2007,2008,2009,2010,2011,2016,2019 Marc Alexander Lehmann <libev@schmorp.de>
5
5
  * All rights reserved.
6
6
  *
7
7
  * Redistribution and use in source and binary forms, with or without modifica-
@@ -39,11 +39,14 @@
39
39
 
40
40
  #include <poll.h>
41
41
 
42
- void inline_size
43
- pollidx_init (int *base, int count)
42
+ inline_size
43
+ void
44
+ array_needsize_pollidx (int *base, int offset, int count)
44
45
  {
45
- /* consider using memset (.., -1, ...), which is practically guaranteed
46
- * to work on all systems implementing poll */
46
+ /* using memset (.., -1, ...) is tempting, we we try
47
+ * to be ultraportable
48
+ */
49
+ base += offset;
47
50
  while (count--)
48
51
  *base++ = -1;
49
52
  }
@@ -56,14 +59,14 @@ poll_modify (EV_P_ int fd, int oev, int nev)
56
59
  if (oev == nev)
57
60
  return;
58
61
 
59
- array_needsize (int, pollidxs, pollidxmax, fd + 1, pollidx_init);
62
+ array_needsize (int, pollidxs, pollidxmax, fd + 1, array_needsize_pollidx);
60
63
 
61
64
  idx = pollidxs [fd];
62
65
 
63
66
  if (idx < 0) /* need to allocate a new pollfd */
64
67
  {
65
68
  pollidxs [fd] = idx = pollcnt++;
66
- array_needsize (struct pollfd, polls, pollmax, pollcnt, EMPTY2);
69
+ array_needsize (struct pollfd, polls, pollmax, pollcnt, array_needsize_noinit);
67
70
  polls [idx].fd = fd;
68
71
  }
69
72
 
@@ -107,14 +110,17 @@ poll_poll (EV_P_ ev_tstamp timeout)
107
110
  else
108
111
  for (p = polls; res; ++p)
109
112
  {
110
- assert (("libev: poll() returned illegal result, broken BSD kernel?", p < polls + pollcnt));
113
+ assert (("libev: poll returned illegal result, broken BSD kernel?", p < polls + pollcnt));
111
114
 
112
115
  if (expect_false (p->revents)) /* this expect is debatable */
113
116
  {
114
117
  --res;
115
118
 
116
119
  if (expect_false (p->revents & POLLNVAL))
117
- fd_kill (EV_A_ p->fd);
120
+ {
121
+ assert (("libev: poll found invalid fd in poll set", 0));
122
+ fd_kill (EV_A_ p->fd);
123
+ }
118
124
  else
119
125
  fd_event (
120
126
  EV_A_
@@ -126,7 +132,8 @@ poll_poll (EV_P_ ev_tstamp timeout)
126
132
  }
127
133
  }
128
134
 
129
- int inline_size
135
+ inline_size
136
+ int
130
137
  poll_init (EV_P_ int flags)
131
138
  {
132
139
  backend_mintime = 1e-3;
@@ -139,7 +146,8 @@ poll_init (EV_P_ int flags)
139
146
  return EVBACKEND_POLL;
140
147
  }
141
148
 
142
- void inline_size
149
+ inline_size
150
+ void
143
151
  poll_destroy (EV_P)
144
152
  {
145
153
  ev_free (pollidxs);
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * libev solaris event port backend
3
3
  *
4
- * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmorp.de>
4
+ * Copyright (c) 2007,2008,2009,2010,2011,2019 Marc Alexander Lehmann <libev@schmorp.de>
5
5
  * All rights reserved.
6
6
  *
7
7
  * Redistribution and use in source and binary forms, with or without modifica-
@@ -55,7 +55,8 @@
55
55
  #include <string.h>
56
56
  #include <errno.h>
57
57
 
58
- void inline_speed
58
+ inline_speed
59
+ void
59
60
  port_associate_and_check (EV_P_ int fd, int ev)
60
61
  {
61
62
  if (0 >
@@ -68,7 +69,10 @@ port_associate_and_check (EV_P_ int fd, int ev)
68
69
  )
69
70
  {
70
71
  if (errno == EBADFD)
71
- fd_kill (EV_A_ fd);
72
+ {
73
+ assert (("libev: port_associate found invalid fd", errno != EBADFD));
74
+ fd_kill (EV_A_ fd);
75
+ }
72
76
  else
73
77
  ev_syserr ("(libev) port_associate");
74
78
  }
@@ -136,7 +140,8 @@ port_poll (EV_P_ ev_tstamp timeout)
136
140
  }
137
141
  }
138
142
 
139
- int inline_size
143
+ inline_size
144
+ int
140
145
  port_init (EV_P_ int flags)
141
146
  {
142
147
  /* Initialize the kernel queue */
@@ -163,13 +168,15 @@ port_init (EV_P_ int flags)
163
168
  return EVBACKEND_PORT;
164
169
  }
165
170
 
166
- void inline_size
171
+ inline_size
172
+ void
167
173
  port_destroy (EV_P)
168
174
  {
169
175
  ev_free (port_events);
170
176
  }
171
177
 
172
- void inline_size
178
+ inline_size
179
+ void
173
180
  port_fork (EV_P)
174
181
  {
175
182
  close (backend_fd);
@@ -271,7 +271,8 @@ select_poll (EV_P_ ev_tstamp timeout)
271
271
  #endif
272
272
  }
273
273
 
274
- int inline_size
274
+ inline_size
275
+ int
275
276
  select_init (EV_P_ int flags)
276
277
  {
277
278
  backend_mintime = 1e-6;
@@ -300,7 +301,8 @@ select_init (EV_P_ int flags)
300
301
  return EVBACKEND_SELECT;
301
302
  }
302
303
 
303
- void inline_size
304
+ inline_size
305
+ void
304
306
  select_destroy (EV_P)
305
307
  {
306
308
  ev_free (vec_ri);
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * loop member variable declarations
3
3
  *
4
- * Copyright (c) 2007,2008,2009,2010,2011,2012,2013 Marc Alexander Lehmann <libev@schmorp.de>
4
+ * Copyright (c) 2007,2008,2009,2010,2011,2012,2013,2019 Marc Alexander Lehmann <libev@schmorp.de>
5
5
  * All rights reserved.
6
6
  *
7
7
  * Redistribution and use in source and binary forms, with or without modifica-
@@ -107,6 +107,17 @@ VARx(int, epoll_epermcnt)
107
107
  VARx(int, epoll_epermmax)
108
108
  #endif
109
109
 
110
+ #if EV_USE_LINUXAIO || EV_GENWRAP
111
+ VARx(aio_context_t, linuxaio_ctx)
112
+ VARx(int, linuxaio_iteration)
113
+ VARx(struct aniocb **, linuxaio_iocbps)
114
+ VARx(int, linuxaio_iocbpmax)
115
+ VARx(struct iocb **, linuxaio_submits)
116
+ VARx(int, linuxaio_submitcnt)
117
+ VARx(int, linuxaio_submitmax)
118
+ VARx(ev_io, linuxaio_epoll_w)
119
+ #endif
120
+
110
121
  #if EV_USE_KQUEUE || EV_GENWRAP
111
122
  VARx(pid_t, kqueue_fd_pid)
112
123
  VARx(struct kevent *, kqueue_changes)
@@ -195,8 +206,8 @@ VARx(unsigned int, loop_depth) /* #ev_run enters - #ev_run leaves */
195
206
 
196
207
  VARx(void *, userdata)
197
208
  /* C++ doesn't support the ev_loop_callback typedef here. stinks. */
198
- VAR (release_cb, void (*release_cb)(EV_P) EV_THROW)
199
- VAR (acquire_cb, void (*acquire_cb)(EV_P) EV_THROW)
209
+ VAR (release_cb, void (*release_cb)(EV_P) EV_NOEXCEPT)
210
+ VAR (acquire_cb, void (*acquire_cb)(EV_P) EV_NOEXCEPT)
200
211
  VAR (invoke_cb , ev_loop_callback invoke_cb)
201
212
  #endif
202
213
 
@@ -50,6 +50,14 @@
50
50
  #define kqueue_eventmax ((loop)->kqueue_eventmax)
51
51
  #define kqueue_events ((loop)->kqueue_events)
52
52
  #define kqueue_fd_pid ((loop)->kqueue_fd_pid)
53
+ #define linuxaio_ctx ((loop)->linuxaio_ctx)
54
+ #define linuxaio_epoll_w ((loop)->linuxaio_epoll_w)
55
+ #define linuxaio_iocbpmax ((loop)->linuxaio_iocbpmax)
56
+ #define linuxaio_iocbps ((loop)->linuxaio_iocbps)
57
+ #define linuxaio_iteration ((loop)->linuxaio_iteration)
58
+ #define linuxaio_submitcnt ((loop)->linuxaio_submitcnt)
59
+ #define linuxaio_submitmax ((loop)->linuxaio_submitmax)
60
+ #define linuxaio_submits ((loop)->linuxaio_submits)
53
61
  #define loop_count ((loop)->loop_count)
54
62
  #define loop_depth ((loop)->loop_depth)
55
63
  #define loop_done ((loop)->loop_done)
@@ -149,6 +157,14 @@
149
157
  #undef kqueue_eventmax
150
158
  #undef kqueue_events
151
159
  #undef kqueue_fd_pid
160
+ #undef linuxaio_ctx
161
+ #undef linuxaio_epoll_w
162
+ #undef linuxaio_iocbpmax
163
+ #undef linuxaio_iocbps
164
+ #undef linuxaio_iteration
165
+ #undef linuxaio_submitcnt
166
+ #undef linuxaio_submitmax
167
+ #undef linuxaio_submits
152
168
  #undef loop_count
153
169
  #undef loop_depth
154
170
  #undef loop_done
@@ -0,0 +1,429 @@
1
+ #include "nio4r.h"
2
+
3
+ static VALUE mNIO = Qnil;
4
+ static VALUE cNIO_ByteBuffer = Qnil;
5
+ static VALUE cNIO_ByteBuffer_OverflowError = Qnil;
6
+ static VALUE cNIO_ByteBuffer_UnderflowError = Qnil;
7
+ static VALUE cNIO_ByteBuffer_MarkUnsetError = Qnil;
8
+
9
+ /* Allocator/deallocator */
10
+ static VALUE NIO_ByteBuffer_allocate(VALUE klass);
11
+ static void NIO_ByteBuffer_gc_mark(struct NIO_ByteBuffer *byteBuffer);
12
+ static void NIO_ByteBuffer_free(struct NIO_ByteBuffer *byteBuffer);
13
+
14
+ /* Methods */
15
+ static VALUE NIO_ByteBuffer_initialize(VALUE self, VALUE capacity);
16
+ static VALUE NIO_ByteBuffer_clear(VALUE self);
17
+ static VALUE NIO_ByteBuffer_get_position(VALUE self);
18
+ static VALUE NIO_ByteBuffer_set_position(VALUE self, VALUE new_position);
19
+ static VALUE NIO_ByteBuffer_get_limit(VALUE self);
20
+ static VALUE NIO_ByteBuffer_set_limit(VALUE self, VALUE new_limit);
21
+ static VALUE NIO_ByteBuffer_capacity(VALUE self);
22
+ static VALUE NIO_ByteBuffer_remaining(VALUE self);
23
+ static VALUE NIO_ByteBuffer_full(VALUE self);
24
+ static VALUE NIO_ByteBuffer_get(int argc, VALUE *argv, VALUE self);
25
+ static VALUE NIO_ByteBuffer_fetch(VALUE self, VALUE index);
26
+ static VALUE NIO_ByteBuffer_put(VALUE self, VALUE string);
27
+ static VALUE NIO_ByteBuffer_write_to(VALUE self, VALUE file);
28
+ static VALUE NIO_ByteBuffer_read_from(VALUE self, VALUE file);
29
+ static VALUE NIO_ByteBuffer_flip(VALUE self);
30
+ static VALUE NIO_ByteBuffer_rewind(VALUE self);
31
+ static VALUE NIO_ByteBuffer_mark(VALUE self);
32
+ static VALUE NIO_ByteBuffer_reset(VALUE self);
33
+ static VALUE NIO_ByteBuffer_compact(VALUE self);
34
+ static VALUE NIO_ByteBuffer_each(VALUE self);
35
+ static VALUE NIO_ByteBuffer_inspect(VALUE self);
36
+
37
+ #define MARK_UNSET -1
38
+
39
+ void Init_NIO_ByteBuffer()
40
+ {
41
+ mNIO = rb_define_module("NIO");
42
+ cNIO_ByteBuffer = rb_define_class_under(mNIO, "ByteBuffer", rb_cObject);
43
+ rb_define_alloc_func(cNIO_ByteBuffer, NIO_ByteBuffer_allocate);
44
+
45
+ cNIO_ByteBuffer_OverflowError = rb_define_class_under(cNIO_ByteBuffer, "OverflowError", rb_eIOError);
46
+ cNIO_ByteBuffer_UnderflowError = rb_define_class_under(cNIO_ByteBuffer, "UnderflowError", rb_eIOError);
47
+ cNIO_ByteBuffer_MarkUnsetError = rb_define_class_under(cNIO_ByteBuffer, "MarkUnsetError", rb_eIOError);
48
+
49
+ rb_include_module(cNIO_ByteBuffer, rb_mEnumerable);
50
+
51
+ rb_define_method(cNIO_ByteBuffer, "initialize", NIO_ByteBuffer_initialize, 1);
52
+ rb_define_method(cNIO_ByteBuffer, "clear", NIO_ByteBuffer_clear, 0);
53
+ rb_define_method(cNIO_ByteBuffer, "position", NIO_ByteBuffer_get_position, 0);
54
+ rb_define_method(cNIO_ByteBuffer, "position=", NIO_ByteBuffer_set_position, 1);
55
+ rb_define_method(cNIO_ByteBuffer, "limit", NIO_ByteBuffer_get_limit, 0);
56
+ rb_define_method(cNIO_ByteBuffer, "limit=", NIO_ByteBuffer_set_limit, 1);
57
+ rb_define_method(cNIO_ByteBuffer, "capacity", NIO_ByteBuffer_capacity, 0);
58
+ rb_define_method(cNIO_ByteBuffer, "size", NIO_ByteBuffer_capacity, 0);
59
+ rb_define_method(cNIO_ByteBuffer, "remaining", NIO_ByteBuffer_remaining, 0);
60
+ rb_define_method(cNIO_ByteBuffer, "full?", NIO_ByteBuffer_full, 0);
61
+ rb_define_method(cNIO_ByteBuffer, "get", NIO_ByteBuffer_get, -1);
62
+ rb_define_method(cNIO_ByteBuffer, "[]", NIO_ByteBuffer_fetch, 1);
63
+ rb_define_method(cNIO_ByteBuffer, "<<", NIO_ByteBuffer_put, 1);
64
+ rb_define_method(cNIO_ByteBuffer, "read_from", NIO_ByteBuffer_read_from, 1);
65
+ rb_define_method(cNIO_ByteBuffer, "write_to", NIO_ByteBuffer_write_to, 1);
66
+ rb_define_method(cNIO_ByteBuffer, "flip", NIO_ByteBuffer_flip, 0);
67
+ rb_define_method(cNIO_ByteBuffer, "rewind", NIO_ByteBuffer_rewind, 0);
68
+ rb_define_method(cNIO_ByteBuffer, "mark", NIO_ByteBuffer_mark, 0);
69
+ rb_define_method(cNIO_ByteBuffer, "reset", NIO_ByteBuffer_reset, 0);
70
+ rb_define_method(cNIO_ByteBuffer, "compact", NIO_ByteBuffer_compact, 0);
71
+ rb_define_method(cNIO_ByteBuffer, "each", NIO_ByteBuffer_each, 0);
72
+ rb_define_method(cNIO_ByteBuffer, "inspect", NIO_ByteBuffer_inspect, 0);
73
+ }
74
+
75
+ static VALUE NIO_ByteBuffer_allocate(VALUE klass)
76
+ {
77
+ struct NIO_ByteBuffer *bytebuffer = (struct NIO_ByteBuffer *)xmalloc(sizeof(struct NIO_ByteBuffer));
78
+ bytebuffer->buffer = NULL;
79
+ return Data_Wrap_Struct(klass, NIO_ByteBuffer_gc_mark, NIO_ByteBuffer_free, bytebuffer);
80
+ }
81
+
82
+ static void NIO_ByteBuffer_gc_mark(struct NIO_ByteBuffer *buffer)
83
+ {
84
+ }
85
+
86
+ static void NIO_ByteBuffer_free(struct NIO_ByteBuffer *buffer)
87
+ {
88
+ if(buffer->buffer)
89
+ xfree(buffer->buffer);
90
+ xfree(buffer);
91
+ }
92
+
93
+ static VALUE NIO_ByteBuffer_initialize(VALUE self, VALUE capacity)
94
+ {
95
+ struct NIO_ByteBuffer *buffer;
96
+ Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
97
+
98
+ buffer->capacity = NUM2INT(capacity);
99
+ buffer->buffer = xmalloc(buffer->capacity);
100
+
101
+ NIO_ByteBuffer_clear(self);
102
+
103
+ return self;
104
+ }
105
+
106
+ static VALUE NIO_ByteBuffer_clear(VALUE self)
107
+ {
108
+ struct NIO_ByteBuffer *buffer;
109
+ Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
110
+
111
+ memset(buffer->buffer, 0, buffer->capacity);
112
+
113
+ buffer->position = 0;
114
+ buffer->limit = buffer->capacity;
115
+ buffer->mark = MARK_UNSET;
116
+
117
+ return self;
118
+ }
119
+
120
+ static VALUE NIO_ByteBuffer_get_position(VALUE self)
121
+ {
122
+ struct NIO_ByteBuffer *buffer;
123
+ Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
124
+
125
+ return INT2NUM(buffer->position);
126
+ }
127
+
128
+ static VALUE NIO_ByteBuffer_set_position(VALUE self, VALUE new_position)
129
+ {
130
+ int pos;
131
+ struct NIO_ByteBuffer *buffer;
132
+ Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
133
+
134
+ pos = NUM2INT(new_position);
135
+
136
+ if(pos < 0) {
137
+ rb_raise(rb_eArgError, "negative position given");
138
+ }
139
+
140
+ if(pos > buffer->limit) {
141
+ rb_raise(rb_eArgError, "specified position exceeds limit");
142
+ }
143
+
144
+ buffer->position = pos;
145
+
146
+ if(buffer->mark > buffer->position) {
147
+ buffer->mark = MARK_UNSET;
148
+ }
149
+
150
+ return new_position;
151
+ }
152
+
153
+ static VALUE NIO_ByteBuffer_get_limit(VALUE self)
154
+ {
155
+ struct NIO_ByteBuffer *buffer;
156
+ Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
157
+
158
+ return INT2NUM(buffer->limit);
159
+ }
160
+
161
+ static VALUE NIO_ByteBuffer_set_limit(VALUE self, VALUE new_limit)
162
+ {
163
+ int lim;
164
+ struct NIO_ByteBuffer *buffer;
165
+ Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
166
+
167
+ lim = NUM2INT(new_limit);
168
+
169
+ if(lim < 0) {
170
+ rb_raise(rb_eArgError, "negative limit given");
171
+ }
172
+
173
+ if(lim > buffer->capacity) {
174
+ rb_raise(rb_eArgError, "specified limit exceeds capacity");
175
+ }
176
+
177
+ buffer->limit = lim;
178
+
179
+ if(buffer->position > lim) {
180
+ buffer->position = lim;
181
+ }
182
+
183
+ if(buffer->mark > lim) {
184
+ buffer->mark = MARK_UNSET;
185
+ }
186
+
187
+ return new_limit;
188
+ }
189
+
190
+ static VALUE NIO_ByteBuffer_capacity(VALUE self)
191
+ {
192
+ struct NIO_ByteBuffer *buffer;
193
+ Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
194
+
195
+ return INT2NUM(buffer->capacity);
196
+ }
197
+
198
+ static VALUE NIO_ByteBuffer_remaining(VALUE self)
199
+ {
200
+ struct NIO_ByteBuffer *buffer;
201
+ Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
202
+
203
+ return INT2NUM(buffer->limit - buffer->position);
204
+ }
205
+
206
+ static VALUE NIO_ByteBuffer_full(VALUE self)
207
+ {
208
+ struct NIO_ByteBuffer *buffer;
209
+ Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
210
+
211
+ return buffer->position == buffer->limit ? Qtrue : Qfalse;
212
+ }
213
+
214
+ static VALUE NIO_ByteBuffer_get(int argc, VALUE *argv, VALUE self)
215
+ {
216
+ int len;
217
+ VALUE length, result;
218
+ struct NIO_ByteBuffer *buffer;
219
+ Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
220
+
221
+ rb_scan_args(argc, argv, "01", &length);
222
+
223
+ if(length == Qnil) {
224
+ len = buffer->limit - buffer->position;
225
+ } else {
226
+ len = NUM2INT(length);
227
+ }
228
+
229
+ if(len < 0) {
230
+ rb_raise(rb_eArgError, "negative length given");
231
+ }
232
+
233
+ if(len > buffer->limit - buffer->position) {
234
+ rb_raise(cNIO_ByteBuffer_UnderflowError, "not enough data in buffer");
235
+ }
236
+
237
+ result = rb_str_new(buffer->buffer + buffer->position, len);
238
+ buffer->position += len;
239
+
240
+ return result;
241
+ }
242
+
243
+ static VALUE NIO_ByteBuffer_fetch(VALUE self, VALUE index)
244
+ {
245
+ int i;
246
+ struct NIO_ByteBuffer *buffer;
247
+ Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
248
+
249
+ i = NUM2INT(index);
250
+
251
+ if(i < 0) {
252
+ rb_raise(rb_eArgError, "negative index given");
253
+ }
254
+
255
+ if(i >= buffer->limit) {
256
+ rb_raise(rb_eArgError, "specified index exceeds limit");
257
+ }
258
+
259
+ return INT2NUM(buffer->buffer[i]);
260
+ }
261
+
262
+ static VALUE NIO_ByteBuffer_put(VALUE self, VALUE string)
263
+ {
264
+ long length;
265
+ struct NIO_ByteBuffer *buffer;
266
+ Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
267
+
268
+ StringValue(string);
269
+ length = RSTRING_LEN(string);
270
+
271
+ if(length > buffer->limit - buffer->position) {
272
+ rb_raise(cNIO_ByteBuffer_OverflowError, "buffer is full");
273
+ }
274
+
275
+ memcpy(buffer->buffer + buffer->position, StringValuePtr(string), length);
276
+ buffer->position += length;
277
+
278
+ return self;
279
+ }
280
+
281
+ static VALUE NIO_ByteBuffer_read_from(VALUE self, VALUE io)
282
+ {
283
+ struct NIO_ByteBuffer *buffer;
284
+ rb_io_t *fptr;
285
+ ssize_t nbytes, bytes_read;
286
+
287
+ Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
288
+ GetOpenFile(rb_convert_type(io, T_FILE, "IO", "to_io"), fptr);
289
+ rb_io_set_nonblock(fptr);
290
+
291
+ nbytes = buffer->limit - buffer->position;
292
+ if(nbytes == 0) {
293
+ rb_raise(cNIO_ByteBuffer_OverflowError, "buffer is full");
294
+ }
295
+
296
+ bytes_read = read(FPTR_TO_FD(fptr), buffer->buffer + buffer->position, nbytes);
297
+
298
+ if(bytes_read < 0) {
299
+ if(errno == EAGAIN) {
300
+ return INT2NUM(0);
301
+ } else {
302
+ rb_sys_fail("write");
303
+ }
304
+ }
305
+
306
+ buffer->position += bytes_read;
307
+
308
+ return INT2NUM(bytes_read);
309
+ }
310
+
311
+ static VALUE NIO_ByteBuffer_write_to(VALUE self, VALUE io)
312
+ {
313
+ struct NIO_ByteBuffer *buffer;
314
+ rb_io_t *fptr;
315
+ ssize_t nbytes, bytes_written;
316
+
317
+ Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
318
+ GetOpenFile(rb_convert_type(io, T_FILE, "IO", "to_io"), fptr);
319
+ rb_io_set_nonblock(fptr);
320
+
321
+ nbytes = buffer->limit - buffer->position;
322
+ if(nbytes == 0) {
323
+ rb_raise(cNIO_ByteBuffer_UnderflowError, "no data remaining in buffer");
324
+ }
325
+
326
+ bytes_written = write(FPTR_TO_FD(fptr), buffer->buffer + buffer->position, nbytes);
327
+
328
+ if(bytes_written < 0) {
329
+ if(errno == EAGAIN) {
330
+ return INT2NUM(0);
331
+ } else {
332
+ rb_sys_fail("write");
333
+ }
334
+ }
335
+
336
+ buffer->position += bytes_written;
337
+
338
+ return INT2NUM(bytes_written);
339
+ }
340
+
341
+ static VALUE NIO_ByteBuffer_flip(VALUE self)
342
+ {
343
+ struct NIO_ByteBuffer *buffer;
344
+ Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
345
+
346
+ buffer->limit = buffer->position;
347
+ buffer->position = 0;
348
+ buffer->mark = MARK_UNSET;
349
+
350
+ return self;
351
+ }
352
+
353
+ static VALUE NIO_ByteBuffer_rewind(VALUE self)
354
+ {
355
+ struct NIO_ByteBuffer *buffer;
356
+ Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
357
+
358
+ buffer->position = 0;
359
+ buffer->mark = MARK_UNSET;
360
+
361
+ return self;
362
+ }
363
+
364
+ static VALUE NIO_ByteBuffer_mark(VALUE self)
365
+ {
366
+ struct NIO_ByteBuffer *buffer;
367
+ Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
368
+
369
+ buffer->mark = buffer->position;
370
+ return self;
371
+ }
372
+
373
+ static VALUE NIO_ByteBuffer_reset(VALUE self)
374
+ {
375
+ struct NIO_ByteBuffer *buffer;
376
+ Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
377
+
378
+ if(buffer->mark < 0) {
379
+ rb_raise(cNIO_ByteBuffer_MarkUnsetError, "mark has not been set");
380
+ } else {
381
+ buffer->position = buffer->mark;
382
+ }
383
+
384
+ return self;
385
+ }
386
+
387
+ static VALUE NIO_ByteBuffer_compact(VALUE self)
388
+ {
389
+ struct NIO_ByteBuffer *buffer;
390
+ Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
391
+
392
+ memmove(buffer->buffer, buffer->buffer + buffer->position, buffer->limit - buffer->position);
393
+ buffer->position = buffer->limit - buffer->position;
394
+ buffer->limit = buffer->capacity;
395
+
396
+ return self;
397
+ }
398
+
399
+ static VALUE NIO_ByteBuffer_each(VALUE self)
400
+ {
401
+ int i;
402
+ struct NIO_ByteBuffer *buffer;
403
+ Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
404
+
405
+ if(rb_block_given_p()) {
406
+ for(i = 0; i < buffer->limit; i++) {
407
+ rb_yield(INT2NUM(buffer->buffer[i]));
408
+ }
409
+ } else {
410
+ rb_raise(rb_eArgError, "no block given");
411
+ }
412
+
413
+ return self;
414
+ }
415
+
416
+ static VALUE NIO_ByteBuffer_inspect(VALUE self)
417
+ {
418
+ struct NIO_ByteBuffer *buffer;
419
+ Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
420
+
421
+ return rb_sprintf(
422
+ "#<%s:%p @position=%d @limit=%d @capacity=%d>",
423
+ rb_class2name(CLASS_OF(self)),
424
+ (void*)self,
425
+ buffer->position,
426
+ buffer->limit,
427
+ buffer->capacity
428
+ );
429
+ }