use std::{
ffi::c_char,
ops::{Deref, DerefMut},
};
use nautilus_core::{
ffi::{cvec::CVec, parsing::u8_as_bool, string::cstr_as_str},
nanos::UnixNanos,
};
use pyo3::{
ffi,
prelude::*,
types::{PyList, PyString},
};
use super::timer::TimeEventHandler;
use crate::{
clock::{Clock, LiveClock, TestClock},
timer::{TimeEvent, TimeEventCallback},
};
#[repr(C)]
#[allow(non_camel_case_types)]
pub struct TestClock_API(Box<TestClock>);
impl Deref for TestClock_API {
type Target = TestClock;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for TestClock_API {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[no_mangle]
pub extern "C" fn test_clock_new() -> TestClock_API {
TestClock_API(Box::new(TestClock::new()))
}
#[no_mangle]
pub extern "C" fn test_clock_drop(clock: TestClock_API) {
drop(clock); }
#[no_mangle]
pub unsafe extern "C" fn test_clock_register_default_handler(
clock: &mut TestClock_API,
callback_ptr: *mut ffi::PyObject,
) {
assert!(!callback_ptr.is_null());
assert!(ffi::Py_None() != callback_ptr);
let callback = Python::with_gil(|py| PyObject::from_borrowed_ptr(py, callback_ptr));
let callback = TimeEventCallback::from(callback);
clock.register_default_handler(callback);
}
#[no_mangle]
pub extern "C" fn test_clock_set_time(clock: &TestClock_API, to_time_ns: u64) {
clock.set_time(to_time_ns.into());
}
#[no_mangle]
pub extern "C" fn test_clock_timestamp(clock: &TestClock_API) -> f64 {
clock.get_time()
}
#[no_mangle]
pub extern "C" fn test_clock_timestamp_ms(clock: &TestClock_API) -> u64 {
clock.get_time_ms()
}
#[no_mangle]
pub extern "C" fn test_clock_timestamp_us(clock: &TestClock_API) -> u64 {
clock.get_time_us()
}
#[no_mangle]
pub extern "C" fn test_clock_timestamp_ns(clock: &TestClock_API) -> u64 {
clock.get_time_ns().as_u64()
}
#[no_mangle]
pub extern "C" fn test_clock_timer_names(clock: &TestClock_API) -> *mut ffi::PyObject {
Python::with_gil(|py| -> Py<PyList> {
let names: Vec<Py<PyString>> = clock
.get_timers()
.keys()
.map(|k| PyString::new_bound(py, k).into())
.collect();
PyList::new_bound(py, names).into()
})
.as_ptr()
}
#[no_mangle]
pub extern "C" fn test_clock_timer_count(clock: &mut TestClock_API) -> usize {
clock.timer_count()
}
#[no_mangle]
pub unsafe extern "C" fn test_clock_set_time_alert(
clock: &mut TestClock_API,
name_ptr: *const c_char,
alert_time_ns: UnixNanos,
callback_ptr: *mut ffi::PyObject,
) {
assert!(!callback_ptr.is_null());
let name = cstr_as_str(name_ptr);
let callback = match callback_ptr == ffi::Py_None() {
true => None,
false => {
let callback = Python::with_gil(|py| PyObject::from_borrowed_ptr(py, callback_ptr));
Some(TimeEventCallback::from(callback))
}
};
clock.set_time_alert_ns(name, alert_time_ns, callback);
}
#[no_mangle]
pub unsafe extern "C" fn test_clock_set_timer(
clock: &mut TestClock_API,
name_ptr: *const c_char,
interval_ns: u64,
start_time_ns: UnixNanos,
stop_time_ns: UnixNanos,
callback_ptr: *mut ffi::PyObject,
) {
assert!(!callback_ptr.is_null());
let name = cstr_as_str(name_ptr);
let stop_time_ns = match stop_time_ns.into() {
0 => None,
_ => Some(stop_time_ns),
};
let callback = match callback_ptr == ffi::Py_None() {
true => None,
false => {
let callback = Python::with_gil(|py| PyObject::from_borrowed_ptr(py, callback_ptr));
Some(TimeEventCallback::from(callback))
}
};
clock.set_timer_ns(name, interval_ns, start_time_ns, stop_time_ns, callback);
}
#[no_mangle]
pub unsafe extern "C" fn test_clock_advance_time(
clock: &mut TestClock_API,
to_time_ns: u64,
set_time: u8,
) -> CVec {
let events: Vec<TimeEvent> = clock.advance_time(to_time_ns.into(), u8_as_bool(set_time));
let t: Vec<TimeEventHandler> = clock
.match_handlers(events)
.into_iter()
.map(Into::into)
.collect();
t.into()
}
#[allow(clippy::drop_non_drop)]
#[no_mangle]
pub extern "C" fn vec_time_event_handlers_drop(v: CVec) {
let CVec { ptr, len, cap } = v;
let data: Vec<TimeEventHandler> =
unsafe { Vec::from_raw_parts(ptr.cast::<TimeEventHandler>(), len, cap) };
drop(data); }
#[no_mangle]
pub unsafe extern "C" fn test_clock_next_time(
clock: &mut TestClock_API,
name_ptr: *const c_char,
) -> UnixNanos {
let name = cstr_as_str(name_ptr);
clock.next_time_ns(name)
}
#[no_mangle]
pub unsafe extern "C" fn test_clock_cancel_timer(
clock: &mut TestClock_API,
name_ptr: *const c_char,
) {
let name = cstr_as_str(name_ptr);
clock.cancel_timer(name);
}
#[no_mangle]
pub extern "C" fn test_clock_cancel_timers(clock: &mut TestClock_API) {
clock.cancel_timers();
}
#[repr(C)]
#[allow(non_camel_case_types)]
pub struct LiveClock_API(Box<LiveClock>);
impl Deref for LiveClock_API {
type Target = LiveClock;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for LiveClock_API {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[no_mangle]
pub extern "C" fn live_clock_new() -> LiveClock_API {
LiveClock_API(Box::new(LiveClock::new()))
}
#[no_mangle]
pub extern "C" fn live_clock_drop(clock: LiveClock_API) {
drop(clock); }
#[no_mangle]
pub unsafe extern "C" fn live_clock_register_default_handler(
clock: &mut LiveClock_API,
callback_ptr: *mut ffi::PyObject,
) {
assert!(!callback_ptr.is_null());
assert!(ffi::Py_None() != callback_ptr);
let callback = Python::with_gil(|py| PyObject::from_borrowed_ptr(py, callback_ptr));
let callback = TimeEventCallback::from(callback);
clock.register_default_handler(callback);
}
#[no_mangle]
pub extern "C" fn live_clock_timestamp(clock: &mut LiveClock_API) -> f64 {
clock.get_time()
}
#[no_mangle]
pub extern "C" fn live_clock_timestamp_ms(clock: &mut LiveClock_API) -> u64 {
clock.get_time_ms()
}
#[no_mangle]
pub extern "C" fn live_clock_timestamp_us(clock: &mut LiveClock_API) -> u64 {
clock.get_time_us()
}
#[no_mangle]
pub extern "C" fn live_clock_timestamp_ns(clock: &mut LiveClock_API) -> u64 {
clock.get_time_ns().as_u64()
}
#[no_mangle]
pub extern "C" fn live_clock_timer_names(clock: &LiveClock_API) -> *mut ffi::PyObject {
Python::with_gil(|py| -> Py<PyList> {
let names: Vec<Py<PyString>> = clock
.get_timers()
.keys()
.map(|k| PyString::new_bound(py, k).into())
.collect();
PyList::new_bound(py, names).into()
})
.as_ptr()
}
#[no_mangle]
pub extern "C" fn live_clock_timer_count(clock: &mut LiveClock_API) -> usize {
clock.timer_count()
}
#[no_mangle]
pub unsafe extern "C" fn live_clock_set_time_alert(
clock: &mut LiveClock_API,
name_ptr: *const c_char,
alert_time_ns: UnixNanos,
callback_ptr: *mut ffi::PyObject,
) {
assert!(!callback_ptr.is_null());
let name = cstr_as_str(name_ptr);
let callback = match callback_ptr == ffi::Py_None() {
true => None,
false => {
let callback = Python::with_gil(|py| PyObject::from_borrowed_ptr(py, callback_ptr));
Some(TimeEventCallback::from(callback))
}
};
clock.set_time_alert_ns(name, alert_time_ns, callback);
}
#[no_mangle]
pub unsafe extern "C" fn live_clock_set_timer(
clock: &mut LiveClock_API,
name_ptr: *const c_char,
interval_ns: u64,
start_time_ns: UnixNanos,
stop_time_ns: UnixNanos,
callback_ptr: *mut ffi::PyObject,
) {
assert!(!callback_ptr.is_null());
let name = cstr_as_str(name_ptr);
let stop_time_ns = match stop_time_ns.into() {
0 => None,
_ => Some(stop_time_ns),
};
let callback = match callback_ptr == ffi::Py_None() {
true => None,
false => {
let callback = Python::with_gil(|py| PyObject::from_borrowed_ptr(py, callback_ptr));
Some(TimeEventCallback::from(callback))
}
};
clock.set_timer_ns(name, interval_ns, start_time_ns, stop_time_ns, callback);
}
#[no_mangle]
pub unsafe extern "C" fn live_clock_next_time(
clock: &mut LiveClock_API,
name_ptr: *const c_char,
) -> UnixNanos {
let name = cstr_as_str(name_ptr);
clock.next_time_ns(name)
}
#[no_mangle]
pub unsafe extern "C" fn live_clock_cancel_timer(
clock: &mut LiveClock_API,
name_ptr: *const c_char,
) {
let name = cstr_as_str(name_ptr);
clock.cancel_timer(name);
}
#[no_mangle]
pub extern "C" fn live_clock_cancel_timers(clock: &mut LiveClock_API) {
clock.cancel_timers();
}