use nautilus_core::{
UnixNanos,
ffi::{abort_on_panic, cvec::CVec},
};
use crate::{
data::OrderBookDeltas, ffi::data::delta::OrderBookDeltaFfi, identifiers::InstrumentId,
};
#[unsafe(no_mangle)]
pub unsafe extern "C" fn orderbook_deltas_new(
instrument_id: InstrumentId,
deltas: &CVec,
) -> *mut OrderBookDeltas {
let cloned_deltas = unsafe { deltas.as_slice::<OrderBookDeltaFfi>() }
.iter()
.copied()
.map(Into::into)
.collect();
Box::into_raw(Box::new(OrderBookDeltas::new(instrument_id, cloned_deltas)))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn orderbook_deltas_drop(deltas: *mut OrderBookDeltas) {
abort_on_panic(|| {
assert!(!deltas.is_null(), "`deltas` was NULL");
drop(unsafe { Box::from_raw(deltas) }); });
}
#[unsafe(no_mangle)]
pub extern "C" fn orderbook_deltas_clone(deltas: &OrderBookDeltas) -> *mut OrderBookDeltas {
Box::into_raw(Box::new(deltas.clone()))
}
#[unsafe(no_mangle)]
pub extern "C" fn orderbook_deltas_instrument_id(deltas: &OrderBookDeltas) -> InstrumentId {
deltas.instrument_id
}
#[unsafe(no_mangle)]
pub extern "C" fn orderbook_deltas_vec_deltas(deltas: &OrderBookDeltas) -> CVec {
deltas
.deltas
.iter()
.copied()
.map(OrderBookDeltaFfi::from)
.collect::<Vec<_>>()
.into()
}
#[unsafe(no_mangle)]
pub extern "C" fn orderbook_deltas_is_snapshot(deltas: &OrderBookDeltas) -> u8 {
u8::from(deltas.is_snapshot())
}
#[unsafe(no_mangle)]
pub extern "C" fn orderbook_deltas_flags(deltas: &OrderBookDeltas) -> u8 {
deltas.flags
}
#[unsafe(no_mangle)]
pub extern "C" fn orderbook_deltas_sequence(deltas: &OrderBookDeltas) -> u64 {
deltas.sequence
}
#[unsafe(no_mangle)]
pub extern "C" fn orderbook_deltas_ts_event(deltas: &OrderBookDeltas) -> UnixNanos {
deltas.ts_event
}
#[unsafe(no_mangle)]
pub extern "C" fn orderbook_deltas_ts_init(deltas: &OrderBookDeltas) -> UnixNanos {
deltas.ts_init
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn orderbook_deltas_vec_drop(v: CVec) {
let deltas = unsafe { v.into_vec::<OrderBookDeltaFfi>() };
drop(deltas); }
#[cfg(test)]
mod tests {
use rstest::rstest;
use super::*;
use crate::{
data::stubs::stub_delta,
enums::{BookAction, RecordFlag},
};
#[rstest]
fn test_empty_delta_drop_returns_without_panic() {
unsafe { orderbook_deltas_vec_drop(CVec::empty()) };
}
#[rstest]
fn test_orderbook_deltas_new_clones_borrowed_buffer() {
let delta = stub_delta();
let mut caller_owned = vec![OrderBookDeltaFfi::from(delta)];
let cvec = CVec {
ptr: caller_owned.as_mut_ptr().cast(),
len: caller_owned.len(),
cap: caller_owned.capacity(),
};
let deltas_ptr = unsafe { orderbook_deltas_new(delta.instrument_id, &cvec) };
let deltas = unsafe { &*deltas_ptr };
assert_eq!(deltas.deltas, vec![delta]);
caller_owned[0].sequence += 1;
assert_ne!(deltas.deltas[0].sequence, caller_owned[0].sequence);
unsafe { orderbook_deltas_drop(deltas_ptr) };
}
#[rstest]
#[case::snapshot(
BookAction::Add,
RecordFlag::F_SNAPSHOT as u8,
1
)]
#[case::combined_flags(
BookAction::Add,
RecordFlag::F_SNAPSHOT as u8 | RecordFlag::F_LAST as u8,
1
)]
#[case::not_snapshot(BookAction::Add, RecordFlag::F_MBP as u8, 0)]
#[case::clear_without_snapshot(BookAction::Clear, 0, 0)]
fn test_orderbook_deltas_is_snapshot(
#[case] action: BookAction,
#[case] flags: u8,
#[case] expected: u8,
) {
let mut delta = stub_delta();
delta.action = action;
delta.flags = flags;
let deltas = OrderBookDeltas::new(delta.instrument_id, vec![delta]);
assert_eq!(orderbook_deltas_is_snapshot(&deltas), expected);
}
}