nautilus_common/ffi/
clock.rs1use std::{
17 ffi::c_char,
18 ops::{Deref, DerefMut},
19};
20
21use nautilus_core::{
22 correctness::FAILED,
23 ffi::{cvec::CVec, parsing::u8_as_bool, string::cstr_as_str},
24 UnixNanos,
25};
26use pyo3::{
27 ffi,
28 prelude::*,
29 types::{PyList, PyString},
30};
31
32use super::timer::TimeEventHandler;
33use crate::{
34 clock::{Clock, LiveClock, TestClock},
35 timer::{TimeEvent, TimeEventCallback},
36};
37
38#[repr(C)]
47#[allow(non_camel_case_types)]
48pub struct TestClock_API(Box<TestClock>);
49
50impl Deref for TestClock_API {
51 type Target = TestClock;
52
53 fn deref(&self) -> &Self::Target {
54 &self.0
55 }
56}
57
58impl DerefMut for TestClock_API {
59 fn deref_mut(&mut self) -> &mut Self::Target {
60 &mut self.0
61 }
62}
63
64#[no_mangle]
65pub extern "C" fn test_clock_new() -> TestClock_API {
66 TestClock_API(Box::new(TestClock::new()))
67}
68
69#[no_mangle]
70pub extern "C" fn test_clock_drop(clock: TestClock_API) {
71 drop(clock); }
73
74#[no_mangle]
78pub unsafe extern "C" fn test_clock_register_default_handler(
79 clock: &mut TestClock_API,
80 callback_ptr: *mut ffi::PyObject,
81) {
82 assert!(!callback_ptr.is_null());
83 assert!(ffi::Py_None() != callback_ptr);
84
85 let callback = Python::with_gil(|py| PyObject::from_borrowed_ptr(py, callback_ptr));
86 let callback = TimeEventCallback::from(callback);
87
88 clock.register_default_handler(callback);
89}
90
91#[no_mangle]
92pub extern "C" fn test_clock_set_time(clock: &TestClock_API, to_time_ns: u64) {
93 clock.set_time(to_time_ns.into());
94}
95
96#[no_mangle]
97pub extern "C" fn test_clock_timestamp(clock: &TestClock_API) -> f64 {
98 clock.get_time()
99}
100
101#[no_mangle]
102pub extern "C" fn test_clock_timestamp_ms(clock: &TestClock_API) -> u64 {
103 clock.get_time_ms()
104}
105
106#[no_mangle]
107pub extern "C" fn test_clock_timestamp_us(clock: &TestClock_API) -> u64 {
108 clock.get_time_us()
109}
110
111#[no_mangle]
112pub extern "C" fn test_clock_timestamp_ns(clock: &TestClock_API) -> u64 {
113 clock.get_time_ns().as_u64()
114}
115
116#[no_mangle]
117pub extern "C" fn test_clock_timer_names(clock: &TestClock_API) -> *mut ffi::PyObject {
118 Python::with_gil(|py| -> Py<PyList> {
119 let names: Vec<Py<PyString>> = clock
120 .get_timers()
121 .keys()
122 .map(|k| PyString::new(py, k).into())
123 .collect();
124 PyList::new(py, names)
125 .expect("Invalid `ExactSizeIterator`")
126 .into()
127 })
128 .as_ptr()
129}
130
131#[no_mangle]
132pub extern "C" fn test_clock_timer_count(clock: &mut TestClock_API) -> usize {
133 clock.timer_count()
134}
135
136#[no_mangle]
141pub unsafe extern "C" fn test_clock_set_time_alert(
142 clock: &mut TestClock_API,
143 name_ptr: *const c_char,
144 alert_time_ns: UnixNanos,
145 callback_ptr: *mut ffi::PyObject,
146) {
147 assert!(!callback_ptr.is_null());
148
149 let name = cstr_as_str(name_ptr);
150 let callback = if callback_ptr == ffi::Py_None() {
151 None
152 } else {
153 let callback = Python::with_gil(|py| PyObject::from_borrowed_ptr(py, callback_ptr));
154 Some(TimeEventCallback::from(callback))
155 };
156
157 clock
158 .set_time_alert_ns(name, alert_time_ns, callback)
159 .expect(FAILED);
160}
161
162#[no_mangle]
167pub unsafe extern "C" fn test_clock_set_timer(
168 clock: &mut TestClock_API,
169 name_ptr: *const c_char,
170 interval_ns: u64,
171 start_time_ns: UnixNanos,
172 stop_time_ns: UnixNanos,
173 callback_ptr: *mut ffi::PyObject,
174) {
175 assert!(!callback_ptr.is_null());
176
177 let name = cstr_as_str(name_ptr);
178 let stop_time_ns = match stop_time_ns.into() {
179 0 => None,
180 _ => Some(stop_time_ns),
181 };
182 let callback = if callback_ptr == ffi::Py_None() {
183 None
184 } else {
185 let callback = Python::with_gil(|py| PyObject::from_borrowed_ptr(py, callback_ptr));
186 Some(TimeEventCallback::from(callback))
187 };
188
189 clock
190 .set_timer_ns(name, interval_ns, start_time_ns, stop_time_ns, callback)
191 .expect(FAILED);
192}
193
194#[no_mangle]
198pub unsafe extern "C" fn test_clock_advance_time(
199 clock: &mut TestClock_API,
200 to_time_ns: u64,
201 set_time: u8,
202) -> CVec {
203 let events: Vec<TimeEvent> = clock.advance_time(to_time_ns.into(), u8_as_bool(set_time));
204 let t: Vec<TimeEventHandler> = clock
205 .match_handlers(events)
206 .into_iter()
207 .map(Into::into)
208 .collect();
209 t.into()
210}
211
212#[allow(clippy::drop_non_drop)]
215#[no_mangle]
216pub extern "C" fn vec_time_event_handlers_drop(v: CVec) {
217 let CVec { ptr, len, cap } = v;
218 let data: Vec<TimeEventHandler> =
219 unsafe { Vec::from_raw_parts(ptr.cast::<TimeEventHandler>(), len, cap) };
220 drop(data); }
222
223#[no_mangle]
227pub unsafe extern "C" fn test_clock_next_time(
228 clock: &mut TestClock_API,
229 name_ptr: *const c_char,
230) -> UnixNanos {
231 let name = cstr_as_str(name_ptr);
232 clock.next_time_ns(name)
233}
234
235#[no_mangle]
239pub unsafe extern "C" fn test_clock_cancel_timer(
240 clock: &mut TestClock_API,
241 name_ptr: *const c_char,
242) {
243 let name = cstr_as_str(name_ptr);
244 clock.cancel_timer(name);
245}
246
247#[no_mangle]
248pub extern "C" fn test_clock_cancel_timers(clock: &mut TestClock_API) {
249 clock.cancel_timers();
250}
251
252#[repr(C)]
262#[allow(non_camel_case_types)]
263pub struct LiveClock_API(Box<LiveClock>);
264
265impl Deref for LiveClock_API {
266 type Target = LiveClock;
267
268 fn deref(&self) -> &Self::Target {
269 &self.0
270 }
271}
272
273impl DerefMut for LiveClock_API {
274 fn deref_mut(&mut self) -> &mut Self::Target {
275 &mut self.0
276 }
277}
278
279#[no_mangle]
280pub extern "C" fn live_clock_new() -> LiveClock_API {
281 LiveClock_API(Box::new(LiveClock::new()))
282}
283
284#[no_mangle]
285pub extern "C" fn live_clock_drop(clock: LiveClock_API) {
286 drop(clock); }
288
289#[no_mangle]
293pub unsafe extern "C" fn live_clock_register_default_handler(
294 clock: &mut LiveClock_API,
295 callback_ptr: *mut ffi::PyObject,
296) {
297 assert!(!callback_ptr.is_null());
298 assert!(ffi::Py_None() != callback_ptr);
299
300 let callback = Python::with_gil(|py| PyObject::from_borrowed_ptr(py, callback_ptr));
301 let callback = TimeEventCallback::from(callback);
302
303 clock.register_default_handler(callback);
304}
305
306#[no_mangle]
307pub extern "C" fn live_clock_timestamp(clock: &mut LiveClock_API) -> f64 {
308 clock.get_time()
309}
310
311#[no_mangle]
312pub extern "C" fn live_clock_timestamp_ms(clock: &mut LiveClock_API) -> u64 {
313 clock.get_time_ms()
314}
315
316#[no_mangle]
317pub extern "C" fn live_clock_timestamp_us(clock: &mut LiveClock_API) -> u64 {
318 clock.get_time_us()
319}
320
321#[no_mangle]
322pub extern "C" fn live_clock_timestamp_ns(clock: &mut LiveClock_API) -> u64 {
323 clock.get_time_ns().as_u64()
324}
325
326#[no_mangle]
327pub extern "C" fn live_clock_timer_names(clock: &LiveClock_API) -> *mut ffi::PyObject {
328 Python::with_gil(|py| -> Py<PyList> {
329 let names: Vec<Py<PyString>> = clock
330 .get_timers()
331 .keys()
332 .map(|k| PyString::new(py, k).into())
333 .collect();
334 PyList::new(py, names)
335 .expect("Invalid `ExactSizeIterator`")
336 .into()
337 })
338 .as_ptr()
339}
340
341#[no_mangle]
342pub extern "C" fn live_clock_timer_count(clock: &mut LiveClock_API) -> usize {
343 clock.timer_count()
344}
345
346#[no_mangle]
357pub unsafe extern "C" fn live_clock_set_time_alert(
358 clock: &mut LiveClock_API,
359 name_ptr: *const c_char,
360 alert_time_ns: UnixNanos,
361 callback_ptr: *mut ffi::PyObject,
362) {
363 assert!(!callback_ptr.is_null());
364
365 let name = cstr_as_str(name_ptr);
366 let callback = if callback_ptr == ffi::Py_None() {
367 None
368 } else {
369 let callback = Python::with_gil(|py| PyObject::from_borrowed_ptr(py, callback_ptr));
370 Some(TimeEventCallback::from(callback))
371 };
372
373 clock
374 .set_time_alert_ns(name, alert_time_ns, callback)
375 .expect(FAILED);
376}
377
378#[no_mangle]
389pub unsafe extern "C" fn live_clock_set_timer(
390 clock: &mut LiveClock_API,
391 name_ptr: *const c_char,
392 interval_ns: u64,
393 start_time_ns: UnixNanos,
394 stop_time_ns: UnixNanos,
395 callback_ptr: *mut ffi::PyObject,
396) {
397 assert!(!callback_ptr.is_null());
398
399 let name = cstr_as_str(name_ptr);
400 let stop_time_ns = match stop_time_ns.into() {
401 0 => None,
402 _ => Some(stop_time_ns),
403 };
404
405 let callback = if callback_ptr == ffi::Py_None() {
406 None
407 } else {
408 let callback = Python::with_gil(|py| PyObject::from_borrowed_ptr(py, callback_ptr));
409 Some(TimeEventCallback::from(callback))
410 };
411
412 clock
413 .set_timer_ns(name, interval_ns, start_time_ns, stop_time_ns, callback)
414 .expect(FAILED);
415}
416
417#[no_mangle]
421pub unsafe extern "C" fn live_clock_next_time(
422 clock: &mut LiveClock_API,
423 name_ptr: *const c_char,
424) -> UnixNanos {
425 let name = cstr_as_str(name_ptr);
426 clock.next_time_ns(name)
427}
428
429#[no_mangle]
433pub unsafe extern "C" fn live_clock_cancel_timer(
434 clock: &mut LiveClock_API,
435 name_ptr: *const c_char,
436) {
437 let name = cstr_as_str(name_ptr);
438 clock.cancel_timer(name);
439}
440
441#[no_mangle]
442pub extern "C" fn live_clock_cancel_timers(clock: &mut LiveClock_API) {
443 clock.cancel_timers();
444}