nautilus_common/ffi/
clock.rs
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};
30use pyo3::{ffi, prelude::*};
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#[unsafe(no_mangle)]
65pub extern "C" fn test_clock_new() -> TestClock_API {
66 TestClock_API(Box::default())
67}
68
69#[unsafe(no_mangle)]
70pub extern "C" fn test_clock_drop(clock: TestClock_API) {
71 drop(clock); }
73
74#[unsafe(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!(unsafe { ffi::Py_None() } != callback_ptr);
84
85 let callback = Python::with_gil(|py| unsafe { PyObject::from_borrowed_ptr(py, callback_ptr) });
86 let callback = TimeEventCallback::from(callback);
87
88 clock.register_default_handler(callback);
89}
90
91#[unsafe(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#[unsafe(no_mangle)]
97pub extern "C" fn test_clock_timestamp(clock: &TestClock_API) -> f64 {
98 clock.get_time()
99}
100
101#[unsafe(no_mangle)]
102pub extern "C" fn test_clock_timestamp_ms(clock: &TestClock_API) -> u64 {
103 clock.get_time_ms()
104}
105
106#[unsafe(no_mangle)]
107pub extern "C" fn test_clock_timestamp_us(clock: &TestClock_API) -> u64 {
108 clock.get_time_us()
109}
110
111#[unsafe(no_mangle)]
112pub extern "C" fn test_clock_timestamp_ns(clock: &TestClock_API) -> u64 {
113 clock.get_time_ns().as_u64()
114}
115
116#[unsafe(no_mangle)]
117pub extern "C" fn test_clock_timer_names(clock: &TestClock_API) -> *const c_char {
118 str_to_cstr(&clock.timer_names().join("<,>"))
121}
122
123#[unsafe(no_mangle)]
124pub extern "C" fn test_clock_timer_count(clock: &mut TestClock_API) -> usize {
125 clock.timer_count()
126}
127
128#[unsafe(no_mangle)]
133pub unsafe extern "C" fn test_clock_set_time_alert(
134 clock: &mut TestClock_API,
135 name_ptr: *const c_char,
136 alert_time_ns: UnixNanos,
137 callback_ptr: *mut ffi::PyObject,
138) {
139 assert!(!callback_ptr.is_null());
140
141 let name = unsafe { cstr_as_str(name_ptr) };
142 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
143 None
144 } else {
145 let callback =
146 Python::with_gil(|py| unsafe { PyObject::from_borrowed_ptr(py, callback_ptr) });
147 Some(TimeEventCallback::from(callback))
148 };
149
150 clock
151 .set_time_alert_ns(name, alert_time_ns, callback)
152 .expect(FAILED);
153}
154
155#[unsafe(no_mangle)]
160pub unsafe extern "C" fn test_clock_set_timer(
161 clock: &mut TestClock_API,
162 name_ptr: *const c_char,
163 interval_ns: u64,
164 start_time_ns: UnixNanos,
165 stop_time_ns: UnixNanos,
166 callback_ptr: *mut ffi::PyObject,
167) {
168 assert!(!callback_ptr.is_null());
169
170 let name = unsafe { cstr_as_str(name_ptr) };
171 let stop_time_ns = match stop_time_ns.into() {
172 0 => None,
173 _ => Some(stop_time_ns),
174 };
175 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
176 None
177 } else {
178 let callback =
179 Python::with_gil(|py| unsafe { PyObject::from_borrowed_ptr(py, callback_ptr) });
180 Some(TimeEventCallback::from(callback))
181 };
182
183 clock
184 .set_timer_ns(name, interval_ns, start_time_ns, stop_time_ns, callback)
185 .expect(FAILED);
186}
187
188#[unsafe(no_mangle)]
192pub unsafe extern "C" fn test_clock_advance_time(
193 clock: &mut TestClock_API,
194 to_time_ns: u64,
195 set_time: u8,
196) -> CVec {
197 let events: Vec<TimeEvent> = clock.advance_time(to_time_ns.into(), u8_as_bool(set_time));
198 let t: Vec<TimeEventHandler> = clock
199 .match_handlers(events)
200 .into_iter()
201 .map(Into::into)
202 .collect();
203 t.into()
204}
205
206#[allow(clippy::drop_non_drop)]
209#[unsafe(no_mangle)]
210pub extern "C" fn vec_time_event_handlers_drop(v: CVec) {
211 let CVec { ptr, len, cap } = v;
212 let data: Vec<TimeEventHandler> =
213 unsafe { Vec::from_raw_parts(ptr.cast::<TimeEventHandler>(), len, cap) };
214 drop(data); }
216
217#[unsafe(no_mangle)]
221pub unsafe extern "C" fn test_clock_next_time(
222 clock: &mut TestClock_API,
223 name_ptr: *const c_char,
224) -> UnixNanos {
225 let name = unsafe { cstr_as_str(name_ptr) };
226 clock.next_time_ns(name)
227}
228
229#[unsafe(no_mangle)]
233pub unsafe extern "C" fn test_clock_cancel_timer(
234 clock: &mut TestClock_API,
235 name_ptr: *const c_char,
236) {
237 let name = unsafe { cstr_as_str(name_ptr) };
238 clock.cancel_timer(name);
239}
240
241#[unsafe(no_mangle)]
242pub extern "C" fn test_clock_cancel_timers(clock: &mut TestClock_API) {
243 clock.cancel_timers();
244}
245
246#[repr(C)]
256#[allow(non_camel_case_types)]
257pub struct LiveClock_API(Box<LiveClock>);
258
259impl Deref for LiveClock_API {
260 type Target = LiveClock;
261
262 fn deref(&self) -> &Self::Target {
263 &self.0
264 }
265}
266
267impl DerefMut for LiveClock_API {
268 fn deref_mut(&mut self) -> &mut Self::Target {
269 &mut self.0
270 }
271}
272
273#[unsafe(no_mangle)]
274pub extern "C" fn live_clock_new() -> LiveClock_API {
275 LiveClock_API(Box::default())
276}
277
278#[unsafe(no_mangle)]
279pub extern "C" fn live_clock_drop(clock: LiveClock_API) {
280 drop(clock); }
282
283#[unsafe(no_mangle)]
287pub unsafe extern "C" fn live_clock_register_default_handler(
288 clock: &mut LiveClock_API,
289 callback_ptr: *mut ffi::PyObject,
290) {
291 assert!(!callback_ptr.is_null());
292 assert!(unsafe { ffi::Py_None() } != callback_ptr);
293
294 let callback = Python::with_gil(|py| unsafe { PyObject::from_borrowed_ptr(py, callback_ptr) });
295 let callback = TimeEventCallback::from(callback);
296
297 clock.register_default_handler(callback);
298}
299
300#[unsafe(no_mangle)]
301pub extern "C" fn live_clock_timestamp(clock: &mut LiveClock_API) -> f64 {
302 clock.get_time()
303}
304
305#[unsafe(no_mangle)]
306pub extern "C" fn live_clock_timestamp_ms(clock: &mut LiveClock_API) -> u64 {
307 clock.get_time_ms()
308}
309
310#[unsafe(no_mangle)]
311pub extern "C" fn live_clock_timestamp_us(clock: &mut LiveClock_API) -> u64 {
312 clock.get_time_us()
313}
314
315#[unsafe(no_mangle)]
316pub extern "C" fn live_clock_timestamp_ns(clock: &mut LiveClock_API) -> u64 {
317 clock.get_time_ns().as_u64()
318}
319
320#[unsafe(no_mangle)]
321pub extern "C" fn live_clock_timer_names(clock: &LiveClock_API) -> *const c_char {
322 str_to_cstr(&clock.timer_names().join("<,>"))
325}
326
327#[unsafe(no_mangle)]
328pub extern "C" fn live_clock_timer_count(clock: &mut LiveClock_API) -> usize {
329 clock.timer_count()
330}
331
332#[unsafe(no_mangle)]
343pub unsafe extern "C" fn live_clock_set_time_alert(
344 clock: &mut LiveClock_API,
345 name_ptr: *const c_char,
346 alert_time_ns: UnixNanos,
347 callback_ptr: *mut ffi::PyObject,
348) {
349 assert!(!callback_ptr.is_null());
350
351 let name = unsafe { cstr_as_str(name_ptr) };
352 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
353 None
354 } else {
355 let callback =
356 Python::with_gil(|py| unsafe { PyObject::from_borrowed_ptr(py, callback_ptr) });
357 Some(TimeEventCallback::from(callback))
358 };
359
360 clock
361 .set_time_alert_ns(name, alert_time_ns, callback)
362 .expect(FAILED);
363}
364
365#[unsafe(no_mangle)]
376pub unsafe extern "C" fn live_clock_set_timer(
377 clock: &mut LiveClock_API,
378 name_ptr: *const c_char,
379 interval_ns: u64,
380 start_time_ns: UnixNanos,
381 stop_time_ns: UnixNanos,
382 callback_ptr: *mut ffi::PyObject,
383) {
384 assert!(!callback_ptr.is_null());
385
386 let name = unsafe { cstr_as_str(name_ptr) };
387 let stop_time_ns = match stop_time_ns.into() {
388 0 => None,
389 _ => Some(stop_time_ns),
390 };
391
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_timer_ns(name, interval_ns, start_time_ns, stop_time_ns, callback)
402 .expect(FAILED);
403}
404
405#[unsafe(no_mangle)]
409pub unsafe extern "C" fn live_clock_next_time(
410 clock: &mut LiveClock_API,
411 name_ptr: *const c_char,
412) -> UnixNanos {
413 let name = unsafe { cstr_as_str(name_ptr) };
414 clock.next_time_ns(name)
415}
416
417#[unsafe(no_mangle)]
421pub unsafe extern "C" fn live_clock_cancel_timer(
422 clock: &mut LiveClock_API,
423 name_ptr: *const c_char,
424) {
425 let name = unsafe { cstr_as_str(name_ptr) };
426 clock.cancel_timer(name);
427}
428
429#[unsafe(no_mangle)]
430pub extern "C" fn live_clock_cancel_timers(clock: &mut LiveClock_API) {
431 clock.cancel_timers();
432}