use std::{
ffi::c_char,
ops::{Deref, DerefMut},
};
#[cfg(feature = "python")]
use nautilus_core::correctness::FAILED;
use nautilus_core::{
UnixNanos,
ffi::{
cvec::CVec,
parsing::u8_as_bool,
string::{cstr_as_str, str_to_cstr},
},
};
#[cfg(feature = "python")]
use pyo3::{ffi, prelude::*};
use super::timer::TimeEventHandler_API;
#[cfg(feature = "python")]
use crate::timer::TimeEventCallback;
use crate::{
clock::{Clock, TestClock},
live::clock::LiveClock,
timer::TimeEvent,
};
#[repr(C)]
#[derive(Debug)]
#[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
}
}
#[unsafe(no_mangle)]
pub extern "C" fn test_clock_new() -> TestClock_API {
TestClock_API(Box::default())
}
#[unsafe(no_mangle)]
pub extern "C" fn test_clock_drop(clock: TestClock_API) {
drop(clock); }
#[cfg(feature = "python")]
#[unsafe(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!(unsafe { ffi::Py_None() } != callback_ptr);
let callback = Python::attach(|py| unsafe {
Bound::<PyAny>::from_borrowed_ptr(py, callback_ptr).unbind()
});
let callback = TimeEventCallback::from(callback);
clock.register_default_handler(callback);
}
#[unsafe(no_mangle)]
pub extern "C" fn test_clock_set_time(clock: &TestClock_API, to_time_ns: u64) {
clock.set_time(to_time_ns.into());
}
#[unsafe(no_mangle)]
pub extern "C" fn test_clock_timestamp(clock: &TestClock_API) -> f64 {
clock.get_time()
}
#[unsafe(no_mangle)]
pub extern "C" fn test_clock_timestamp_ms(clock: &TestClock_API) -> u64 {
clock.get_time_ms()
}
#[unsafe(no_mangle)]
pub extern "C" fn test_clock_timestamp_us(clock: &TestClock_API) -> u64 {
clock.get_time_us()
}
#[unsafe(no_mangle)]
pub extern "C" fn test_clock_timestamp_ns(clock: &TestClock_API) -> u64 {
clock.get_time_ns().as_u64()
}
#[unsafe(no_mangle)]
pub extern "C" fn test_clock_timer_names(clock: &TestClock_API) -> *const c_char {
str_to_cstr(&clock.timer_names().join("<,>"))
}
#[unsafe(no_mangle)]
pub extern "C" fn test_clock_timer_count(clock: &mut TestClock_API) -> usize {
clock.timer_count()
}
#[cfg(feature = "python")]
#[unsafe(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,
allow_past: u8,
) {
assert!(!callback_ptr.is_null());
let name = unsafe { cstr_as_str(name_ptr) };
let callback = if callback_ptr == unsafe { ffi::Py_None() } {
None
} else {
let callback = Python::attach(|py| unsafe {
Bound::<PyAny>::from_borrowed_ptr(py, callback_ptr).unbind()
});
Some(TimeEventCallback::from(callback))
};
clock
.set_time_alert_ns(name, alert_time_ns, callback, Some(allow_past != 0))
.expect(FAILED);
}
#[cfg(feature = "python")]
#[unsafe(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,
allow_past: u8,
fire_immediately: u8,
) {
assert!(!callback_ptr.is_null());
let name = unsafe { cstr_as_str(name_ptr) };
let start_time_ns = (start_time_ns != 0).then_some(start_time_ns);
let stop_time_ns = (stop_time_ns != 0).then_some(stop_time_ns);
let callback = if callback_ptr == unsafe { ffi::Py_None() } {
None
} else {
let callback = Python::attach(|py| unsafe {
Bound::<PyAny>::from_borrowed_ptr(py, callback_ptr).unbind()
});
Some(TimeEventCallback::from(callback))
};
clock
.set_timer_ns(
name,
interval_ns,
start_time_ns,
stop_time_ns,
callback,
Some(allow_past != 0),
Some(fire_immediately != 0),
)
.expect(FAILED);
}
#[unsafe(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_API> = clock
.match_handlers(events)
.into_iter()
.map(Into::into)
.collect();
t.into()
}
#[unsafe(no_mangle)]
pub extern "C" fn vec_time_event_handlers_drop(v: CVec) {
let CVec { ptr, len, cap } = v;
assert!(
len <= cap,
"vec_time_event_handlers_drop: len ({len}) > cap ({cap}) - memory corruption or wrong drop helper"
);
assert!(
len == 0 || !ptr.is_null(),
"vec_time_event_handlers_drop: null ptr with non-zero len ({len}) - memory corruption or wrong drop helper"
);
let data: Vec<TimeEventHandler_API> =
unsafe { Vec::from_raw_parts(ptr.cast::<TimeEventHandler_API>(), len, cap) };
drop(data); }
#[unsafe(no_mangle)]
pub unsafe extern "C" fn test_clock_next_time(
clock: &mut TestClock_API,
name_ptr: *const c_char,
) -> UnixNanos {
let name = unsafe { cstr_as_str(name_ptr) };
clock.next_time_ns(name).unwrap_or_default()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn test_clock_cancel_timer(
clock: &mut TestClock_API,
name_ptr: *const c_char,
) {
let name = unsafe { cstr_as_str(name_ptr) };
clock.cancel_timer(name);
}
#[unsafe(no_mangle)]
pub extern "C" fn test_clock_cancel_timers(clock: &mut TestClock_API) {
clock.cancel_timers();
}
#[repr(C)]
#[derive(Debug)]
#[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
}
}
#[unsafe(no_mangle)]
pub extern "C" fn live_clock_new() -> LiveClock_API {
LiveClock_API(Box::new(LiveClock::new(None)))
}
#[unsafe(no_mangle)]
pub extern "C" fn live_clock_drop(clock: LiveClock_API) {
drop(clock); }
#[cfg(feature = "python")]
#[unsafe(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!(unsafe { ffi::Py_None() } != callback_ptr);
let callback = Python::attach(|py| unsafe {
Bound::<PyAny>::from_borrowed_ptr(py, callback_ptr).unbind()
});
let callback = TimeEventCallback::from(callback);
clock.register_default_handler(callback);
}
#[unsafe(no_mangle)]
pub extern "C" fn live_clock_timestamp(clock: &mut LiveClock_API) -> f64 {
clock.get_time()
}
#[unsafe(no_mangle)]
pub extern "C" fn live_clock_timestamp_ms(clock: &mut LiveClock_API) -> u64 {
clock.get_time_ms()
}
#[unsafe(no_mangle)]
pub extern "C" fn live_clock_timestamp_us(clock: &mut LiveClock_API) -> u64 {
clock.get_time_us()
}
#[unsafe(no_mangle)]
pub extern "C" fn live_clock_timestamp_ns(clock: &mut LiveClock_API) -> u64 {
clock.get_time_ns().as_u64()
}
#[unsafe(no_mangle)]
pub extern "C" fn live_clock_timer_names(clock: &LiveClock_API) -> *const c_char {
str_to_cstr(&clock.timer_names().join("<,>"))
}
#[unsafe(no_mangle)]
pub extern "C" fn live_clock_timer_count(clock: &mut LiveClock_API) -> usize {
clock.timer_count()
}
#[cfg(feature = "python")]
#[unsafe(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,
allow_past: u8,
) {
assert!(!callback_ptr.is_null());
let name = unsafe { cstr_as_str(name_ptr) };
let callback = if callback_ptr == unsafe { ffi::Py_None() } {
None
} else {
let callback = Python::attach(|py| unsafe {
Bound::<PyAny>::from_borrowed_ptr(py, callback_ptr).unbind()
});
Some(TimeEventCallback::from(callback))
};
clock
.set_time_alert_ns(name, alert_time_ns, callback, Some(allow_past != 0))
.expect(FAILED);
}
#[cfg(feature = "python")]
#[unsafe(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,
allow_past: u8,
fire_immediately: u8,
) {
assert!(!callback_ptr.is_null());
let name = unsafe { cstr_as_str(name_ptr) };
let start_time_ns = (start_time_ns != 0).then_some(start_time_ns);
let stop_time_ns = (stop_time_ns != 0).then_some(stop_time_ns);
let callback = if callback_ptr == unsafe { ffi::Py_None() } {
None
} else {
let callback = Python::attach(|py| unsafe {
Bound::<PyAny>::from_borrowed_ptr(py, callback_ptr).unbind()
});
Some(TimeEventCallback::from(callback))
};
clock
.set_timer_ns(
name,
interval_ns,
start_time_ns,
stop_time_ns,
callback,
Some(allow_past != 0),
Some(fire_immediately != 0),
)
.expect(FAILED);
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn live_clock_next_time(
clock: &mut LiveClock_API,
name_ptr: *const c_char,
) -> UnixNanos {
let name = unsafe { cstr_as_str(name_ptr) };
clock.next_time_ns(name).unwrap_or_default()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn live_clock_cancel_timer(
clock: &mut LiveClock_API,
name_ptr: *const c_char,
) {
let name = unsafe { cstr_as_str(name_ptr) };
clock.cancel_timer(name);
}
#[unsafe(no_mangle)]
pub extern "C" fn live_clock_cancel_timers(clock: &mut LiveClock_API) {
clock.cancel_timers();
}