omq-backend-rust 0.2.0 → 0.3.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,707 +0,0 @@
1
- use std::ffi::c_void;
2
- use std::panic::{AssertUnwindSafe, catch_unwind};
3
- use std::str::FromStr;
4
- use std::sync::atomic::{AtomicBool, Ordering};
5
- use std::sync::{Arc, Mutex, OnceLock, RwLock};
6
-
7
- use bytes::Bytes;
8
- use rb_sys::{VALUE, rb_data_type_struct__bindgen_ty_1, rb_data_type_t, size_t};
9
-
10
- use crate::error::map_err;
11
- use crate::notify::PipeNotify;
12
- use crate::rb::{self, RbResult, RubyErr};
13
- use crate::runtime::{self, Materialized};
14
-
15
- static IO_THREADS: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(1);
16
-
17
- pub fn set_io_threads(n: usize) {
18
- IO_THREADS.store(n, Ordering::Relaxed);
19
- }
20
-
21
- fn io_threads() -> usize {
22
- IO_THREADS.load(Ordering::Relaxed)
23
- }
24
-
25
- pub struct RustSocket {
26
- socket_type: omq_tokio::SocketType,
27
- options: Mutex<Option<omq_tokio::Options>>,
28
- materialized: RwLock<Option<Materialized>>,
29
- closed: AtomicBool,
30
- linger: Mutex<Option<std::time::Duration>>,
31
- }
32
-
33
- unsafe impl Send for RustSocket {}
34
- unsafe impl Sync for RustSocket {}
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
-
89
- fn parse_socket_type(s: &str) -> Result<omq_tokio::SocketType, String> {
90
- match s {
91
- "REQ" => Ok(omq_tokio::SocketType::Req),
92
- "REP" => Ok(omq_tokio::SocketType::Rep),
93
- "PUB" => Ok(omq_tokio::SocketType::Pub),
94
- "SUB" => Ok(omq_tokio::SocketType::Sub),
95
- "XPUB" => Ok(omq_tokio::SocketType::XPub),
96
- "XSUB" => Ok(omq_tokio::SocketType::XSub),
97
- "PUSH" => Ok(omq_tokio::SocketType::Push),
98
- "PULL" => Ok(omq_tokio::SocketType::Pull),
99
- "DEALER" => Ok(omq_tokio::SocketType::Dealer),
100
- "ROUTER" => Ok(omq_tokio::SocketType::Router),
101
- "PAIR" => Ok(omq_tokio::SocketType::Pair),
102
- "CLIENT" => Ok(omq_tokio::SocketType::Client),
103
- "SERVER" => Ok(omq_tokio::SocketType::Server),
104
- "RADIO" => Ok(omq_tokio::SocketType::Radio),
105
- "DISH" => Ok(omq_tokio::SocketType::Dish),
106
- "SCATTER" => Ok(omq_tokio::SocketType::Scatter),
107
- "GATHER" => Ok(omq_tokio::SocketType::Gather),
108
- "CHANNEL" => Ok(omq_tokio::SocketType::Channel),
109
- "PEER" => Ok(omq_tokio::SocketType::Peer),
110
- _ => Err(format!("unknown socket type: {s}")),
111
- }
112
- }
113
-
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))
134
- }
135
-
136
- fn rust_socket_set_options_impl(rb_self: &RustSocket, hash: VALUE) -> RbResult<()> {
137
- let opts = crate::options::build_options(hash)?;
138
- *rb_self.linger.lock().unwrap() = opts.linger;
139
- *rb_self.options.lock().unwrap() = Some(opts);
140
- Ok(())
141
- }
142
-
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<()> {
152
- if rb_self.closed.load(Ordering::Relaxed) {
153
- return Err(RubyErr::io("socket closed"));
154
- }
155
- {
156
- let slot = rb_self.materialized.read().unwrap();
157
- if slot.is_some() {
158
- return Ok(());
159
- }
160
- }
161
- let mut slot = rb_self.materialized.write().unwrap();
162
- if slot.is_some() {
163
- return Ok(());
164
- }
165
-
166
- let opts = rb_self.options.lock().unwrap().take().unwrap_or_default();
167
- let send_cap = opts.send_hwm.max(1) as usize;
168
- let recv_cap = opts.recv_hwm.max(1) as usize;
169
- let (send_prod, send_cons) = yring::async_spsc(send_cap);
170
- let (recv_prod, recv_cons) = yring::spsc(recv_cap);
171
- let recv_notify = Arc::new(PipeNotify::new());
172
- let send_notify = Arc::new(PipeNotify::new());
173
- let recv_space = Arc::new(tokio::sync::Notify::new());
174
-
175
- let (monitor_tx, monitor_rx) = flume::bounded(64);
176
- let monitor_notify = Arc::new(PipeNotify::new());
177
- let peer_connected_notify = Arc::new(PipeNotify::new());
178
- let all_peers_gone_notify = Arc::new(PipeNotify::new());
179
- let subscriber_joined_notify = Arc::new(PipeNotify::new());
180
-
181
- let (socket, send_pump, recv_pump, monitor_pump) = runtime::materialize(
182
- io_threads(),
183
- rb_self.socket_type,
184
- opts,
185
- send_cons,
186
- recv_prod,
187
- recv_notify.clone(),
188
- send_notify.clone(),
189
- recv_space.clone(),
190
- monitor_tx,
191
- monitor_notify.clone(),
192
- peer_connected_notify.clone(),
193
- all_peers_gone_notify.clone(),
194
- subscriber_joined_notify.clone(),
195
- );
196
-
197
- *slot = Some(Materialized {
198
- socket,
199
- send_prod: Mutex::new(send_prod),
200
- recv_cons: Mutex::new(recv_cons),
201
- recv_notify,
202
- send_notify,
203
- recv_space,
204
- send_pump,
205
- recv_pump,
206
- monitor_rx,
207
- monitor_notify,
208
- peer_connected_notify,
209
- all_peers_gone_notify,
210
- subscriber_joined_notify,
211
- monitor_pump,
212
- });
213
- Ok(())
214
- }
215
-
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)?;
228
- let result = runtime::spawn_blocking(io_threads(), async move { sock.bind(ep).await });
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
- })
238
- }
239
-
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)?;
244
- let result = runtime::spawn_blocking(io_threads(), async move { sock.connect(ep).await });
245
- result.map_err(map_err)
246
- }
247
-
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)?;
260
- let result = runtime::spawn_blocking(io_threads(), async move { sock.disconnect(ep).await });
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
- })
270
- }
271
-
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)?;
276
- let result = runtime::spawn_blocking(io_threads(), async move { sock.unbind(ep).await });
277
- result.map_err(map_err)
278
- }
279
-
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> {
289
- let mat_guard = rb_self.materialized.read().unwrap();
290
- let mat = mat_guard
291
- .as_ref()
292
- .ok_or_else(|| RubyErr::runtime("socket not materialized"))?;
293
-
294
- let msg = ruby_parts_to_message(parts)?;
295
- let mut prod = mat.send_prod.lock().unwrap();
296
- match prod.push(msg) {
297
- Ok(()) => {
298
- prod.flush();
299
- rb::symbol("ok")
300
- }
301
- Err(returned) => {
302
- prod.flush();
303
- match prod.push(returned) {
304
- Ok(()) => {
305
- prod.flush();
306
- rb::symbol("ok")
307
- }
308
- Err(_) => rb::symbol("full"),
309
- }
310
- }
311
- }
312
- }
313
-
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> {
322
- let mat_guard = rb_self.materialized.read().unwrap();
323
- let mat = match mat_guard.as_ref() {
324
- Some(m) => m,
325
- None => return Ok(rb::qnil()),
326
- };
327
-
328
- let mut cons = mat.recv_cons.lock().unwrap();
329
- match cons.prefetch_and_pop() {
330
- Some(msg) => {
331
- mat.recv_space.notify_one();
332
- message_to_ruby_parts(msg)
333
- }
334
- None => Ok(rb::qnil()),
335
- }
336
- }
337
-
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> {
346
- let mat_guard = rb_self.materialized.read().unwrap();
347
- let mat = match mat_guard.as_ref() {
348
- Some(m) => m,
349
- None => return Ok(rb::qnil()),
350
- };
351
-
352
- let mut cons = mat.recv_cons.lock().unwrap();
353
- let count = cons.prefetch();
354
- if count == 0 {
355
- return Ok(rb::qnil());
356
- }
357
-
358
- let batch = rb::array_new_capa(count)?;
359
- let mut popped = 0usize;
360
- while let Some(msg) = cons.pop() {
361
- rb::array_push(batch, message_to_ruby_parts(msg)?)?;
362
- popped += 1;
363
- }
364
- cons.release();
365
-
366
- if popped > 0 {
367
- mat.recv_space.notify_one();
368
- Ok(batch)
369
- } else {
370
- Ok(rb::qnil())
371
- }
372
- }
373
-
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) {
382
- let mat_guard = rb_self.materialized.read().unwrap();
383
- if let Some(mat) = mat_guard.as_ref() {
384
- mat.recv_notify.force_wake();
385
- }
386
- }
387
-
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> {
397
- let mat_guard = rb_self.materialized.read().unwrap();
398
- let mat = mat_guard
399
- .as_ref()
400
- .ok_or_else(|| RubyErr::runtime("socket not materialized"))?;
401
- mat.recv_notify.park_begin();
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
- })
410
- }
411
-
412
- fn rust_socket_send_fd_impl(rb_self: &RustSocket) -> RbResult<VALUE> {
413
- let mat_guard = rb_self.materialized.read().unwrap();
414
- let mat = mat_guard
415
- .as_ref()
416
- .ok_or_else(|| RubyErr::runtime("socket not materialized"))?;
417
- mat.send_notify.park_begin();
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
- })
426
- }
427
-
428
- fn rust_socket_peer_connected_fd_impl(rb_self: &RustSocket) -> RbResult<VALUE> {
429
- let mat_guard = rb_self.materialized.read().unwrap();
430
- let mat = mat_guard
431
- .as_ref()
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
- })
441
- }
442
-
443
- fn rust_socket_all_peers_gone_fd_impl(rb_self: &RustSocket) -> RbResult<VALUE> {
444
- let mat_guard = rb_self.materialized.read().unwrap();
445
- let mat = mat_guard
446
- .as_ref()
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
- })
456
- }
457
-
458
- fn rust_socket_subscriber_joined_fd_impl(rb_self: &RustSocket) -> RbResult<VALUE> {
459
- let mat_guard = rb_self.materialized.read().unwrap();
460
- let mat = mat_guard
461
- .as_ref()
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
- })
471
- }
472
-
473
- fn rust_socket_monitor_fd_impl(rb_self: &RustSocket) -> RbResult<VALUE> {
474
- let mat_guard = rb_self.materialized.read().unwrap();
475
- let mat = mat_guard
476
- .as_ref()
477
- .ok_or_else(|| RubyErr::runtime("socket not materialized"))?;
478
- mat.monitor_notify.park_begin();
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
- })
487
- }
488
-
489
- fn rust_socket_try_recv_monitor_impl(rb_self: &RustSocket) -> RbResult<VALUE> {
490
- let mat_guard = rb_self.materialized.read().unwrap();
491
- let mat = match mat_guard.as_ref() {
492
- Some(m) => m,
493
- None => return Ok(rb::qnil()),
494
- };
495
-
496
- match mat.monitor_rx.try_recv() {
497
- Ok(data) => {
498
- let hash = rb::hash_new()?;
499
- rb::hash_aset(hash, rb::symbol("type")?, rb::symbol(data.event_type)?)?;
500
- if let Some(ep) = data.endpoint {
501
- rb::hash_aset(hash, rb::symbol("endpoint")?, rb::new_utf8_string(&ep)?)?;
502
- }
503
- if !data.detail.is_empty() {
504
- let detail = rb::hash_new()?;
505
- for (k, v) in &data.detail {
506
- rb::hash_aset(detail, rb::symbol(k)?, rb::new_utf8_string(v)?)?;
507
- }
508
- rb::hash_aset(hash, rb::symbol("detail")?, detail)?;
509
- }
510
- Ok(hash)
511
- }
512
- Err(_) => Ok(rb::qnil()),
513
- }
514
- }
515
-
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)?);
526
- let result = runtime::spawn_blocking(io_threads(), async move { sock.subscribe(bytes).await });
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
- })
536
- }
537
-
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)?);
541
- let result =
542
- runtime::spawn_blocking(io_threads(), async move { sock.unsubscribe(bytes).await });
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
- })
552
- }
553
-
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)?);
557
- let result = runtime::spawn_blocking(io_threads(), async move { sock.join(bytes).await });
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
- })
567
- }
568
-
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)?);
572
- let result = runtime::spawn_blocking(io_threads(), async move { sock.leave(bytes).await });
573
- result.map_err(map_err)
574
- }
575
-
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) {
585
- rb_self.closed.store(true, Ordering::Relaxed);
586
- let mat = rb_self.materialized.write().unwrap().take();
587
- if let Some(m) = mat {
588
- m.recv_notify.force_wake();
589
- m.send_notify.force_wake();
590
- m.peer_connected_notify.force_wake();
591
- m.all_peers_gone_notify.force_wake();
592
- m.subscriber_joined_notify.force_wake();
593
- m.monitor_notify.force_wake();
594
- let linger = *rb_self.linger.lock().unwrap();
595
- runtime::destroy_socket(
596
- io_threads(),
597
- m.socket,
598
- m.send_prod,
599
- m.send_pump,
600
- m.recv_pump,
601
- m.monitor_pump,
602
- linger,
603
- );
604
- }
605
- }
606
-
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 {
616
- rb_self.closed.load(Ordering::Relaxed)
617
- }
618
-
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
- })
624
- }
625
-
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>> {
638
- let slot = rb_self.materialized.read().unwrap();
639
- slot.as_ref()
640
- .map(|m| m.socket.clone())
641
- .ok_or_else(|| RubyErr::runtime("socket not materialized"))
642
- }
643
-
644
- fn ruby_parts_to_message(parts: VALUE) -> RbResult<omq_tokio::Message> {
645
- let len = rb::array_len(parts)?;
646
- if len == 1 {
647
- let part = rb::array_entry(parts, 0)?;
648
- let data = rb::value_to_bytes(part)?;
649
- Ok(omq_tokio::Message::from_slice(&data))
650
- } else {
651
- let mut frames: Vec<Bytes> = Vec::with_capacity(len);
652
- for i in 0..len {
653
- let part = rb::array_entry(parts, i)?;
654
- let data = rb::value_to_bytes(part)?;
655
- frames.push(Bytes::from(data));
656
- }
657
- Ok(omq_tokio::Message::multipart(frames))
658
- }
659
- }
660
-
661
- fn message_to_ruby_parts(msg: omq_tokio::Message) -> RbResult<VALUE> {
662
- let arr = rb::array_new()?;
663
- for part in msg.iter() {
664
- let s = rb::new_binary_string(&part)?;
665
- rb::array_push(arr, s)?;
666
- }
667
- Ok(arr)
668
- }
669
-
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
- }
705
-
706
- Ok(())
707
- }