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_API;
34use crate::{
35 clock::{Clock, TestClock},
36 live::clock::LiveClock,
37 timer::{TimeEvent, TimeEventCallback},
38};
39
40#[repr(C)]
49#[derive(Debug)]
50#[allow(non_camel_case_types)]
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 {
96 Bound::<PyAny>::from_borrowed_ptr(py, callback_ptr).unbind()
97 });
98 let callback = TimeEventCallback::from(callback);
99
100 clock.register_default_handler(callback);
101}
102
103#[unsafe(no_mangle)]
104pub extern "C" fn test_clock_set_time(clock: &TestClock_API, to_time_ns: u64) {
105 clock.set_time(to_time_ns.into());
106}
107
108#[unsafe(no_mangle)]
109pub extern "C" fn test_clock_timestamp(clock: &TestClock_API) -> f64 {
110 clock.get_time()
111}
112
113#[unsafe(no_mangle)]
114pub extern "C" fn test_clock_timestamp_ms(clock: &TestClock_API) -> u64 {
115 clock.get_time_ms()
116}
117
118#[unsafe(no_mangle)]
119pub extern "C" fn test_clock_timestamp_us(clock: &TestClock_API) -> u64 {
120 clock.get_time_us()
121}
122
123#[unsafe(no_mangle)]
124pub extern "C" fn test_clock_timestamp_ns(clock: &TestClock_API) -> u64 {
125 clock.get_time_ns().as_u64()
126}
127
128#[unsafe(no_mangle)]
129pub extern "C" fn test_clock_timer_names(clock: &TestClock_API) -> *const c_char {
130 str_to_cstr(&clock.timer_names().join("<,>"))
133}
134
135#[unsafe(no_mangle)]
136pub extern "C" fn test_clock_timer_count(clock: &mut TestClock_API) -> usize {
137 clock.timer_count()
138}
139
140#[cfg(feature = "python")]
150#[unsafe(no_mangle)]
151pub unsafe extern "C" fn test_clock_set_time_alert(
152 clock: &mut TestClock_API,
153 name_ptr: *const c_char,
154 alert_time_ns: UnixNanos,
155 callback_ptr: *mut ffi::PyObject,
156 allow_past: u8,
157) {
158 assert!(!callback_ptr.is_null());
159
160 let name = unsafe { cstr_as_str(name_ptr) };
161 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
162 None
163 } else {
164 let callback = Python::attach(|py| unsafe {
165 Bound::<PyAny>::from_borrowed_ptr(py, callback_ptr).unbind()
166 });
167 Some(TimeEventCallback::from(callback))
168 };
169
170 clock
171 .set_time_alert_ns(name, alert_time_ns, callback, Some(allow_past != 0))
172 .expect(FAILED);
173}
174
175#[cfg(feature = "python")]
190#[unsafe(no_mangle)]
191pub unsafe extern "C" fn test_clock_set_timer(
192 clock: &mut TestClock_API,
193 name_ptr: *const c_char,
194 interval_ns: u64,
195 start_time_ns: UnixNanos,
196 stop_time_ns: UnixNanos,
197 callback_ptr: *mut ffi::PyObject,
198 allow_past: u8,
199 fire_immediately: u8,
200) {
201 assert!(!callback_ptr.is_null());
202
203 let name = unsafe { cstr_as_str(name_ptr) };
204 let start_time_ns = (start_time_ns != 0).then_some(start_time_ns);
206 let stop_time_ns = (stop_time_ns != 0).then_some(stop_time_ns);
207 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
208 None
209 } else {
210 let callback = Python::attach(|py| unsafe {
211 Bound::<PyAny>::from_borrowed_ptr(py, callback_ptr).unbind()
212 });
213 Some(TimeEventCallback::from(callback))
214 };
215
216 clock
217 .set_timer_ns(
218 name,
219 interval_ns,
220 start_time_ns,
221 stop_time_ns,
222 callback,
223 Some(allow_past != 0),
224 Some(fire_immediately != 0),
225 )
226 .expect(FAILED);
227}
228
229#[unsafe(no_mangle)]
233pub unsafe extern "C" fn test_clock_advance_time(
234 clock: &mut TestClock_API,
235 to_time_ns: u64,
236 set_time: u8,
237) -> CVec {
238 let events: Vec<TimeEvent> = clock.advance_time(to_time_ns.into(), u8_as_bool(set_time));
239 let t: Vec<TimeEventHandler_API> = clock
240 .match_handlers(events)
241 .into_iter()
242 .map(Into::into)
243 .collect();
244 t.into()
245}
246
247#[allow(clippy::drop_non_drop)]
255#[unsafe(no_mangle)]
256pub extern "C" fn vec_time_event_handlers_drop(v: CVec) {
257 let CVec { ptr, len, cap } = v;
258
259 assert!(
260 len <= cap,
261 "vec_time_event_handlers_drop: len ({len}) > cap ({cap}) - memory corruption or wrong drop helper"
262 );
263 assert!(
264 len == 0 || !ptr.is_null(),
265 "vec_time_event_handlers_drop: null ptr with non-zero len ({len}) - memory corruption or wrong drop helper"
266 );
267
268 let data: Vec<TimeEventHandler_API> =
269 unsafe { Vec::from_raw_parts(ptr.cast::<TimeEventHandler_API>(), len, cap) };
270 drop(data); }
272
273#[unsafe(no_mangle)]
277pub unsafe extern "C" fn test_clock_next_time(
278 clock: &mut TestClock_API,
279 name_ptr: *const c_char,
280) -> UnixNanos {
281 let name = unsafe { cstr_as_str(name_ptr) };
282 clock.next_time_ns(name).unwrap_or_default()
283}
284
285#[unsafe(no_mangle)]
289pub unsafe extern "C" fn test_clock_cancel_timer(
290 clock: &mut TestClock_API,
291 name_ptr: *const c_char,
292) {
293 let name = unsafe { cstr_as_str(name_ptr) };
294 clock.cancel_timer(name);
295}
296
297#[unsafe(no_mangle)]
298pub extern "C" fn test_clock_cancel_timers(clock: &mut TestClock_API) {
299 clock.cancel_timers();
300}
301
302#[repr(C)]
312#[derive(Debug)]
313#[allow(non_camel_case_types)]
314pub struct LiveClock_API(Box<LiveClock>);
315
316impl Deref for LiveClock_API {
317 type Target = LiveClock;
318
319 fn deref(&self) -> &Self::Target {
320 &self.0
321 }
322}
323
324impl DerefMut for LiveClock_API {
325 fn deref_mut(&mut self) -> &mut Self::Target {
326 &mut self.0
327 }
328}
329
330#[unsafe(no_mangle)]
331pub extern "C" fn live_clock_new() -> LiveClock_API {
332 LiveClock_API(Box::new(LiveClock::new(None)))
334}
335
336#[unsafe(no_mangle)]
337pub extern "C" fn live_clock_drop(clock: LiveClock_API) {
338 drop(clock); }
340
341#[cfg(feature = "python")]
349#[unsafe(no_mangle)]
350pub unsafe extern "C" fn live_clock_register_default_handler(
351 clock: &mut LiveClock_API,
352 callback_ptr: *mut ffi::PyObject,
353) {
354 assert!(!callback_ptr.is_null());
355 assert!(unsafe { ffi::Py_None() } != callback_ptr);
356
357 let callback = Python::attach(|py| unsafe {
358 Bound::<PyAny>::from_borrowed_ptr(py, callback_ptr).unbind()
359 });
360 let callback = TimeEventCallback::from(callback);
361
362 clock.register_default_handler(callback);
363}
364
365#[unsafe(no_mangle)]
366pub extern "C" fn live_clock_timestamp(clock: &mut LiveClock_API) -> f64 {
367 clock.get_time()
368}
369
370#[unsafe(no_mangle)]
371pub extern "C" fn live_clock_timestamp_ms(clock: &mut LiveClock_API) -> u64 {
372 clock.get_time_ms()
373}
374
375#[unsafe(no_mangle)]
376pub extern "C" fn live_clock_timestamp_us(clock: &mut LiveClock_API) -> u64 {
377 clock.get_time_us()
378}
379
380#[unsafe(no_mangle)]
381pub extern "C" fn live_clock_timestamp_ns(clock: &mut LiveClock_API) -> u64 {
382 clock.get_time_ns().as_u64()
383}
384
385#[unsafe(no_mangle)]
386pub extern "C" fn live_clock_timer_names(clock: &LiveClock_API) -> *const c_char {
387 str_to_cstr(&clock.timer_names().join("<,>"))
390}
391
392#[unsafe(no_mangle)]
393pub extern "C" fn live_clock_timer_count(clock: &mut LiveClock_API) -> usize {
394 clock.timer_count()
395}
396
397#[cfg(feature = "python")]
409#[unsafe(no_mangle)]
410pub unsafe extern "C" fn live_clock_set_time_alert(
411 clock: &mut LiveClock_API,
412 name_ptr: *const c_char,
413 alert_time_ns: UnixNanos,
414 callback_ptr: *mut ffi::PyObject,
415 allow_past: u8,
416) {
417 assert!(!callback_ptr.is_null());
418
419 let name = unsafe { cstr_as_str(name_ptr) };
420 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
421 None
422 } else {
423 let callback = Python::attach(|py| unsafe {
424 Bound::<PyAny>::from_borrowed_ptr(py, callback_ptr).unbind()
425 });
426 Some(TimeEventCallback::from(callback))
427 };
428
429 clock
430 .set_time_alert_ns(name, alert_time_ns, callback, Some(allow_past != 0))
431 .expect(FAILED);
432}
433
434#[cfg(feature = "python")]
451#[unsafe(no_mangle)]
452pub unsafe extern "C" fn live_clock_set_timer(
453 clock: &mut LiveClock_API,
454 name_ptr: *const c_char,
455 interval_ns: u64,
456 start_time_ns: UnixNanos,
457 stop_time_ns: UnixNanos,
458 callback_ptr: *mut ffi::PyObject,
459 allow_past: u8,
460 fire_immediately: u8,
461) {
462 assert!(!callback_ptr.is_null());
463
464 let name = unsafe { cstr_as_str(name_ptr) };
465 let start_time_ns = (start_time_ns != 0).then_some(start_time_ns);
467 let stop_time_ns = (stop_time_ns != 0).then_some(stop_time_ns);
468 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
469 None
470 } else {
471 let callback = Python::attach(|py| unsafe {
472 Bound::<PyAny>::from_borrowed_ptr(py, callback_ptr).unbind()
473 });
474 Some(TimeEventCallback::from(callback))
475 };
476
477 clock
478 .set_timer_ns(
479 name,
480 interval_ns,
481 start_time_ns,
482 stop_time_ns,
483 callback,
484 Some(allow_past != 0),
485 Some(fire_immediately != 0),
486 )
487 .expect(FAILED);
488}
489
490#[unsafe(no_mangle)]
494pub unsafe extern "C" fn live_clock_next_time(
495 clock: &mut LiveClock_API,
496 name_ptr: *const c_char,
497) -> UnixNanos {
498 let name = unsafe { cstr_as_str(name_ptr) };
499 clock.next_time_ns(name).unwrap_or_default()
500}
501
502#[unsafe(no_mangle)]
506pub unsafe extern "C" fn live_clock_cancel_timer(
507 clock: &mut LiveClock_API,
508 name_ptr: *const c_char,
509) {
510 let name = unsafe { cstr_as_str(name_ptr) };
511 clock.cancel_timer(name);
512}
513
514#[unsafe(no_mangle)]
515pub extern "C" fn live_clock_cancel_timers(clock: &mut LiveClock_API) {
516 clock.cancel_timers();
517}