omq-backend-rust 0.1.7 → 0.2.0

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.
@@ -1,13 +1,15 @@
1
+ use std::ffi::c_void;
2
+ use std::panic::{AssertUnwindSafe, catch_unwind};
1
3
  use std::str::FromStr;
2
4
  use std::sync::atomic::{AtomicBool, Ordering};
3
- use std::sync::{Arc, Mutex, RwLock};
5
+ use std::sync::{Arc, Mutex, OnceLock, RwLock};
4
6
 
5
7
  use bytes::Bytes;
6
- use magnus::r_hash::RHash;
7
- use magnus::{Error, Ruby, function, method, prelude::*, r_array::RArray, r_string::RString};
8
+ use rb_sys::{VALUE, rb_data_type_struct__bindgen_ty_1, rb_data_type_t, size_t};
8
9
 
9
10
  use crate::error::map_err;
10
11
  use crate::notify::PipeNotify;
12
+ use crate::rb::{self, RbResult, RubyErr};
11
13
  use crate::runtime::{self, Materialized};
12
14
 
13
15
  static IO_THREADS: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(1);
@@ -20,7 +22,6 @@ fn io_threads() -> usize {
20
22
  IO_THREADS.load(Ordering::Relaxed)
21
23
  }
22
24
 
23
- #[magnus::wrap(class = "OMQ::Rust::Native::RustSocket", free_immediately, size)]
24
25
  pub struct RustSocket {
25
26
  socket_type: omq_tokio::SocketType,
26
27
  options: Mutex<Option<omq_tokio::Options>>,
@@ -32,6 +33,59 @@ pub struct RustSocket {
32
33
  unsafe impl Send for RustSocket {}
33
34
  unsafe impl Sync for RustSocket {}
34
35
 
36
+ struct SocketDataType(rb_data_type_t);
37
+
38
+ unsafe impl Send for SocketDataType {}
39
+ unsafe impl Sync for SocketDataType {}
40
+
41
+ static RUST_SOCKET_DATA_TYPE: OnceLock<SocketDataType> = OnceLock::new();
42
+
43
+ fn rust_socket_data_type() -> *const rb_data_type_t {
44
+ &RUST_SOCKET_DATA_TYPE
45
+ .get_or_init(|| SocketDataType(make_rust_socket_data_type()))
46
+ .0
47
+ }
48
+
49
+ fn make_rust_socket_data_type() -> rb_data_type_t {
50
+ rb_data_type_t {
51
+ wrap_struct_name: c"omq_backend_rust_socket".as_ptr(),
52
+ function: rb_data_type_struct__bindgen_ty_1 {
53
+ dmark: None,
54
+ dfree: Some(rust_socket_free),
55
+ dsize: Some(rust_socket_size),
56
+ dcompact: None,
57
+ reserved: [std::ptr::null_mut(); 1],
58
+ },
59
+ parent: std::ptr::null(),
60
+ data: std::ptr::null_mut(),
61
+ flags: 1,
62
+ }
63
+ }
64
+
65
+ unsafe extern "C" fn rust_socket_free(ptr: *mut c_void) {
66
+ if ptr.is_null() {
67
+ return;
68
+ }
69
+
70
+ let _ = catch_unwind(AssertUnwindSafe(|| unsafe {
71
+ drop(Box::from_raw(ptr as *mut RustSocket));
72
+ }));
73
+ }
74
+
75
+ unsafe extern "C" fn rust_socket_size(_ptr: *const c_void) -> size_t {
76
+ std::mem::size_of::<RustSocket>() as size_t
77
+ }
78
+
79
+ unsafe fn rust_socket_ref(value: VALUE) -> RbResult<&'static RustSocket> {
80
+ unsafe {
81
+ rb::typed_data_ref(
82
+ value,
83
+ rust_socket_data_type(),
84
+ "OMQ::Rust::Native::RustSocket",
85
+ )
86
+ }
87
+ }
88
+
35
89
  fn parse_socket_type(s: &str) -> Result<omq_tokio::SocketType, String> {
36
90
  match s {
37
91
  "REQ" => Ok(omq_tokio::SocketType::Req),
@@ -57,27 +111,46 @@ fn parse_socket_type(s: &str) -> Result<omq_tokio::SocketType, String> {
57
111
  }
58
112
  }
59
113
 
60
- fn rust_socket_new(ruby: &Ruby, type_str: String) -> Result<RustSocket, Error> {
61
- let st = parse_socket_type(&type_str).map_err(|e| Error::new(ruby.exception_arg_error(), e))?;
62
- Ok(RustSocket {
63
- socket_type: st,
64
- options: Mutex::new(None),
65
- materialized: RwLock::new(None),
66
- closed: AtomicBool::new(false),
67
- linger: Mutex::new(None),
68
- })
114
+ fn rust_socket_new_impl(class: VALUE, type_str: VALUE) -> RbResult<VALUE> {
115
+ let type_str = rb::value_to_string(type_str)?;
116
+ let st = parse_socket_type(&type_str).map_err(RubyErr::arg)?;
117
+ unsafe {
118
+ rb::wrap_typed_data(
119
+ class,
120
+ Box::new(RustSocket {
121
+ socket_type: st,
122
+ options: Mutex::new(None),
123
+ materialized: RwLock::new(None),
124
+ closed: AtomicBool::new(false),
125
+ linger: Mutex::new(None),
126
+ }),
127
+ rust_socket_data_type(),
128
+ )
129
+ }
130
+ }
131
+
132
+ unsafe extern "C" fn rust_socket_new(class: VALUE, type_str: VALUE) -> VALUE {
133
+ rb::wrap(|| rust_socket_new_impl(class, type_str))
69
134
  }
70
135
 
71
- fn rust_socket_set_options(ruby: &Ruby, rb_self: &RustSocket, hash: RHash) -> Result<(), Error> {
72
- let opts = crate::options::build_options(ruby, hash)?;
136
+ fn rust_socket_set_options_impl(rb_self: &RustSocket, hash: VALUE) -> RbResult<()> {
137
+ let opts = crate::options::build_options(hash)?;
73
138
  *rb_self.linger.lock().unwrap() = opts.linger;
74
139
  *rb_self.options.lock().unwrap() = Some(opts);
75
140
  Ok(())
76
141
  }
77
142
 
78
- fn rust_socket_materialize(ruby: &Ruby, rb_self: &RustSocket) -> Result<(), Error> {
143
+ unsafe extern "C" fn rust_socket_set_options(rb_self: VALUE, hash: VALUE) -> VALUE {
144
+ rb::wrap(|| {
145
+ let rb_self = unsafe { rust_socket_ref(rb_self)? };
146
+ rust_socket_set_options_impl(rb_self, hash)?;
147
+ Ok(rb::qnil())
148
+ })
149
+ }
150
+
151
+ fn rust_socket_materialize_impl(rb_self: &RustSocket) -> RbResult<()> {
79
152
  if rb_self.closed.load(Ordering::Relaxed) {
80
- return Err(Error::new(ruby.exception_io_error(), "socket closed"));
153
+ return Err(RubyErr::io("socket closed"));
81
154
  }
82
155
  {
83
156
  let slot = rb_self.materialized.read().unwrap();
@@ -140,235 +213,375 @@ fn rust_socket_materialize(ruby: &Ruby, rb_self: &RustSocket) -> Result<(), Erro
140
213
  Ok(())
141
214
  }
142
215
 
143
- fn rust_socket_bind(ruby: &Ruby, rb_self: &RustSocket, endpoint: String) -> Result<String, Error> {
144
- let sock = ensure_socket(ruby, rb_self)?;
145
- let ep = omq_tokio::Endpoint::from_str(&endpoint).map_err(|e| map_err(ruby, e))?;
216
+ unsafe extern "C" fn rust_socket_materialize(rb_self: VALUE) -> VALUE {
217
+ rb::wrap(|| {
218
+ let rb_self = unsafe { rust_socket_ref(rb_self)? };
219
+ rust_socket_materialize_impl(rb_self)?;
220
+ Ok(rb::qnil())
221
+ })
222
+ }
223
+
224
+ fn rust_socket_bind_impl(rb_self: &RustSocket, endpoint: VALUE) -> RbResult<VALUE> {
225
+ let sock = ensure_socket(rb_self)?;
226
+ let endpoint = rb::value_to_string(endpoint)?;
227
+ let ep = omq_tokio::Endpoint::from_str(&endpoint).map_err(map_err)?;
146
228
  let result = runtime::spawn_blocking(io_threads(), async move { sock.bind(ep).await });
147
- result
148
- .map(|ep| ep.to_string())
149
- .map_err(|e| map_err(ruby, e))
229
+ let endpoint = result.map_err(map_err)?;
230
+ rb::new_utf8_string(&endpoint.to_string())
231
+ }
232
+
233
+ unsafe extern "C" fn rust_socket_bind(rb_self: VALUE, endpoint: VALUE) -> VALUE {
234
+ rb::wrap(|| {
235
+ let rb_self = unsafe { rust_socket_ref(rb_self)? };
236
+ rust_socket_bind_impl(rb_self, endpoint)
237
+ })
150
238
  }
151
239
 
152
- fn rust_socket_connect(ruby: &Ruby, rb_self: &RustSocket, endpoint: String) -> Result<(), Error> {
153
- let sock = ensure_socket(ruby, rb_self)?;
154
- let ep = omq_tokio::Endpoint::from_str(&endpoint).map_err(|e| map_err(ruby, e))?;
240
+ fn rust_socket_connect_impl(rb_self: &RustSocket, endpoint: VALUE) -> RbResult<()> {
241
+ let sock = ensure_socket(rb_self)?;
242
+ let endpoint = rb::value_to_string(endpoint)?;
243
+ let ep = omq_tokio::Endpoint::from_str(&endpoint).map_err(map_err)?;
155
244
  let result = runtime::spawn_blocking(io_threads(), async move { sock.connect(ep).await });
156
- result.map_err(|e| map_err(ruby, e))
245
+ result.map_err(map_err)
157
246
  }
158
247
 
159
- fn rust_socket_disconnect(
160
- ruby: &Ruby,
161
- rb_self: &RustSocket,
162
- endpoint: String,
163
- ) -> Result<(), Error> {
164
- let sock = ensure_socket(ruby, rb_self)?;
165
- let ep = omq_tokio::Endpoint::from_str(&endpoint).map_err(|e| map_err(ruby, e))?;
248
+ unsafe extern "C" fn rust_socket_connect(rb_self: VALUE, endpoint: VALUE) -> VALUE {
249
+ rb::wrap(|| {
250
+ let rb_self = unsafe { rust_socket_ref(rb_self)? };
251
+ rust_socket_connect_impl(rb_self, endpoint)?;
252
+ Ok(rb::qnil())
253
+ })
254
+ }
255
+
256
+ fn rust_socket_disconnect_impl(rb_self: &RustSocket, endpoint: VALUE) -> RbResult<()> {
257
+ let sock = ensure_socket(rb_self)?;
258
+ let endpoint = rb::value_to_string(endpoint)?;
259
+ let ep = omq_tokio::Endpoint::from_str(&endpoint).map_err(map_err)?;
166
260
  let result = runtime::spawn_blocking(io_threads(), async move { sock.disconnect(ep).await });
167
- result.map_err(|e| map_err(ruby, e))
261
+ result.map_err(map_err)
262
+ }
263
+
264
+ unsafe extern "C" fn rust_socket_disconnect(rb_self: VALUE, endpoint: VALUE) -> VALUE {
265
+ rb::wrap(|| {
266
+ let rb_self = unsafe { rust_socket_ref(rb_self)? };
267
+ rust_socket_disconnect_impl(rb_self, endpoint)?;
268
+ Ok(rb::qnil())
269
+ })
168
270
  }
169
271
 
170
- fn rust_socket_unbind(ruby: &Ruby, rb_self: &RustSocket, endpoint: String) -> Result<(), Error> {
171
- let sock = ensure_socket(ruby, rb_self)?;
172
- let ep = omq_tokio::Endpoint::from_str(&endpoint).map_err(|e| map_err(ruby, e))?;
272
+ fn rust_socket_unbind_impl(rb_self: &RustSocket, endpoint: VALUE) -> RbResult<()> {
273
+ let sock = ensure_socket(rb_self)?;
274
+ let endpoint = rb::value_to_string(endpoint)?;
275
+ let ep = omq_tokio::Endpoint::from_str(&endpoint).map_err(map_err)?;
173
276
  let result = runtime::spawn_blocking(io_threads(), async move { sock.unbind(ep).await });
174
- result.map_err(|e| map_err(ruby, e))
277
+ result.map_err(map_err)
175
278
  }
176
279
 
177
- fn rust_socket_enqueue_send(
178
- ruby: &Ruby,
179
- rb_self: &RustSocket,
180
- parts: RArray,
181
- ) -> Result<magnus::Symbol, Error> {
280
+ unsafe extern "C" fn rust_socket_unbind(rb_self: VALUE, endpoint: VALUE) -> VALUE {
281
+ rb::wrap(|| {
282
+ let rb_self = unsafe { rust_socket_ref(rb_self)? };
283
+ rust_socket_unbind_impl(rb_self, endpoint)?;
284
+ Ok(rb::qnil())
285
+ })
286
+ }
287
+
288
+ fn rust_socket_enqueue_send_impl(rb_self: &RustSocket, parts: VALUE) -> RbResult<VALUE> {
182
289
  let mat_guard = rb_self.materialized.read().unwrap();
183
290
  let mat = mat_guard
184
291
  .as_ref()
185
- .ok_or_else(|| Error::new(ruby.exception_runtime_error(), "socket not materialized"))?;
292
+ .ok_or_else(|| RubyErr::runtime("socket not materialized"))?;
186
293
 
187
- let msg = ruby_parts_to_message(ruby, parts)?;
294
+ let msg = ruby_parts_to_message(parts)?;
188
295
  let mut prod = mat.send_prod.lock().unwrap();
189
296
  match prod.push(msg) {
190
297
  Ok(()) => {
191
298
  prod.flush();
192
- Ok(ruby.to_symbol("ok"))
299
+ rb::symbol("ok")
193
300
  }
194
301
  Err(returned) => {
195
302
  prod.flush();
196
303
  match prod.push(returned) {
197
304
  Ok(()) => {
198
305
  prod.flush();
199
- Ok(ruby.to_symbol("ok"))
306
+ rb::symbol("ok")
200
307
  }
201
- Err(_) => Ok(ruby.to_symbol("full")),
308
+ Err(_) => rb::symbol("full"),
202
309
  }
203
310
  }
204
311
  }
205
312
  }
206
313
 
207
- fn rust_socket_try_recv(ruby: &Ruby, rb_self: &RustSocket) -> Result<Option<RArray>, Error> {
314
+ unsafe extern "C" fn rust_socket_enqueue_send(rb_self: VALUE, parts: VALUE) -> VALUE {
315
+ rb::wrap(|| {
316
+ let rb_self = unsafe { rust_socket_ref(rb_self)? };
317
+ rust_socket_enqueue_send_impl(rb_self, parts)
318
+ })
319
+ }
320
+
321
+ fn rust_socket_try_recv_impl(rb_self: &RustSocket) -> RbResult<VALUE> {
208
322
  let mat_guard = rb_self.materialized.read().unwrap();
209
323
  let mat = match mat_guard.as_ref() {
210
324
  Some(m) => m,
211
- None => return Ok(None),
325
+ None => return Ok(rb::qnil()),
212
326
  };
213
327
 
214
328
  let mut cons = mat.recv_cons.lock().unwrap();
215
329
  match cons.prefetch_and_pop() {
216
330
  Some(msg) => {
217
331
  mat.recv_space.notify_one();
218
- Ok(Some(message_to_ruby_parts(ruby, msg)?))
332
+ message_to_ruby_parts(msg)
219
333
  }
220
- None => Ok(None),
334
+ None => Ok(rb::qnil()),
221
335
  }
222
336
  }
223
337
 
224
- fn rust_socket_try_recv_batch(ruby: &Ruby, rb_self: &RustSocket) -> Result<Option<RArray>, Error> {
338
+ unsafe extern "C" fn rust_socket_try_recv(rb_self: VALUE) -> VALUE {
339
+ rb::wrap(|| {
340
+ let rb_self = unsafe { rust_socket_ref(rb_self)? };
341
+ rust_socket_try_recv_impl(rb_self)
342
+ })
343
+ }
344
+
345
+ fn rust_socket_try_recv_batch_impl(rb_self: &RustSocket) -> RbResult<VALUE> {
225
346
  let mat_guard = rb_self.materialized.read().unwrap();
226
347
  let mat = match mat_guard.as_ref() {
227
348
  Some(m) => m,
228
- None => return Ok(None),
349
+ None => return Ok(rb::qnil()),
229
350
  };
230
351
 
231
352
  let mut cons = mat.recv_cons.lock().unwrap();
232
353
  let count = cons.prefetch();
233
354
  if count == 0 {
234
- return Ok(None);
355
+ return Ok(rb::qnil());
235
356
  }
236
357
 
237
- let batch = ruby.ary_new_capa(count);
358
+ let batch = rb::array_new_capa(count)?;
238
359
  let mut popped = 0usize;
239
360
  while let Some(msg) = cons.pop() {
240
- batch.push(message_to_ruby_parts(ruby, msg)?)?;
361
+ rb::array_push(batch, message_to_ruby_parts(msg)?)?;
241
362
  popped += 1;
242
363
  }
243
364
  cons.release();
244
365
 
245
366
  if popped > 0 {
246
367
  mat.recv_space.notify_one();
247
- Ok(Some(batch))
368
+ Ok(batch)
248
369
  } else {
249
- Ok(None)
370
+ Ok(rb::qnil())
250
371
  }
251
372
  }
252
373
 
253
- fn rust_socket_wake_recv(rb_self: &RustSocket) {
374
+ unsafe extern "C" fn rust_socket_try_recv_batch(rb_self: VALUE) -> VALUE {
375
+ rb::wrap(|| {
376
+ let rb_self = unsafe { rust_socket_ref(rb_self)? };
377
+ rust_socket_try_recv_batch_impl(rb_self)
378
+ })
379
+ }
380
+
381
+ fn rust_socket_wake_recv_impl(rb_self: &RustSocket) {
254
382
  let mat_guard = rb_self.materialized.read().unwrap();
255
383
  if let Some(mat) = mat_guard.as_ref() {
256
384
  mat.recv_notify.force_wake();
257
385
  }
258
386
  }
259
387
 
260
- fn rust_socket_recv_fd(ruby: &Ruby, rb_self: &RustSocket) -> Result<i32, Error> {
388
+ unsafe extern "C" fn rust_socket_wake_recv(rb_self: VALUE) -> VALUE {
389
+ rb::wrap(|| {
390
+ let rb_self = unsafe { rust_socket_ref(rb_self)? };
391
+ rust_socket_wake_recv_impl(rb_self);
392
+ Ok(rb::qnil())
393
+ })
394
+ }
395
+
396
+ fn rust_socket_recv_fd_impl(rb_self: &RustSocket) -> RbResult<VALUE> {
261
397
  let mat_guard = rb_self.materialized.read().unwrap();
262
398
  let mat = mat_guard
263
399
  .as_ref()
264
- .ok_or_else(|| Error::new(ruby.exception_runtime_error(), "socket not materialized"))?;
400
+ .ok_or_else(|| RubyErr::runtime("socket not materialized"))?;
265
401
  mat.recv_notify.park_begin();
266
- Ok(mat.recv_notify.read_fd())
402
+ Ok(rb::int_value(mat.recv_notify.read_fd()))
403
+ }
404
+
405
+ unsafe extern "C" fn rust_socket_recv_fd(rb_self: VALUE) -> VALUE {
406
+ rb::wrap(|| {
407
+ let rb_self = unsafe { rust_socket_ref(rb_self)? };
408
+ rust_socket_recv_fd_impl(rb_self)
409
+ })
267
410
  }
268
411
 
269
- fn rust_socket_send_fd(ruby: &Ruby, rb_self: &RustSocket) -> Result<i32, Error> {
412
+ fn rust_socket_send_fd_impl(rb_self: &RustSocket) -> RbResult<VALUE> {
270
413
  let mat_guard = rb_self.materialized.read().unwrap();
271
414
  let mat = mat_guard
272
415
  .as_ref()
273
- .ok_or_else(|| Error::new(ruby.exception_runtime_error(), "socket not materialized"))?;
416
+ .ok_or_else(|| RubyErr::runtime("socket not materialized"))?;
274
417
  mat.send_notify.park_begin();
275
- Ok(mat.send_notify.read_fd())
418
+ Ok(rb::int_value(mat.send_notify.read_fd()))
419
+ }
420
+
421
+ unsafe extern "C" fn rust_socket_send_fd(rb_self: VALUE) -> VALUE {
422
+ rb::wrap(|| {
423
+ let rb_self = unsafe { rust_socket_ref(rb_self)? };
424
+ rust_socket_send_fd_impl(rb_self)
425
+ })
276
426
  }
277
427
 
278
- fn rust_socket_peer_connected_fd(ruby: &Ruby, rb_self: &RustSocket) -> Result<i32, Error> {
428
+ fn rust_socket_peer_connected_fd_impl(rb_self: &RustSocket) -> RbResult<VALUE> {
279
429
  let mat_guard = rb_self.materialized.read().unwrap();
280
430
  let mat = mat_guard
281
431
  .as_ref()
282
- .ok_or_else(|| Error::new(ruby.exception_runtime_error(), "socket not materialized"))?;
283
- Ok(mat.peer_connected_notify.read_fd())
432
+ .ok_or_else(|| RubyErr::runtime("socket not materialized"))?;
433
+ Ok(rb::int_value(mat.peer_connected_notify.read_fd()))
434
+ }
435
+
436
+ unsafe extern "C" fn rust_socket_peer_connected_fd(rb_self: VALUE) -> VALUE {
437
+ rb::wrap(|| {
438
+ let rb_self = unsafe { rust_socket_ref(rb_self)? };
439
+ rust_socket_peer_connected_fd_impl(rb_self)
440
+ })
284
441
  }
285
442
 
286
- fn rust_socket_all_peers_gone_fd(ruby: &Ruby, rb_self: &RustSocket) -> Result<i32, Error> {
443
+ fn rust_socket_all_peers_gone_fd_impl(rb_self: &RustSocket) -> RbResult<VALUE> {
287
444
  let mat_guard = rb_self.materialized.read().unwrap();
288
445
  let mat = mat_guard
289
446
  .as_ref()
290
- .ok_or_else(|| Error::new(ruby.exception_runtime_error(), "socket not materialized"))?;
291
- Ok(mat.all_peers_gone_notify.read_fd())
447
+ .ok_or_else(|| RubyErr::runtime("socket not materialized"))?;
448
+ Ok(rb::int_value(mat.all_peers_gone_notify.read_fd()))
449
+ }
450
+
451
+ unsafe extern "C" fn rust_socket_all_peers_gone_fd(rb_self: VALUE) -> VALUE {
452
+ rb::wrap(|| {
453
+ let rb_self = unsafe { rust_socket_ref(rb_self)? };
454
+ rust_socket_all_peers_gone_fd_impl(rb_self)
455
+ })
292
456
  }
293
457
 
294
- fn rust_socket_subscriber_joined_fd(ruby: &Ruby, rb_self: &RustSocket) -> Result<i32, Error> {
458
+ fn rust_socket_subscriber_joined_fd_impl(rb_self: &RustSocket) -> RbResult<VALUE> {
295
459
  let mat_guard = rb_self.materialized.read().unwrap();
296
460
  let mat = mat_guard
297
461
  .as_ref()
298
- .ok_or_else(|| Error::new(ruby.exception_runtime_error(), "socket not materialized"))?;
299
- Ok(mat.subscriber_joined_notify.read_fd())
462
+ .ok_or_else(|| RubyErr::runtime("socket not materialized"))?;
463
+ Ok(rb::int_value(mat.subscriber_joined_notify.read_fd()))
464
+ }
465
+
466
+ unsafe extern "C" fn rust_socket_subscriber_joined_fd(rb_self: VALUE) -> VALUE {
467
+ rb::wrap(|| {
468
+ let rb_self = unsafe { rust_socket_ref(rb_self)? };
469
+ rust_socket_subscriber_joined_fd_impl(rb_self)
470
+ })
300
471
  }
301
472
 
302
- fn rust_socket_monitor_fd(ruby: &Ruby, rb_self: &RustSocket) -> Result<i32, Error> {
473
+ fn rust_socket_monitor_fd_impl(rb_self: &RustSocket) -> RbResult<VALUE> {
303
474
  let mat_guard = rb_self.materialized.read().unwrap();
304
475
  let mat = mat_guard
305
476
  .as_ref()
306
- .ok_or_else(|| Error::new(ruby.exception_runtime_error(), "socket not materialized"))?;
477
+ .ok_or_else(|| RubyErr::runtime("socket not materialized"))?;
307
478
  mat.monitor_notify.park_begin();
308
- Ok(mat.monitor_notify.read_fd())
479
+ Ok(rb::int_value(mat.monitor_notify.read_fd()))
480
+ }
481
+
482
+ unsafe extern "C" fn rust_socket_monitor_fd(rb_self: VALUE) -> VALUE {
483
+ rb::wrap(|| {
484
+ let rb_self = unsafe { rust_socket_ref(rb_self)? };
485
+ rust_socket_monitor_fd_impl(rb_self)
486
+ })
309
487
  }
310
488
 
311
- fn rust_socket_try_recv_monitor(ruby: &Ruby, rb_self: &RustSocket) -> Result<Option<RHash>, Error> {
489
+ fn rust_socket_try_recv_monitor_impl(rb_self: &RustSocket) -> RbResult<VALUE> {
312
490
  let mat_guard = rb_self.materialized.read().unwrap();
313
491
  let mat = match mat_guard.as_ref() {
314
492
  Some(m) => m,
315
- None => return Ok(None),
493
+ None => return Ok(rb::qnil()),
316
494
  };
317
495
 
318
496
  match mat.monitor_rx.try_recv() {
319
497
  Ok(data) => {
320
- let hash = ruby.hash_new();
321
- hash.aset(ruby.to_symbol("type"), ruby.to_symbol(data.event_type))?;
498
+ let hash = rb::hash_new()?;
499
+ rb::hash_aset(hash, rb::symbol("type")?, rb::symbol(data.event_type)?)?;
322
500
  if let Some(ep) = data.endpoint {
323
- hash.aset(ruby.to_symbol("endpoint"), ruby.str_new(&ep))?;
501
+ rb::hash_aset(hash, rb::symbol("endpoint")?, rb::new_utf8_string(&ep)?)?;
324
502
  }
325
503
  if !data.detail.is_empty() {
326
- let detail = ruby.hash_new();
504
+ let detail = rb::hash_new()?;
327
505
  for (k, v) in &data.detail {
328
- detail.aset(ruby.to_symbol(k), ruby.str_new(v))?;
506
+ rb::hash_aset(detail, rb::symbol(k)?, rb::new_utf8_string(v)?)?;
329
507
  }
330
- hash.aset(ruby.to_symbol("detail"), detail)?;
508
+ rb::hash_aset(hash, rb::symbol("detail")?, detail)?;
331
509
  }
332
- Ok(Some(hash))
510
+ Ok(hash)
333
511
  }
334
- Err(_) => Ok(None),
512
+ Err(_) => Ok(rb::qnil()),
335
513
  }
336
514
  }
337
515
 
338
- fn rust_socket_subscribe(ruby: &Ruby, rb_self: &RustSocket, prefix: RString) -> Result<(), Error> {
339
- let sock = ensure_socket(ruby, rb_self)?;
340
- let bytes = Bytes::from(unsafe { prefix.as_slice() }.to_vec());
516
+ unsafe extern "C" fn rust_socket_try_recv_monitor(rb_self: VALUE) -> VALUE {
517
+ rb::wrap(|| {
518
+ let rb_self = unsafe { rust_socket_ref(rb_self)? };
519
+ rust_socket_try_recv_monitor_impl(rb_self)
520
+ })
521
+ }
522
+
523
+ fn rust_socket_subscribe_impl(rb_self: &RustSocket, prefix: VALUE) -> RbResult<()> {
524
+ let sock = ensure_socket(rb_self)?;
525
+ let bytes = Bytes::from(rb::value_to_bytes(prefix)?);
341
526
  let result = runtime::spawn_blocking(io_threads(), async move { sock.subscribe(bytes).await });
342
- result.map_err(|e| map_err(ruby, e))
527
+ result.map_err(map_err)
528
+ }
529
+
530
+ unsafe extern "C" fn rust_socket_subscribe(rb_self: VALUE, prefix: VALUE) -> VALUE {
531
+ rb::wrap(|| {
532
+ let rb_self = unsafe { rust_socket_ref(rb_self)? };
533
+ rust_socket_subscribe_impl(rb_self, prefix)?;
534
+ Ok(rb::qnil())
535
+ })
343
536
  }
344
537
 
345
- fn rust_socket_unsubscribe(
346
- ruby: &Ruby,
347
- rb_self: &RustSocket,
348
- prefix: RString,
349
- ) -> Result<(), Error> {
350
- let sock = ensure_socket(ruby, rb_self)?;
351
- let bytes = Bytes::from(unsafe { prefix.as_slice() }.to_vec());
538
+ fn rust_socket_unsubscribe_impl(rb_self: &RustSocket, prefix: VALUE) -> RbResult<()> {
539
+ let sock = ensure_socket(rb_self)?;
540
+ let bytes = Bytes::from(rb::value_to_bytes(prefix)?);
352
541
  let result =
353
542
  runtime::spawn_blocking(io_threads(), async move { sock.unsubscribe(bytes).await });
354
- result.map_err(|e| map_err(ruby, e))
543
+ result.map_err(map_err)
544
+ }
545
+
546
+ unsafe extern "C" fn rust_socket_unsubscribe(rb_self: VALUE, prefix: VALUE) -> VALUE {
547
+ rb::wrap(|| {
548
+ let rb_self = unsafe { rust_socket_ref(rb_self)? };
549
+ rust_socket_unsubscribe_impl(rb_self, prefix)?;
550
+ Ok(rb::qnil())
551
+ })
355
552
  }
356
553
 
357
- fn rust_socket_join(ruby: &Ruby, rb_self: &RustSocket, group: RString) -> Result<(), Error> {
358
- let sock = ensure_socket(ruby, rb_self)?;
359
- let bytes = Bytes::from(unsafe { group.as_slice() }.to_vec());
554
+ fn rust_socket_join_impl(rb_self: &RustSocket, group: VALUE) -> RbResult<()> {
555
+ let sock = ensure_socket(rb_self)?;
556
+ let bytes = Bytes::from(rb::value_to_bytes(group)?);
360
557
  let result = runtime::spawn_blocking(io_threads(), async move { sock.join(bytes).await });
361
- result.map_err(|e| map_err(ruby, e))
558
+ result.map_err(map_err)
559
+ }
560
+
561
+ unsafe extern "C" fn rust_socket_join(rb_self: VALUE, group: VALUE) -> VALUE {
562
+ rb::wrap(|| {
563
+ let rb_self = unsafe { rust_socket_ref(rb_self)? };
564
+ rust_socket_join_impl(rb_self, group)?;
565
+ Ok(rb::qnil())
566
+ })
362
567
  }
363
568
 
364
- fn rust_socket_leave(ruby: &Ruby, rb_self: &RustSocket, group: RString) -> Result<(), Error> {
365
- let sock = ensure_socket(ruby, rb_self)?;
366
- let bytes = Bytes::from(unsafe { group.as_slice() }.to_vec());
569
+ fn rust_socket_leave_impl(rb_self: &RustSocket, group: VALUE) -> RbResult<()> {
570
+ let sock = ensure_socket(rb_self)?;
571
+ let bytes = Bytes::from(rb::value_to_bytes(group)?);
367
572
  let result = runtime::spawn_blocking(io_threads(), async move { sock.leave(bytes).await });
368
- result.map_err(|e| map_err(ruby, e))
573
+ result.map_err(map_err)
369
574
  }
370
575
 
371
- fn rust_socket_close(rb_self: &RustSocket) {
576
+ unsafe extern "C" fn rust_socket_leave(rb_self: VALUE, group: VALUE) -> VALUE {
577
+ rb::wrap(|| {
578
+ let rb_self = unsafe { rust_socket_ref(rb_self)? };
579
+ rust_socket_leave_impl(rb_self, group)?;
580
+ Ok(rb::qnil())
581
+ })
582
+ }
583
+
584
+ fn rust_socket_close_impl(rb_self: &RustSocket) {
372
585
  rb_self.closed.store(true, Ordering::Relaxed);
373
586
  let mat = rb_self.materialized.write().unwrap().take();
374
587
  if let Some(m) = mat {
@@ -391,88 +604,104 @@ fn rust_socket_close(rb_self: &RustSocket) {
391
604
  }
392
605
  }
393
606
 
394
- fn rust_socket_closed(rb_self: &RustSocket) -> bool {
607
+ unsafe extern "C" fn rust_socket_close(rb_self: VALUE) -> VALUE {
608
+ rb::wrap(|| {
609
+ let rb_self = unsafe { rust_socket_ref(rb_self)? };
610
+ rust_socket_close_impl(rb_self);
611
+ Ok(rb::qnil())
612
+ })
613
+ }
614
+
615
+ fn rust_socket_closed_impl(rb_self: &RustSocket) -> bool {
395
616
  rb_self.closed.load(Ordering::Relaxed)
396
617
  }
397
618
 
398
- fn rust_socket_type_name(rb_self: &RustSocket) -> &'static str {
399
- rb_self.socket_type.as_str()
619
+ unsafe extern "C" fn rust_socket_closed(rb_self: VALUE) -> VALUE {
620
+ rb::wrap(|| {
621
+ let rb_self = unsafe { rust_socket_ref(rb_self)? };
622
+ Ok(rb::bool_value(rust_socket_closed_impl(rb_self)))
623
+ })
400
624
  }
401
625
 
402
- fn ensure_socket(ruby: &Ruby, rb_self: &RustSocket) -> Result<Arc<omq_tokio::Socket>, Error> {
626
+ fn rust_socket_type_name_impl(rb_self: &RustSocket) -> RbResult<VALUE> {
627
+ rb::new_utf8_string(rb_self.socket_type.as_str())
628
+ }
629
+
630
+ unsafe extern "C" fn rust_socket_type_name(rb_self: VALUE) -> VALUE {
631
+ rb::wrap(|| {
632
+ let rb_self = unsafe { rust_socket_ref(rb_self)? };
633
+ rust_socket_type_name_impl(rb_self)
634
+ })
635
+ }
636
+
637
+ fn ensure_socket(rb_self: &RustSocket) -> RbResult<Arc<omq_tokio::Socket>> {
403
638
  let slot = rb_self.materialized.read().unwrap();
404
639
  slot.as_ref()
405
640
  .map(|m| m.socket.clone())
406
- .ok_or_else(|| Error::new(ruby.exception_runtime_error(), "socket not materialized"))
641
+ .ok_or_else(|| RubyErr::runtime("socket not materialized"))
407
642
  }
408
643
 
409
- fn ruby_parts_to_message(_ruby: &Ruby, parts: RArray) -> Result<omq_tokio::Message, Error> {
410
- let len = parts.len();
644
+ fn ruby_parts_to_message(parts: VALUE) -> RbResult<omq_tokio::Message> {
645
+ let len = rb::array_len(parts)?;
411
646
  if len == 1 {
412
- let part: RString = parts.entry(0)?;
413
- let data = unsafe { part.as_slice() }.to_vec();
647
+ let part = rb::array_entry(parts, 0)?;
648
+ let data = rb::value_to_bytes(part)?;
414
649
  Ok(omq_tokio::Message::from_slice(&data))
415
650
  } else {
416
651
  let mut frames: Vec<Bytes> = Vec::with_capacity(len);
417
652
  for i in 0..len {
418
- let part: RString = parts.entry(i as isize)?;
419
- let data = unsafe { part.as_slice() }.to_vec();
653
+ let part = rb::array_entry(parts, i)?;
654
+ let data = rb::value_to_bytes(part)?;
420
655
  frames.push(Bytes::from(data));
421
656
  }
422
657
  Ok(omq_tokio::Message::multipart(frames))
423
658
  }
424
659
  }
425
660
 
426
- fn message_to_ruby_parts(ruby: &Ruby, msg: omq_tokio::Message) -> Result<RArray, Error> {
427
- let arr = ruby.ary_new();
661
+ fn message_to_ruby_parts(msg: omq_tokio::Message) -> RbResult<VALUE> {
662
+ let arr = rb::array_new()?;
428
663
  for part in msg.iter() {
429
- let s = ruby.str_from_slice(&part);
430
- s.freeze();
431
- arr.push(s)?;
664
+ let s = rb::new_binary_string(&part)?;
665
+ rb::array_push(arr, s)?;
432
666
  }
433
667
  Ok(arr)
434
668
  }
435
669
 
436
- pub fn register(ruby: &Ruby) -> Result<(), Error> {
437
- let omq = ruby.define_module("OMQ")?;
438
- let rust = omq.define_module("Rust")?;
439
- let native = rust.define_module("Native")?;
440
-
441
- let class = native.define_class("RustSocket", ruby.class_object())?;
442
- class.define_singleton_method("new", function!(rust_socket_new, 1))?;
443
- class.define_method("set_options", method!(rust_socket_set_options, 1))?;
444
- class.define_method("materialize", method!(rust_socket_materialize, 0))?;
445
- class.define_method("bind", method!(rust_socket_bind, 1))?;
446
- class.define_method("connect", method!(rust_socket_connect, 1))?;
447
- class.define_method("disconnect", method!(rust_socket_disconnect, 1))?;
448
- class.define_method("unbind", method!(rust_socket_unbind, 1))?;
449
- class.define_method("enqueue_send", method!(rust_socket_enqueue_send, 1))?;
450
- class.define_method("try_recv", method!(rust_socket_try_recv, 0))?;
451
- class.define_method("try_recv_batch", method!(rust_socket_try_recv_batch, 0))?;
452
- class.define_method("wake_recv", method!(rust_socket_wake_recv, 0))?;
453
- class.define_method("recv_fd", method!(rust_socket_recv_fd, 0))?;
454
- class.define_method("send_fd", method!(rust_socket_send_fd, 0))?;
455
- class.define_method(
456
- "peer_connected_fd",
457
- method!(rust_socket_peer_connected_fd, 0),
458
- )?;
459
- class.define_method(
460
- "all_peers_gone_fd",
461
- method!(rust_socket_all_peers_gone_fd, 0),
462
- )?;
463
- class.define_method(
464
- "subscriber_joined_fd",
465
- method!(rust_socket_subscriber_joined_fd, 0),
466
- )?;
467
- class.define_method("monitor_fd", method!(rust_socket_monitor_fd, 0))?;
468
- class.define_method("try_recv_monitor", method!(rust_socket_try_recv_monitor, 0))?;
469
- class.define_method("subscribe", method!(rust_socket_subscribe, 1))?;
470
- class.define_method("unsubscribe", method!(rust_socket_unsubscribe, 1))?;
471
- class.define_method("join", method!(rust_socket_join, 1))?;
472
- class.define_method("leave", method!(rust_socket_leave, 1))?;
473
- class.define_method("close", method!(rust_socket_close, 0))?;
474
- class.define_method("closed?", method!(rust_socket_closed, 0))?;
475
- class.define_method("socket_type_name", method!(rust_socket_type_name, 0))?;
670
+ pub fn register(native: VALUE) -> RbResult<()> {
671
+ let class = unsafe { rb::define_class_under(native, c"RustSocket", rb_sys::rb_cObject)? };
672
+
673
+ unsafe {
674
+ rb::undef_alloc_func(class)?;
675
+ rb::define_singleton_method_1(class, c"new", rust_socket_new)?;
676
+ rb::define_method_1(class, c"set_options", rust_socket_set_options)?;
677
+ rb::define_method_0(class, c"materialize", rust_socket_materialize)?;
678
+ rb::define_method_1(class, c"bind", rust_socket_bind)?;
679
+ rb::define_method_1(class, c"connect", rust_socket_connect)?;
680
+ rb::define_method_1(class, c"disconnect", rust_socket_disconnect)?;
681
+ rb::define_method_1(class, c"unbind", rust_socket_unbind)?;
682
+ rb::define_method_1(class, c"enqueue_send", rust_socket_enqueue_send)?;
683
+ rb::define_method_0(class, c"try_recv", rust_socket_try_recv)?;
684
+ rb::define_method_0(class, c"try_recv_batch", rust_socket_try_recv_batch)?;
685
+ rb::define_method_0(class, c"wake_recv", rust_socket_wake_recv)?;
686
+ rb::define_method_0(class, c"recv_fd", rust_socket_recv_fd)?;
687
+ rb::define_method_0(class, c"send_fd", rust_socket_send_fd)?;
688
+ rb::define_method_0(class, c"peer_connected_fd", rust_socket_peer_connected_fd)?;
689
+ rb::define_method_0(class, c"all_peers_gone_fd", rust_socket_all_peers_gone_fd)?;
690
+ rb::define_method_0(
691
+ class,
692
+ c"subscriber_joined_fd",
693
+ rust_socket_subscriber_joined_fd,
694
+ )?;
695
+ rb::define_method_0(class, c"monitor_fd", rust_socket_monitor_fd)?;
696
+ rb::define_method_0(class, c"try_recv_monitor", rust_socket_try_recv_monitor)?;
697
+ rb::define_method_1(class, c"subscribe", rust_socket_subscribe)?;
698
+ rb::define_method_1(class, c"unsubscribe", rust_socket_unsubscribe)?;
699
+ rb::define_method_1(class, c"join", rust_socket_join)?;
700
+ rb::define_method_1(class, c"leave", rust_socket_leave)?;
701
+ rb::define_method_0(class, c"close", rust_socket_close)?;
702
+ rb::define_method_0(class, c"closed?", rust_socket_closed)?;
703
+ rb::define_method_0(class, c"socket_type_name", rust_socket_type_name)?;
704
+ }
476
705
 
477
706
  Ok(())
478
707
  }