nautilus_common/ffi/
clock.rs1use std::{
17 ffi::c_char,
18 ops::{Deref, DerefMut},
19};
20
21use nautilus_core::{
22 UnixNanos,
23 correctness::FAILED,
24 ffi::{cvec::CVec, parsing::u8_as_bool, string::cstr_as_str},
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#[unsafe(no_mangle)]
65pub extern "C" fn test_clock_new() -> TestClock_API {
66 TestClock_API(Box::new(TestClock::new()))
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) -> *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#[unsafe(no_mangle)]
132pub extern "C" fn test_clock_timer_count(clock: &mut TestClock_API) -> usize {
133 clock.timer_count()
134}
135
136#[unsafe(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 = unsafe { cstr_as_str(name_ptr) };
150 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
151 None
152 } else {
153 let callback =
154 Python::with_gil(|py| unsafe { PyObject::from_borrowed_ptr(py, callback_ptr) });
155 Some(TimeEventCallback::from(callback))
156 };
157
158 clock
159 .set_time_alert_ns(name, alert_time_ns, callback)
160 .expect(FAILED);
161}
162
163#[unsafe(no_mangle)]
168pub unsafe extern "C" fn test_clock_set_timer(
169 clock: &mut TestClock_API,
170 name_ptr: *const c_char,
171 interval_ns: u64,
172 start_time_ns: UnixNanos,
173 stop_time_ns: UnixNanos,
174 callback_ptr: *mut ffi::PyObject,
175) {
176 assert!(!callback_ptr.is_null());
177
178 let name = unsafe { cstr_as_str(name_ptr) };
179 let stop_time_ns = match stop_time_ns.into() {
180 0 => None,
181 _ => Some(stop_time_ns),
182 };
183 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
184 None
185 } else {
186 let callback =
187 Python::with_gil(|py| unsafe { PyObject::from_borrowed_ptr(py, callback_ptr) });
188 Some(TimeEventCallback::from(callback))
189 };
190
191 clock
192 .set_timer_ns(name, interval_ns, start_time_ns, stop_time_ns, callback)
193 .expect(FAILED);
194}
195
196#[unsafe(no_mangle)]
200pub unsafe extern "C" fn test_clock_advance_time(
201 clock: &mut TestClock_API,
202 to_time_ns: u64,
203 set_time: u8,
204) -> CVec {
205 let events: Vec<TimeEvent> = clock.advance_time(to_time_ns.into(), u8_as_bool(set_time));
206 let t: Vec<TimeEventHandler> = clock
207 .match_handlers(events)
208 .into_iter()
209 .map(Into::into)
210 .collect();
211 t.into()
212}
213
214#[allow(clippy::drop_non_drop)]
217#[unsafe(no_mangle)]
218pub extern "C" fn vec_time_event_handlers_drop(v: CVec) {
219 let CVec { ptr, len, cap } = v;
220 let data: Vec<TimeEventHandler> =
221 unsafe { Vec::from_raw_parts(ptr.cast::<TimeEventHandler>(), len, cap) };
222 drop(data); }
224
225#[unsafe(no_mangle)]
229pub unsafe extern "C" fn test_clock_next_time(
230 clock: &mut TestClock_API,
231 name_ptr: *const c_char,
232) -> UnixNanos {
233 let name = unsafe { cstr_as_str(name_ptr) };
234 clock.next_time_ns(name)
235}
236
237#[unsafe(no_mangle)]
241pub unsafe extern "C" fn test_clock_cancel_timer(
242 clock: &mut TestClock_API,
243 name_ptr: *const c_char,
244) {
245 let name = unsafe { cstr_as_str(name_ptr) };
246 clock.cancel_timer(name);
247}
248
249#[unsafe(no_mangle)]
250pub extern "C" fn test_clock_cancel_timers(clock: &mut TestClock_API) {
251 clock.cancel_timers();
252}
253
254#[repr(C)]
264#[allow(non_camel_case_types)]
265pub struct LiveClock_API(Box<LiveClock>);
266
267impl Deref for LiveClock_API {
268 type Target = LiveClock;
269
270 fn deref(&self) -> &Self::Target {
271 &self.0
272 }
273}
274
275impl DerefMut for LiveClock_API {
276 fn deref_mut(&mut self) -> &mut Self::Target {
277 &mut self.0
278 }
279}
280
281#[unsafe(no_mangle)]
282pub extern "C" fn live_clock_new() -> LiveClock_API {
283 LiveClock_API(Box::new(LiveClock::new()))
284}
285
286#[unsafe(no_mangle)]
287pub extern "C" fn live_clock_drop(clock: LiveClock_API) {
288 drop(clock); }
290
291#[unsafe(no_mangle)]
295pub unsafe extern "C" fn live_clock_register_default_handler(
296 clock: &mut LiveClock_API,
297 callback_ptr: *mut ffi::PyObject,
298) {
299 assert!(!callback_ptr.is_null());
300 assert!(unsafe { ffi::Py_None() } != callback_ptr);
301
302 let callback = Python::with_gil(|py| unsafe { PyObject::from_borrowed_ptr(py, callback_ptr) });
303 let callback = TimeEventCallback::from(callback);
304
305 clock.register_default_handler(callback);
306}
307
308#[unsafe(no_mangle)]
309pub extern "C" fn live_clock_timestamp(clock: &mut LiveClock_API) -> f64 {
310 clock.get_time()
311}
312
313#[unsafe(no_mangle)]
314pub extern "C" fn live_clock_timestamp_ms(clock: &mut LiveClock_API) -> u64 {
315 clock.get_time_ms()
316}
317
318#[unsafe(no_mangle)]
319pub extern "C" fn live_clock_timestamp_us(clock: &mut LiveClock_API) -> u64 {
320 clock.get_time_us()
321}
322
323#[unsafe(no_mangle)]
324pub extern "C" fn live_clock_timestamp_ns(clock: &mut LiveClock_API) -> u64 {
325 clock.get_time_ns().as_u64()
326}
327
328#[unsafe(no_mangle)]
329pub extern "C" fn live_clock_timer_names(clock: &LiveClock_API) -> *mut ffi::PyObject {
330 Python::with_gil(|py| -> Py<PyList> {
331 let names: Vec<Py<PyString>> = clock
332 .get_timers()
333 .keys()
334 .map(|k| PyString::new(py, k).into())
335 .collect();
336 PyList::new(py, names)
337 .expect("Invalid `ExactSizeIterator`")
338 .into()
339 })
340 .as_ptr()
341}
342
343#[unsafe(no_mangle)]
344pub extern "C" fn live_clock_timer_count(clock: &mut LiveClock_API) -> usize {
345 clock.timer_count()
346}
347
348#[unsafe(no_mangle)]
359pub unsafe extern "C" fn live_clock_set_time_alert(
360 clock: &mut LiveClock_API,
361 name_ptr: *const c_char,
362 alert_time_ns: UnixNanos,
363 callback_ptr: *mut ffi::PyObject,
364) {
365 assert!(!callback_ptr.is_null());
366
367 let name = unsafe { cstr_as_str(name_ptr) };
368 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
369 None
370 } else {
371 let callback =
372 Python::with_gil(|py| unsafe { PyObject::from_borrowed_ptr(py, callback_ptr) });
373 Some(TimeEventCallback::from(callback))
374 };
375
376 clock
377 .set_time_alert_ns(name, alert_time_ns, callback)
378 .expect(FAILED);
379}
380
381#[unsafe(no_mangle)]
392pub unsafe extern "C" fn live_clock_set_timer(
393 clock: &mut LiveClock_API,
394 name_ptr: *const c_char,
395 interval_ns: u64,
396 start_time_ns: UnixNanos,
397 stop_time_ns: UnixNanos,
398 callback_ptr: *mut ffi::PyObject,
399) {
400 assert!(!callback_ptr.is_null());
401
402 let name = unsafe { cstr_as_str(name_ptr) };
403 let stop_time_ns = match stop_time_ns.into() {
404 0 => None,
405 _ => Some(stop_time_ns),
406 };
407
408 let callback = if callback_ptr == unsafe { ffi::Py_None() } {
409 None
410 } else {
411 let callback =
412 Python::with_gil(|py| unsafe { PyObject::from_borrowed_ptr(py, callback_ptr) });
413 Some(TimeEventCallback::from(callback))
414 };
415
416 clock
417 .set_timer_ns(name, interval_ns, start_time_ns, stop_time_ns, callback)
418 .expect(FAILED);
419}
420
421#[unsafe(no_mangle)]
425pub unsafe extern "C" fn live_clock_next_time(
426 clock: &mut LiveClock_API,
427 name_ptr: *const c_char,
428) -> UnixNanos {
429 let name = unsafe { cstr_as_str(name_ptr) };
430 clock.next_time_ns(name)
431}
432
433#[unsafe(no_mangle)]
437pub unsafe extern "C" fn live_clock_cancel_timer(
438 clock: &mut LiveClock_API,
439 name_ptr: *const c_char,
440) {
441 let name = unsafe { cstr_as_str(name_ptr) };
442 clock.cancel_timer(name);
443}
444
445#[unsafe(no_mangle)]
446pub extern "C" fn live_clock_cancel_timers(clock: &mut LiveClock_API) {
447 clock.cancel_timers();
448}