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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -0
- data/ext/omq_backend_rust/Cargo.toml +3 -4
- data/ext/omq_backend_rust/build.rs +23 -0
- data/ext/omq_backend_rust/src/error.rs +11 -10
- data/ext/omq_backend_rust/src/lib.rs +35 -10
- data/ext/omq_backend_rust/src/options.rs +117 -104
- data/ext/omq_backend_rust/src/rb.rs +433 -0
- data/ext/omq_backend_rust/src/runtime.rs +45 -99
- data/ext/omq_backend_rust/src/socket.rs +395 -166
- data/lib/omq/rust/engine.rb +64 -24
- data/lib/omq/rust/fd_watcher.rb +184 -0
- data/lib/omq/rust/version.rb +1 -1
- metadata +4 -1
|
@@ -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
|
|
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
|
|
61
|
-
let
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
|
72
|
-
let opts = crate::options::build_options(
|
|
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
|
|
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(
|
|
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
|
|
144
|
-
|
|
145
|
-
|
|
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
|
-
|
|
149
|
-
|
|
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
|
|
153
|
-
let sock = ensure_socket(
|
|
154
|
-
let
|
|
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(
|
|
245
|
+
result.map_err(map_err)
|
|
157
246
|
}
|
|
158
247
|
|
|
159
|
-
fn
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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(
|
|
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
|
|
171
|
-
let sock = ensure_socket(
|
|
172
|
-
let
|
|
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(
|
|
277
|
+
result.map_err(map_err)
|
|
175
278
|
}
|
|
176
279
|
|
|
177
|
-
fn
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
)
|
|
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(||
|
|
292
|
+
.ok_or_else(|| RubyErr::runtime("socket not materialized"))?;
|
|
186
293
|
|
|
187
|
-
let msg = ruby_parts_to_message(
|
|
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
|
-
|
|
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
|
-
|
|
306
|
+
rb::symbol("ok")
|
|
200
307
|
}
|
|
201
|
-
Err(_) =>
|
|
308
|
+
Err(_) => rb::symbol("full"),
|
|
202
309
|
}
|
|
203
310
|
}
|
|
204
311
|
}
|
|
205
312
|
}
|
|
206
313
|
|
|
207
|
-
fn
|
|
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(
|
|
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
|
-
|
|
332
|
+
message_to_ruby_parts(msg)
|
|
219
333
|
}
|
|
220
|
-
None => Ok(
|
|
334
|
+
None => Ok(rb::qnil()),
|
|
221
335
|
}
|
|
222
336
|
}
|
|
223
337
|
|
|
224
|
-
fn
|
|
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(
|
|
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(
|
|
355
|
+
return Ok(rb::qnil());
|
|
235
356
|
}
|
|
236
357
|
|
|
237
|
-
let batch =
|
|
358
|
+
let batch = rb::array_new_capa(count)?;
|
|
238
359
|
let mut popped = 0usize;
|
|
239
360
|
while let Some(msg) = cons.pop() {
|
|
240
|
-
batch
|
|
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(
|
|
368
|
+
Ok(batch)
|
|
248
369
|
} else {
|
|
249
|
-
Ok(
|
|
370
|
+
Ok(rb::qnil())
|
|
250
371
|
}
|
|
251
372
|
}
|
|
252
373
|
|
|
253
|
-
fn
|
|
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
|
|
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(||
|
|
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
|
|
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(||
|
|
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
|
|
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(||
|
|
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
|
|
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(||
|
|
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
|
|
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(||
|
|
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
|
|
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(||
|
|
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
|
|
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(
|
|
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 =
|
|
321
|
-
hash
|
|
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
|
|
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 =
|
|
504
|
+
let detail = rb::hash_new()?;
|
|
327
505
|
for (k, v) in &data.detail {
|
|
328
|
-
detail
|
|
506
|
+
rb::hash_aset(detail, rb::symbol(k)?, rb::new_utf8_string(v)?)?;
|
|
329
507
|
}
|
|
330
|
-
hash
|
|
508
|
+
rb::hash_aset(hash, rb::symbol("detail")?, detail)?;
|
|
331
509
|
}
|
|
332
|
-
Ok(
|
|
510
|
+
Ok(hash)
|
|
333
511
|
}
|
|
334
|
-
Err(_) => Ok(
|
|
512
|
+
Err(_) => Ok(rb::qnil()),
|
|
335
513
|
}
|
|
336
514
|
}
|
|
337
515
|
|
|
338
|
-
fn
|
|
339
|
-
|
|
340
|
-
|
|
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(
|
|
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
|
|
346
|
-
|
|
347
|
-
|
|
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(
|
|
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
|
|
358
|
-
let sock = ensure_socket(
|
|
359
|
-
let bytes = Bytes::from(
|
|
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(
|
|
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
|
|
365
|
-
let sock = ensure_socket(
|
|
366
|
-
let bytes = Bytes::from(
|
|
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(
|
|
573
|
+
result.map_err(map_err)
|
|
369
574
|
}
|
|
370
575
|
|
|
371
|
-
fn
|
|
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
|
|
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
|
|
399
|
-
|
|
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
|
|
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(||
|
|
641
|
+
.ok_or_else(|| RubyErr::runtime("socket not materialized"))
|
|
407
642
|
}
|
|
408
643
|
|
|
409
|
-
fn ruby_parts_to_message(
|
|
410
|
-
let len = parts
|
|
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
|
|
413
|
-
let data =
|
|
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
|
|
419
|
-
let data =
|
|
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(
|
|
427
|
-
let arr =
|
|
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 =
|
|
430
|
-
s
|
|
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(
|
|
437
|
-
let
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
"
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
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
|
}
|