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, LiveClock, TestClock},
36 timer::{TimeEvent, TimeEventCallback},
37};
38
39#[repr(C)]
48#[allow(non_camel_case_types)]
49#[derive(Debug)]
50pub struct TestClock_API(Box<TestClock>);
51
52impl Deref for TestClock_API {
53 type Target = TestClock;
54
55 fn deref(&self) -> &Self::Target {
56 &self.0
57 }
58}
59
60impl DerefMut for TestClock_API {
61 fn deref_mut(&mut self) -> &mut Self::Target {
62 &mut self.0
63 }
64}
65
66#[unsafe(no_mangle)]
67pub extern "C" fn test_clock_new() -> TestClock_API {
68 TestClock_API(Box::default())
69}
70
71#[unsafe(no_mangle)]
72pub extern "C" fn test_clock_drop(clock: TestClock_API) {
73 drop(clock); }
75
76#[cfg(feature = "python")]
86#[unsafe(no_mangle)]
87pub unsafe extern "C" fn test_clock_register_default_handler(
88 clock: &mut TestClock_API,
89 callback_ptr: *mut ffi::PyObject,
90) {
91 assert!(!callback_ptr.is_null());
92 assert!(unsafe { ffi::Py_None() } != callback_ptr);
93
94 let callback = Python::attach(|py| unsafe { Py::<PyAny>::from_borrowed_ptr(py, callback_ptr) });
95 let callback = TimeEventCallback::from(callback);
96
97 clock.register_default_handler(callback);
98}
99
100#[unsafe(no_mangle)]
101pub extern "C" fn test_clock_set_time(clock: &TestClock_API, to_time_ns: u64) {
102 clock.set_time(to_time_ns.into());
103}
104
105#[unsafe(no_mangle)]
106pub extern "C" fn test_clock_timestamp(clock: &TestClock_API) -> f64 {
107 clock.get_time()
108}
109
110#[unsafe(no_mangle)]
111pub extern "C" fn test_clock_timestamp_ms(clock: &TestClock_API) -> u64 {
112 clock.get_time_ms()
113}
114
115#[unsafe(no_mangle)]
116pub extern "C" fn test_clock_timestamp_us(clock: &TestClock_API) -> u64 {
117 clock.get_time_us()
118}
119
120#[unsafe(no_mangle)]
121pub extern "C" fn test_clock_timestamp_ns(clock: &TestClock_API) -> u64 {
122 clock.get_time_ns().as_u64()
123}
124
125#[unsafe(no_mangle)]
126pub extern "C" fn test_clock_timer_names(clock: &TestClock_API) -> *const c_char {
127 str_to_cstr(&clock.timer_names().join("<,>"))
130}
131
132#[unsafe(no_mangle)]
133pub extern "C" fn test_clock_timer_count(clock: &mut TestClock_API) -> usize {
134 clock.timer_count()
135}
136
137#[cfg(feature = "python")]
147#[unsafe(no_mangle)]
148pub unsafe extern "C" fn test_clock_set_time_alert(
149 clock: &mut TestClock_API,
150 name_ptr: *const c_char,
151 alert_time_ns: UnixNanos,
152 callback_ptr: *mut ffi::PyObject,
153 allow_past: u8,
154) {
155 assert!(!callback_ptr.is_null());
156
157 let name = unsafe { cstr_as_str(name_ptr) };
158 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
159 None
160 } else {
161 let callback =
162 Python::attach(|py| unsafe { Py::<PyAny>::from_borrowed_ptr(py, callback_ptr) });
163 Some(TimeEventCallback::from(callback))
164 };
165
166 clock
167 .set_time_alert_ns(name, alert_time_ns, callback, Some(allow_past != 0))
168 .expect(FAILED);
169}
170
171#[cfg(feature = "python")]
186#[unsafe(no_mangle)]
187pub unsafe extern "C" fn test_clock_set_timer(
188 clock: &mut TestClock_API,
189 name_ptr: *const c_char,
190 interval_ns: u64,
191 start_time_ns: UnixNanos,
192 stop_time_ns: UnixNanos,
193 callback_ptr: *mut ffi::PyObject,
194 allow_past: u8,
195 fire_immediately: u8,
196) {
197 assert!(!callback_ptr.is_null());
198
199 let name = unsafe { cstr_as_str(name_ptr) };
200 let start_time_ns = (start_time_ns != 0).then_some(start_time_ns);
202 let stop_time_ns = (stop_time_ns != 0).then_some(stop_time_ns);
203 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
204 None
205 } else {
206 let callback =
207 Python::attach(|py| unsafe { Py::<PyAny>::from_borrowed_ptr(py, callback_ptr) });
208 Some(TimeEventCallback::from(callback))
209 };
210
211 clock
212 .set_timer_ns(
213 name,
214 interval_ns,
215 start_time_ns,
216 stop_time_ns,
217 callback,
218 Some(allow_past != 0),
219 Some(fire_immediately != 0),
220 )
221 .expect(FAILED);
222}
223
224#[unsafe(no_mangle)]
228pub unsafe extern "C" fn test_clock_advance_time(
229 clock: &mut TestClock_API,
230 to_time_ns: u64,
231 set_time: u8,
232) -> CVec {
233 let events: Vec<TimeEvent> = clock.advance_time(to_time_ns.into(), u8_as_bool(set_time));
234 let t: Vec<TimeEventHandler> = clock
235 .match_handlers(events)
236 .into_iter()
237 .map(Into::into)
238 .collect();
239 t.into()
240}
241
242#[allow(clippy::drop_non_drop)]
245#[unsafe(no_mangle)]
246pub extern "C" fn vec_time_event_handlers_drop(v: CVec) {
247 let CVec { ptr, len, cap } = v;
248 let data: Vec<TimeEventHandler> =
249 unsafe { Vec::from_raw_parts(ptr.cast::<TimeEventHandler>(), len, cap) };
250 drop(data); }
252
253#[unsafe(no_mangle)]
257pub unsafe extern "C" fn test_clock_next_time(
258 clock: &mut TestClock_API,
259 name_ptr: *const c_char,
260) -> UnixNanos {
261 let name = unsafe { cstr_as_str(name_ptr) };
262 clock.next_time_ns(name).unwrap_or_default()
263}
264
265#[unsafe(no_mangle)]
269pub unsafe extern "C" fn test_clock_cancel_timer(
270 clock: &mut TestClock_API,
271 name_ptr: *const c_char,
272) {
273 let name = unsafe { cstr_as_str(name_ptr) };
274 clock.cancel_timer(name);
275}
276
277#[unsafe(no_mangle)]
278pub extern "C" fn test_clock_cancel_timers(clock: &mut TestClock_API) {
279 clock.cancel_timers();
280}
281
282#[repr(C)]
292#[allow(non_camel_case_types)]
293#[derive(Debug)]
294pub struct LiveClock_API(Box<LiveClock>);
295
296impl Deref for LiveClock_API {
297 type Target = LiveClock;
298
299 fn deref(&self) -> &Self::Target {
300 &self.0
301 }
302}
303
304impl DerefMut for LiveClock_API {
305 fn deref_mut(&mut self) -> &mut Self::Target {
306 &mut self.0
307 }
308}
309
310#[unsafe(no_mangle)]
311pub extern "C" fn live_clock_new() -> LiveClock_API {
312 LiveClock_API(Box::new(LiveClock::new(None)))
314}
315
316#[unsafe(no_mangle)]
317pub extern "C" fn live_clock_drop(clock: LiveClock_API) {
318 drop(clock); }
320
321#[cfg(feature = "python")]
329#[unsafe(no_mangle)]
330pub unsafe extern "C" fn live_clock_register_default_handler(
331 clock: &mut LiveClock_API,
332 callback_ptr: *mut ffi::PyObject,
333) {
334 assert!(!callback_ptr.is_null());
335 assert!(unsafe { ffi::Py_None() } != callback_ptr);
336
337 let callback = Python::attach(|py| unsafe { Py::<PyAny>::from_borrowed_ptr(py, callback_ptr) });
338 let callback = TimeEventCallback::from(callback);
339
340 clock.register_default_handler(callback);
341}
342
343#[unsafe(no_mangle)]
344pub extern "C" fn live_clock_timestamp(clock: &mut LiveClock_API) -> f64 {
345 clock.get_time()
346}
347
348#[unsafe(no_mangle)]
349pub extern "C" fn live_clock_timestamp_ms(clock: &mut LiveClock_API) -> u64 {
350 clock.get_time_ms()
351}
352
353#[unsafe(no_mangle)]
354pub extern "C" fn live_clock_timestamp_us(clock: &mut LiveClock_API) -> u64 {
355 clock.get_time_us()
356}
357
358#[unsafe(no_mangle)]
359pub extern "C" fn live_clock_timestamp_ns(clock: &mut LiveClock_API) -> u64 {
360 clock.get_time_ns().as_u64()
361}
362
363#[unsafe(no_mangle)]
364pub extern "C" fn live_clock_timer_names(clock: &LiveClock_API) -> *const c_char {
365 str_to_cstr(&clock.timer_names().join("<,>"))
368}
369
370#[unsafe(no_mangle)]
371pub extern "C" fn live_clock_timer_count(clock: &mut LiveClock_API) -> usize {
372 clock.timer_count()
373}
374
375#[cfg(feature = "python")]
387#[unsafe(no_mangle)]
388pub unsafe extern "C" fn live_clock_set_time_alert(
389 clock: &mut LiveClock_API,
390 name_ptr: *const c_char,
391 alert_time_ns: UnixNanos,
392 callback_ptr: *mut ffi::PyObject,
393 allow_past: u8,
394) {
395 assert!(!callback_ptr.is_null());
396
397 let name = unsafe { cstr_as_str(name_ptr) };
398 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
399 None
400 } else {
401 let callback =
402 Python::attach(|py| unsafe { Py::<PyAny>::from_borrowed_ptr(py, callback_ptr) });
403 Some(TimeEventCallback::from(callback))
404 };
405
406 clock
407 .set_time_alert_ns(name, alert_time_ns, callback, Some(allow_past != 0))
408 .expect(FAILED);
409}
410
411#[cfg(feature = "python")]
428#[unsafe(no_mangle)]
429pub unsafe extern "C" fn live_clock_set_timer(
430 clock: &mut LiveClock_API,
431 name_ptr: *const c_char,
432 interval_ns: u64,
433 start_time_ns: UnixNanos,
434 stop_time_ns: UnixNanos,
435 callback_ptr: *mut ffi::PyObject,
436 allow_past: u8,
437 fire_immediately: u8,
438) {
439 assert!(!callback_ptr.is_null());
440
441 let name = unsafe { cstr_as_str(name_ptr) };
442 let start_time_ns = (start_time_ns != 0).then_some(start_time_ns);
444 let stop_time_ns = (stop_time_ns != 0).then_some(stop_time_ns);
445 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
446 None
447 } else {
448 let callback =
449 Python::attach(|py| unsafe { Py::<PyAny>::from_borrowed_ptr(py, callback_ptr) });
450 Some(TimeEventCallback::from(callback))
451 };
452
453 clock
454 .set_timer_ns(
455 name,
456 interval_ns,
457 start_time_ns,
458 stop_time_ns,
459 callback,
460 Some(allow_past != 0),
461 Some(fire_immediately != 0),
462 )
463 .expect(FAILED);
464}
465
466#[unsafe(no_mangle)]
470pub unsafe extern "C" fn live_clock_next_time(
471 clock: &mut LiveClock_API,
472 name_ptr: *const c_char,
473) -> UnixNanos {
474 let name = unsafe { cstr_as_str(name_ptr) };
475 clock.next_time_ns(name).unwrap_or_default()
476}
477
478#[unsafe(no_mangle)]
482pub unsafe extern "C" fn live_clock_cancel_timer(
483 clock: &mut LiveClock_API,
484 name_ptr: *const c_char,
485) {
486 let name = unsafe { cstr_as_str(name_ptr) };
487 clock.cancel_timer(name);
488}
489
490#[unsafe(no_mangle)]
491pub extern "C" fn live_clock_cancel_timers(clock: &mut LiveClock_API) {
492 clock.cancel_timers();
493}