1use std::{
17 ffi::c_char,
18 ops::{Deref, DerefMut},
19};
20
21use nautilus_core::{
22 UnixNanos,
23 correctness::FAILED,
24 ffi::{
25 cvec::CVec,
26 parsing::u8_as_bool,
27 string::{cstr_as_str, str_to_cstr},
28 },
29};
30#[cfg(feature = "python")]
31use pyo3::{ffi, prelude::*};
32
33use super::timer::TimeEventHandler;
34use crate::{
35 clock::{Clock, TestClock},
36 live::clock::LiveClock,
37 timer::{TimeEvent, TimeEventCallback},
38};
39
40#[repr(C)]
49#[allow(non_camel_case_types)]
50#[derive(Debug)]
51pub struct TestClock_API(Box<TestClock>);
52
53impl Deref for TestClock_API {
54 type Target = TestClock;
55
56 fn deref(&self) -> &Self::Target {
57 &self.0
58 }
59}
60
61impl DerefMut for TestClock_API {
62 fn deref_mut(&mut self) -> &mut Self::Target {
63 &mut self.0
64 }
65}
66
67#[unsafe(no_mangle)]
68pub extern "C" fn test_clock_new() -> TestClock_API {
69 TestClock_API(Box::default())
70}
71
72#[unsafe(no_mangle)]
73pub extern "C" fn test_clock_drop(clock: TestClock_API) {
74 drop(clock); }
76
77#[cfg(feature = "python")]
87#[unsafe(no_mangle)]
88pub unsafe extern "C" fn test_clock_register_default_handler(
89 clock: &mut TestClock_API,
90 callback_ptr: *mut ffi::PyObject,
91) {
92 assert!(!callback_ptr.is_null());
93 assert!(unsafe { ffi::Py_None() } != callback_ptr);
94
95 let callback = Python::attach(|py| unsafe { Py::<PyAny>::from_borrowed_ptr(py, callback_ptr) });
96 let callback = TimeEventCallback::from(callback);
97
98 clock.register_default_handler(callback);
99}
100
101#[unsafe(no_mangle)]
102pub extern "C" fn test_clock_set_time(clock: &TestClock_API, to_time_ns: u64) {
103 clock.set_time(to_time_ns.into());
104}
105
106#[unsafe(no_mangle)]
107pub extern "C" fn test_clock_timestamp(clock: &TestClock_API) -> f64 {
108 clock.get_time()
109}
110
111#[unsafe(no_mangle)]
112pub extern "C" fn test_clock_timestamp_ms(clock: &TestClock_API) -> u64 {
113 clock.get_time_ms()
114}
115
116#[unsafe(no_mangle)]
117pub extern "C" fn test_clock_timestamp_us(clock: &TestClock_API) -> u64 {
118 clock.get_time_us()
119}
120
121#[unsafe(no_mangle)]
122pub extern "C" fn test_clock_timestamp_ns(clock: &TestClock_API) -> u64 {
123 clock.get_time_ns().as_u64()
124}
125
126#[unsafe(no_mangle)]
127pub extern "C" fn test_clock_timer_names(clock: &TestClock_API) -> *const c_char {
128 str_to_cstr(&clock.timer_names().join("<,>"))
131}
132
133#[unsafe(no_mangle)]
134pub extern "C" fn test_clock_timer_count(clock: &mut TestClock_API) -> usize {
135 clock.timer_count()
136}
137
138#[cfg(feature = "python")]
148#[unsafe(no_mangle)]
149pub unsafe extern "C" fn test_clock_set_time_alert(
150 clock: &mut TestClock_API,
151 name_ptr: *const c_char,
152 alert_time_ns: UnixNanos,
153 callback_ptr: *mut ffi::PyObject,
154 allow_past: u8,
155) {
156 assert!(!callback_ptr.is_null());
157
158 let name = unsafe { cstr_as_str(name_ptr) };
159 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
160 None
161 } else {
162 let callback =
163 Python::attach(|py| unsafe { Py::<PyAny>::from_borrowed_ptr(py, callback_ptr) });
164 Some(TimeEventCallback::from(callback))
165 };
166
167 clock
168 .set_time_alert_ns(name, alert_time_ns, callback, Some(allow_past != 0))
169 .expect(FAILED);
170}
171
172#[cfg(feature = "python")]
187#[unsafe(no_mangle)]
188pub unsafe extern "C" fn test_clock_set_timer(
189 clock: &mut TestClock_API,
190 name_ptr: *const c_char,
191 interval_ns: u64,
192 start_time_ns: UnixNanos,
193 stop_time_ns: UnixNanos,
194 callback_ptr: *mut ffi::PyObject,
195 allow_past: u8,
196 fire_immediately: u8,
197) {
198 assert!(!callback_ptr.is_null());
199
200 let name = unsafe { cstr_as_str(name_ptr) };
201 let start_time_ns = (start_time_ns != 0).then_some(start_time_ns);
203 let stop_time_ns = (stop_time_ns != 0).then_some(stop_time_ns);
204 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
205 None
206 } else {
207 let callback =
208 Python::attach(|py| unsafe { Py::<PyAny>::from_borrowed_ptr(py, callback_ptr) });
209 Some(TimeEventCallback::from(callback))
210 };
211
212 clock
213 .set_timer_ns(
214 name,
215 interval_ns,
216 start_time_ns,
217 stop_time_ns,
218 callback,
219 Some(allow_past != 0),
220 Some(fire_immediately != 0),
221 )
222 .expect(FAILED);
223}
224
225#[unsafe(no_mangle)]
229pub unsafe extern "C" fn test_clock_advance_time(
230 clock: &mut TestClock_API,
231 to_time_ns: u64,
232 set_time: u8,
233) -> CVec {
234 let events: Vec<TimeEvent> = clock.advance_time(to_time_ns.into(), u8_as_bool(set_time));
235 let t: Vec<TimeEventHandler> = clock
236 .match_handlers(events)
237 .into_iter()
238 .map(Into::into)
239 .collect();
240 t.into()
241}
242
243#[allow(clippy::drop_non_drop)]
251#[unsafe(no_mangle)]
252pub extern "C" fn vec_time_event_handlers_drop(v: CVec) {
253 let CVec { ptr, len, cap } = v;
254
255 assert!(
256 len <= cap,
257 "vec_time_event_handlers_drop: len ({len}) > cap ({cap}) - memory corruption or wrong drop helper"
258 );
259 assert!(
260 len == 0 || !ptr.is_null(),
261 "vec_time_event_handlers_drop: null ptr with non-zero len ({len}) - memory corruption or wrong drop helper"
262 );
263
264 let data: Vec<TimeEventHandler> =
265 unsafe { Vec::from_raw_parts(ptr.cast::<TimeEventHandler>(), len, cap) };
266 drop(data); }
268
269#[unsafe(no_mangle)]
273pub unsafe extern "C" fn test_clock_next_time(
274 clock: &mut TestClock_API,
275 name_ptr: *const c_char,
276) -> UnixNanos {
277 let name = unsafe { cstr_as_str(name_ptr) };
278 clock.next_time_ns(name).unwrap_or_default()
279}
280
281#[unsafe(no_mangle)]
285pub unsafe extern "C" fn test_clock_cancel_timer(
286 clock: &mut TestClock_API,
287 name_ptr: *const c_char,
288) {
289 let name = unsafe { cstr_as_str(name_ptr) };
290 clock.cancel_timer(name);
291}
292
293#[unsafe(no_mangle)]
294pub extern "C" fn test_clock_cancel_timers(clock: &mut TestClock_API) {
295 clock.cancel_timers();
296}
297
298#[repr(C)]
308#[allow(non_camel_case_types)]
309#[derive(Debug)]
310pub struct LiveClock_API(Box<LiveClock>);
311
312impl Deref for LiveClock_API {
313 type Target = LiveClock;
314
315 fn deref(&self) -> &Self::Target {
316 &self.0
317 }
318}
319
320impl DerefMut for LiveClock_API {
321 fn deref_mut(&mut self) -> &mut Self::Target {
322 &mut self.0
323 }
324}
325
326#[unsafe(no_mangle)]
327pub extern "C" fn live_clock_new() -> LiveClock_API {
328 LiveClock_API(Box::new(LiveClock::new(None)))
330}
331
332#[unsafe(no_mangle)]
333pub extern "C" fn live_clock_drop(clock: LiveClock_API) {
334 drop(clock); }
336
337#[cfg(feature = "python")]
345#[unsafe(no_mangle)]
346pub unsafe extern "C" fn live_clock_register_default_handler(
347 clock: &mut LiveClock_API,
348 callback_ptr: *mut ffi::PyObject,
349) {
350 assert!(!callback_ptr.is_null());
351 assert!(unsafe { ffi::Py_None() } != callback_ptr);
352
353 let callback = Python::attach(|py| unsafe { Py::<PyAny>::from_borrowed_ptr(py, callback_ptr) });
354 let callback = TimeEventCallback::from(callback);
355
356 clock.register_default_handler(callback);
357}
358
359#[unsafe(no_mangle)]
360pub extern "C" fn live_clock_timestamp(clock: &mut LiveClock_API) -> f64 {
361 clock.get_time()
362}
363
364#[unsafe(no_mangle)]
365pub extern "C" fn live_clock_timestamp_ms(clock: &mut LiveClock_API) -> u64 {
366 clock.get_time_ms()
367}
368
369#[unsafe(no_mangle)]
370pub extern "C" fn live_clock_timestamp_us(clock: &mut LiveClock_API) -> u64 {
371 clock.get_time_us()
372}
373
374#[unsafe(no_mangle)]
375pub extern "C" fn live_clock_timestamp_ns(clock: &mut LiveClock_API) -> u64 {
376 clock.get_time_ns().as_u64()
377}
378
379#[unsafe(no_mangle)]
380pub extern "C" fn live_clock_timer_names(clock: &LiveClock_API) -> *const c_char {
381 str_to_cstr(&clock.timer_names().join("<,>"))
384}
385
386#[unsafe(no_mangle)]
387pub extern "C" fn live_clock_timer_count(clock: &mut LiveClock_API) -> usize {
388 clock.timer_count()
389}
390
391#[cfg(feature = "python")]
403#[unsafe(no_mangle)]
404pub unsafe extern "C" fn live_clock_set_time_alert(
405 clock: &mut LiveClock_API,
406 name_ptr: *const c_char,
407 alert_time_ns: UnixNanos,
408 callback_ptr: *mut ffi::PyObject,
409 allow_past: u8,
410) {
411 assert!(!callback_ptr.is_null());
412
413 let name = unsafe { cstr_as_str(name_ptr) };
414 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
415 None
416 } else {
417 let callback =
418 Python::attach(|py| unsafe { Py::<PyAny>::from_borrowed_ptr(py, callback_ptr) });
419 Some(TimeEventCallback::from(callback))
420 };
421
422 clock
423 .set_time_alert_ns(name, alert_time_ns, callback, Some(allow_past != 0))
424 .expect(FAILED);
425}
426
427#[cfg(feature = "python")]
444#[unsafe(no_mangle)]
445pub unsafe extern "C" fn live_clock_set_timer(
446 clock: &mut LiveClock_API,
447 name_ptr: *const c_char,
448 interval_ns: u64,
449 start_time_ns: UnixNanos,
450 stop_time_ns: UnixNanos,
451 callback_ptr: *mut ffi::PyObject,
452 allow_past: u8,
453 fire_immediately: u8,
454) {
455 assert!(!callback_ptr.is_null());
456
457 let name = unsafe { cstr_as_str(name_ptr) };
458 let start_time_ns = (start_time_ns != 0).then_some(start_time_ns);
460 let stop_time_ns = (stop_time_ns != 0).then_some(stop_time_ns);
461 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
462 None
463 } else {
464 let callback =
465 Python::attach(|py| unsafe { Py::<PyAny>::from_borrowed_ptr(py, callback_ptr) });
466 Some(TimeEventCallback::from(callback))
467 };
468
469 clock
470 .set_timer_ns(
471 name,
472 interval_ns,
473 start_time_ns,
474 stop_time_ns,
475 callback,
476 Some(allow_past != 0),
477 Some(fire_immediately != 0),
478 )
479 .expect(FAILED);
480}
481
482#[unsafe(no_mangle)]
486pub unsafe extern "C" fn live_clock_next_time(
487 clock: &mut LiveClock_API,
488 name_ptr: *const c_char,
489) -> UnixNanos {
490 let name = unsafe { cstr_as_str(name_ptr) };
491 clock.next_time_ns(name).unwrap_or_default()
492}
493
494#[unsafe(no_mangle)]
498pub unsafe extern "C" fn live_clock_cancel_timer(
499 clock: &mut LiveClock_API,
500 name_ptr: *const c_char,
501) {
502 let name = unsafe { cstr_as_str(name_ptr) };
503 clock.cancel_timer(name);
504}
505
506#[unsafe(no_mangle)]
507pub extern "C" fn live_clock_cancel_timers(clock: &mut LiveClock_API) {
508 clock.cancel_timers();
509}