1use std::{
17 ffi::c_char,
18 ops::{Deref, DerefMut},
19};
20
21#[cfg(feature = "python")]
22use nautilus_core::correctness::FAILED;
23use nautilus_core::{
24 UnixNanos,
25 ffi::{
26 cvec::CVec,
27 parsing::u8_as_bool,
28 string::{cstr_as_str, str_to_cstr},
29 },
30};
31#[cfg(feature = "python")]
32use pyo3::{ffi, prelude::*};
33
34use super::timer::TimeEventHandler_API;
35#[cfg(feature = "python")]
36use crate::timer::TimeEventCallback;
37use crate::{
38 clock::{Clock, TestClock},
39 live::clock::LiveClock,
40 timer::TimeEvent,
41};
42
43#[repr(C)]
52#[derive(Debug)]
53#[allow(non_camel_case_types)]
54pub struct TestClock_API(Box<TestClock>);
55
56impl Deref for TestClock_API {
57 type Target = TestClock;
58
59 fn deref(&self) -> &Self::Target {
60 &self.0
61 }
62}
63
64impl DerefMut for TestClock_API {
65 fn deref_mut(&mut self) -> &mut Self::Target {
66 &mut self.0
67 }
68}
69
70#[unsafe(no_mangle)]
71pub extern "C" fn test_clock_new() -> TestClock_API {
72 TestClock_API(Box::default())
73}
74
75#[unsafe(no_mangle)]
76pub extern "C" fn test_clock_drop(clock: TestClock_API) {
77 drop(clock); }
79
80#[cfg(feature = "python")]
90#[unsafe(no_mangle)]
91pub unsafe extern "C" fn test_clock_register_default_handler(
92 clock: &mut TestClock_API,
93 callback_ptr: *mut ffi::PyObject,
94) {
95 assert!(!callback_ptr.is_null());
96 assert!(unsafe { ffi::Py_None() } != callback_ptr);
97
98 let callback = Python::attach(|py| unsafe {
99 Bound::<PyAny>::from_borrowed_ptr(py, callback_ptr).unbind()
100 });
101 let callback = TimeEventCallback::from(callback);
102
103 clock.register_default_handler(callback);
104}
105
106#[unsafe(no_mangle)]
107pub extern "C" fn test_clock_set_time(clock: &TestClock_API, to_time_ns: u64) {
108 clock.set_time(to_time_ns.into());
109}
110
111#[unsafe(no_mangle)]
112pub extern "C" fn test_clock_timestamp(clock: &TestClock_API) -> f64 {
113 clock.get_time()
114}
115
116#[unsafe(no_mangle)]
117pub extern "C" fn test_clock_timestamp_ms(clock: &TestClock_API) -> u64 {
118 clock.get_time_ms()
119}
120
121#[unsafe(no_mangle)]
122pub extern "C" fn test_clock_timestamp_us(clock: &TestClock_API) -> u64 {
123 clock.get_time_us()
124}
125
126#[unsafe(no_mangle)]
127pub extern "C" fn test_clock_timestamp_ns(clock: &TestClock_API) -> u64 {
128 clock.get_time_ns().as_u64()
129}
130
131#[unsafe(no_mangle)]
132pub extern "C" fn test_clock_timer_names(clock: &TestClock_API) -> *const c_char {
133 str_to_cstr(&clock.timer_names().join("<,>"))
136}
137
138#[unsafe(no_mangle)]
139pub extern "C" fn test_clock_timer_count(clock: &mut TestClock_API) -> usize {
140 clock.timer_count()
141}
142
143#[cfg(feature = "python")]
153#[unsafe(no_mangle)]
154pub unsafe extern "C" fn test_clock_set_time_alert(
155 clock: &mut TestClock_API,
156 name_ptr: *const c_char,
157 alert_time_ns: UnixNanos,
158 callback_ptr: *mut ffi::PyObject,
159 allow_past: u8,
160) {
161 assert!(!callback_ptr.is_null());
162
163 let name = unsafe { cstr_as_str(name_ptr) };
164 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
165 None
166 } else {
167 let callback = Python::attach(|py| unsafe {
168 Bound::<PyAny>::from_borrowed_ptr(py, callback_ptr).unbind()
169 });
170 Some(TimeEventCallback::from(callback))
171 };
172
173 clock
174 .set_time_alert_ns(name, alert_time_ns, callback, Some(allow_past != 0))
175 .expect(FAILED);
176}
177
178#[cfg(feature = "python")]
193#[unsafe(no_mangle)]
194pub unsafe extern "C" fn test_clock_set_timer(
195 clock: &mut TestClock_API,
196 name_ptr: *const c_char,
197 interval_ns: u64,
198 start_time_ns: UnixNanos,
199 stop_time_ns: UnixNanos,
200 callback_ptr: *mut ffi::PyObject,
201 allow_past: u8,
202 fire_immediately: u8,
203) {
204 assert!(!callback_ptr.is_null());
205
206 let name = unsafe { cstr_as_str(name_ptr) };
207 let start_time_ns = (start_time_ns != 0).then_some(start_time_ns);
209 let stop_time_ns = (stop_time_ns != 0).then_some(stop_time_ns);
210 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
211 None
212 } else {
213 let callback = Python::attach(|py| unsafe {
214 Bound::<PyAny>::from_borrowed_ptr(py, callback_ptr).unbind()
215 });
216 Some(TimeEventCallback::from(callback))
217 };
218
219 clock
220 .set_timer_ns(
221 name,
222 interval_ns,
223 start_time_ns,
224 stop_time_ns,
225 callback,
226 Some(allow_past != 0),
227 Some(fire_immediately != 0),
228 )
229 .expect(FAILED);
230}
231
232#[unsafe(no_mangle)]
236pub unsafe extern "C" fn test_clock_advance_time(
237 clock: &mut TestClock_API,
238 to_time_ns: u64,
239 set_time: u8,
240) -> CVec {
241 let events: Vec<TimeEvent> = clock.advance_time(to_time_ns.into(), u8_as_bool(set_time));
242 let t: Vec<TimeEventHandler_API> = clock
243 .match_handlers(events)
244 .into_iter()
245 .map(Into::into)
246 .collect();
247 t.into()
248}
249
250#[unsafe(no_mangle)]
258pub extern "C" fn vec_time_event_handlers_drop(v: CVec) {
259 let CVec { ptr, len, cap } = v;
260
261 assert!(
262 len <= cap,
263 "vec_time_event_handlers_drop: len ({len}) > cap ({cap}) - memory corruption or wrong drop helper"
264 );
265 assert!(
266 len == 0 || !ptr.is_null(),
267 "vec_time_event_handlers_drop: null ptr with non-zero len ({len}) - memory corruption or wrong drop helper"
268 );
269
270 let data: Vec<TimeEventHandler_API> =
271 unsafe { Vec::from_raw_parts(ptr.cast::<TimeEventHandler_API>(), len, cap) };
272 drop(data); }
274
275#[unsafe(no_mangle)]
279pub unsafe extern "C" fn test_clock_next_time(
280 clock: &mut TestClock_API,
281 name_ptr: *const c_char,
282) -> UnixNanos {
283 let name = unsafe { cstr_as_str(name_ptr) };
284 clock.next_time_ns(name).unwrap_or_default()
285}
286
287#[unsafe(no_mangle)]
291pub unsafe extern "C" fn test_clock_cancel_timer(
292 clock: &mut TestClock_API,
293 name_ptr: *const c_char,
294) {
295 let name = unsafe { cstr_as_str(name_ptr) };
296 clock.cancel_timer(name);
297}
298
299#[unsafe(no_mangle)]
300pub extern "C" fn test_clock_cancel_timers(clock: &mut TestClock_API) {
301 clock.cancel_timers();
302}
303
304#[repr(C)]
314#[derive(Debug)]
315#[allow(non_camel_case_types)]
316pub struct LiveClock_API(Box<LiveClock>);
317
318impl Deref for LiveClock_API {
319 type Target = LiveClock;
320
321 fn deref(&self) -> &Self::Target {
322 &self.0
323 }
324}
325
326impl DerefMut for LiveClock_API {
327 fn deref_mut(&mut self) -> &mut Self::Target {
328 &mut self.0
329 }
330}
331
332#[unsafe(no_mangle)]
333pub extern "C" fn live_clock_new() -> LiveClock_API {
334 LiveClock_API(Box::new(LiveClock::new(None)))
336}
337
338#[unsafe(no_mangle)]
339pub extern "C" fn live_clock_drop(clock: LiveClock_API) {
340 drop(clock); }
342
343#[cfg(feature = "python")]
351#[unsafe(no_mangle)]
352pub unsafe extern "C" fn live_clock_register_default_handler(
353 clock: &mut LiveClock_API,
354 callback_ptr: *mut ffi::PyObject,
355) {
356 assert!(!callback_ptr.is_null());
357 assert!(unsafe { ffi::Py_None() } != callback_ptr);
358
359 let callback = Python::attach(|py| unsafe {
360 Bound::<PyAny>::from_borrowed_ptr(py, callback_ptr).unbind()
361 });
362 let callback = TimeEventCallback::from(callback);
363
364 clock.register_default_handler(callback);
365}
366
367#[unsafe(no_mangle)]
368pub extern "C" fn live_clock_timestamp(clock: &mut LiveClock_API) -> f64 {
369 clock.get_time()
370}
371
372#[unsafe(no_mangle)]
373pub extern "C" fn live_clock_timestamp_ms(clock: &mut LiveClock_API) -> u64 {
374 clock.get_time_ms()
375}
376
377#[unsafe(no_mangle)]
378pub extern "C" fn live_clock_timestamp_us(clock: &mut LiveClock_API) -> u64 {
379 clock.get_time_us()
380}
381
382#[unsafe(no_mangle)]
383pub extern "C" fn live_clock_timestamp_ns(clock: &mut LiveClock_API) -> u64 {
384 clock.get_time_ns().as_u64()
385}
386
387#[unsafe(no_mangle)]
388pub extern "C" fn live_clock_timer_names(clock: &LiveClock_API) -> *const c_char {
389 str_to_cstr(&clock.timer_names().join("<,>"))
392}
393
394#[unsafe(no_mangle)]
395pub extern "C" fn live_clock_timer_count(clock: &mut LiveClock_API) -> usize {
396 clock.timer_count()
397}
398
399#[cfg(feature = "python")]
411#[unsafe(no_mangle)]
412pub unsafe extern "C" fn live_clock_set_time_alert(
413 clock: &mut LiveClock_API,
414 name_ptr: *const c_char,
415 alert_time_ns: UnixNanos,
416 callback_ptr: *mut ffi::PyObject,
417 allow_past: u8,
418) {
419 assert!(!callback_ptr.is_null());
420
421 let name = unsafe { cstr_as_str(name_ptr) };
422 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
423 None
424 } else {
425 let callback = Python::attach(|py| unsafe {
426 Bound::<PyAny>::from_borrowed_ptr(py, callback_ptr).unbind()
427 });
428 Some(TimeEventCallback::from(callback))
429 };
430
431 clock
432 .set_time_alert_ns(name, alert_time_ns, callback, Some(allow_past != 0))
433 .expect(FAILED);
434}
435
436#[cfg(feature = "python")]
453#[unsafe(no_mangle)]
454pub unsafe extern "C" fn live_clock_set_timer(
455 clock: &mut LiveClock_API,
456 name_ptr: *const c_char,
457 interval_ns: u64,
458 start_time_ns: UnixNanos,
459 stop_time_ns: UnixNanos,
460 callback_ptr: *mut ffi::PyObject,
461 allow_past: u8,
462 fire_immediately: u8,
463) {
464 assert!(!callback_ptr.is_null());
465
466 let name = unsafe { cstr_as_str(name_ptr) };
467 let start_time_ns = (start_time_ns != 0).then_some(start_time_ns);
469 let stop_time_ns = (stop_time_ns != 0).then_some(stop_time_ns);
470 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
471 None
472 } else {
473 let callback = Python::attach(|py| unsafe {
474 Bound::<PyAny>::from_borrowed_ptr(py, callback_ptr).unbind()
475 });
476 Some(TimeEventCallback::from(callback))
477 };
478
479 clock
480 .set_timer_ns(
481 name,
482 interval_ns,
483 start_time_ns,
484 stop_time_ns,
485 callback,
486 Some(allow_past != 0),
487 Some(fire_immediately != 0),
488 )
489 .expect(FAILED);
490}
491
492#[unsafe(no_mangle)]
496pub unsafe extern "C" fn live_clock_next_time(
497 clock: &mut LiveClock_API,
498 name_ptr: *const c_char,
499) -> UnixNanos {
500 let name = unsafe { cstr_as_str(name_ptr) };
501 clock.next_time_ns(name).unwrap_or_default()
502}
503
504#[unsafe(no_mangle)]
508pub unsafe extern "C" fn live_clock_cancel_timer(
509 clock: &mut LiveClock_API,
510 name_ptr: *const c_char,
511) {
512 let name = unsafe { cstr_as_str(name_ptr) };
513 clock.cancel_timer(name);
514}
515
516#[unsafe(no_mangle)]
517pub extern "C" fn live_clock_cancel_timers(clock: &mut LiveClock_API) {
518 clock.cancel_timers();
519}