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::with_gil(|py| unsafe { PyObject::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::with_gil(|py| unsafe { PyObject::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")]
181#[unsafe(no_mangle)]
182pub unsafe extern "C" fn test_clock_set_timer(
183 clock: &mut TestClock_API,
184 name_ptr: *const c_char,
185 interval_ns: u64,
186 start_time_ns: UnixNanos,
187 stop_time_ns: UnixNanos,
188 callback_ptr: *mut ffi::PyObject,
189 allow_past: u8,
190 fire_immediately: u8,
191) {
192 assert!(!callback_ptr.is_null());
193
194 let name = unsafe { cstr_as_str(name_ptr) };
195 let start_time_ns = (start_time_ns != 0).then_some(start_time_ns);
196 let stop_time_ns = (stop_time_ns != 0).then_some(stop_time_ns);
197 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
198 None
199 } else {
200 let callback =
201 Python::with_gil(|py| unsafe { PyObject::from_borrowed_ptr(py, callback_ptr) });
202 Some(TimeEventCallback::from(callback))
203 };
204
205 clock
206 .set_timer_ns(
207 name,
208 interval_ns,
209 start_time_ns,
210 stop_time_ns,
211 callback,
212 Some(allow_past != 0),
213 Some(fire_immediately != 0),
214 )
215 .expect(FAILED);
216}
217
218#[unsafe(no_mangle)]
222pub unsafe extern "C" fn test_clock_advance_time(
223 clock: &mut TestClock_API,
224 to_time_ns: u64,
225 set_time: u8,
226) -> CVec {
227 let events: Vec<TimeEvent> = clock.advance_time(to_time_ns.into(), u8_as_bool(set_time));
228 let t: Vec<TimeEventHandler> = clock
229 .match_handlers(events)
230 .into_iter()
231 .map(Into::into)
232 .collect();
233 t.into()
234}
235
236#[allow(clippy::drop_non_drop)]
239#[unsafe(no_mangle)]
240pub extern "C" fn vec_time_event_handlers_drop(v: CVec) {
241 let CVec { ptr, len, cap } = v;
242 let data: Vec<TimeEventHandler> =
243 unsafe { Vec::from_raw_parts(ptr.cast::<TimeEventHandler>(), len, cap) };
244 drop(data); }
246
247#[unsafe(no_mangle)]
251pub unsafe extern "C" fn test_clock_next_time(
252 clock: &mut TestClock_API,
253 name_ptr: *const c_char,
254) -> UnixNanos {
255 let name = unsafe { cstr_as_str(name_ptr) };
256 clock.next_time_ns(name).unwrap_or_default()
257}
258
259#[unsafe(no_mangle)]
263pub unsafe extern "C" fn test_clock_cancel_timer(
264 clock: &mut TestClock_API,
265 name_ptr: *const c_char,
266) {
267 let name = unsafe { cstr_as_str(name_ptr) };
268 clock.cancel_timer(name);
269}
270
271#[unsafe(no_mangle)]
272pub extern "C" fn test_clock_cancel_timers(clock: &mut TestClock_API) {
273 clock.cancel_timers();
274}
275
276#[repr(C)]
286#[allow(non_camel_case_types)]
287#[derive(Debug)]
288pub struct LiveClock_API(Box<LiveClock>);
289
290impl Deref for LiveClock_API {
291 type Target = LiveClock;
292
293 fn deref(&self) -> &Self::Target {
294 &self.0
295 }
296}
297
298impl DerefMut for LiveClock_API {
299 fn deref_mut(&mut self) -> &mut Self::Target {
300 &mut self.0
301 }
302}
303
304#[unsafe(no_mangle)]
305pub extern "C" fn live_clock_new() -> LiveClock_API {
306 LiveClock_API(Box::new(LiveClock::new(None)))
308}
309
310#[unsafe(no_mangle)]
311pub extern "C" fn live_clock_drop(clock: LiveClock_API) {
312 drop(clock); }
314
315#[cfg(feature = "python")]
323#[unsafe(no_mangle)]
324pub unsafe extern "C" fn live_clock_register_default_handler(
325 clock: &mut LiveClock_API,
326 callback_ptr: *mut ffi::PyObject,
327) {
328 assert!(!callback_ptr.is_null());
329 assert!(unsafe { ffi::Py_None() } != callback_ptr);
330
331 let callback = Python::with_gil(|py| unsafe { PyObject::from_borrowed_ptr(py, callback_ptr) });
332 let callback = TimeEventCallback::from(callback);
333
334 clock.register_default_handler(callback);
335}
336
337#[unsafe(no_mangle)]
338pub extern "C" fn live_clock_timestamp(clock: &mut LiveClock_API) -> f64 {
339 clock.get_time()
340}
341
342#[unsafe(no_mangle)]
343pub extern "C" fn live_clock_timestamp_ms(clock: &mut LiveClock_API) -> u64 {
344 clock.get_time_ms()
345}
346
347#[unsafe(no_mangle)]
348pub extern "C" fn live_clock_timestamp_us(clock: &mut LiveClock_API) -> u64 {
349 clock.get_time_us()
350}
351
352#[unsafe(no_mangle)]
353pub extern "C" fn live_clock_timestamp_ns(clock: &mut LiveClock_API) -> u64 {
354 clock.get_time_ns().as_u64()
355}
356
357#[unsafe(no_mangle)]
358pub extern "C" fn live_clock_timer_names(clock: &LiveClock_API) -> *const c_char {
359 str_to_cstr(&clock.timer_names().join("<,>"))
362}
363
364#[unsafe(no_mangle)]
365pub extern "C" fn live_clock_timer_count(clock: &mut LiveClock_API) -> usize {
366 clock.timer_count()
367}
368
369#[cfg(feature = "python")]
381#[unsafe(no_mangle)]
382pub unsafe extern "C" fn live_clock_set_time_alert(
383 clock: &mut LiveClock_API,
384 name_ptr: *const c_char,
385 alert_time_ns: UnixNanos,
386 callback_ptr: *mut ffi::PyObject,
387 allow_past: u8,
388) {
389 assert!(!callback_ptr.is_null());
390
391 let name = unsafe { cstr_as_str(name_ptr) };
392 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
393 None
394 } else {
395 let callback =
396 Python::with_gil(|py| unsafe { PyObject::from_borrowed_ptr(py, callback_ptr) });
397 Some(TimeEventCallback::from(callback))
398 };
399
400 clock
401 .set_time_alert_ns(name, alert_time_ns, callback, Some(allow_past != 0))
402 .expect(FAILED);
403}
404
405#[cfg(feature = "python")]
417#[unsafe(no_mangle)]
418pub unsafe extern "C" fn live_clock_set_timer(
419 clock: &mut LiveClock_API,
420 name_ptr: *const c_char,
421 interval_ns: u64,
422 start_time_ns: UnixNanos,
423 stop_time_ns: UnixNanos,
424 callback_ptr: *mut ffi::PyObject,
425 allow_past: u8,
426 fire_immediately: u8,
427) {
428 assert!(!callback_ptr.is_null());
429
430 let name = unsafe { cstr_as_str(name_ptr) };
431 let start_time_ns = (start_time_ns != 0).then_some(start_time_ns);
432 let stop_time_ns = (stop_time_ns != 0).then_some(stop_time_ns);
433 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
434 None
435 } else {
436 let callback =
437 Python::with_gil(|py| unsafe { PyObject::from_borrowed_ptr(py, callback_ptr) });
438 Some(TimeEventCallback::from(callback))
439 };
440
441 clock
442 .set_timer_ns(
443 name,
444 interval_ns,
445 start_time_ns,
446 stop_time_ns,
447 callback,
448 Some(allow_past != 0),
449 Some(fire_immediately != 0),
450 )
451 .expect(FAILED);
452}
453
454#[unsafe(no_mangle)]
458pub unsafe extern "C" fn live_clock_next_time(
459 clock: &mut LiveClock_API,
460 name_ptr: *const c_char,
461) -> UnixNanos {
462 let name = unsafe { cstr_as_str(name_ptr) };
463 clock.next_time_ns(name).unwrap_or_default()
464}
465
466#[unsafe(no_mangle)]
470pub unsafe extern "C" fn live_clock_cancel_timer(
471 clock: &mut LiveClock_API,
472 name_ptr: *const c_char,
473) {
474 let name = unsafe { cstr_as_str(name_ptr) };
475 clock.cancel_timer(name);
476}
477
478#[unsafe(no_mangle)]
479pub extern "C" fn live_clock_cancel_timers(clock: &mut LiveClock_API) {
480 clock.cancel_timers();
481}