nautilus_model/ffi/data/
deltas.rs1use nautilus_core::{
17 UnixNanos,
18 ffi::{abort_on_panic, cvec::CVec},
19};
20
21use crate::{
22 data::OrderBookDeltas, ffi::data::delta::OrderBookDeltaFfi, identifiers::InstrumentId,
23};
24
25#[unsafe(no_mangle)]
37pub unsafe extern "C" fn orderbook_deltas_new(
38 instrument_id: InstrumentId,
39 deltas: &CVec,
40) -> *mut OrderBookDeltas {
41 let cloned_deltas = unsafe { deltas.as_slice::<OrderBookDeltaFfi>() }
42 .iter()
43 .copied()
44 .map(Into::into)
45 .collect();
46 Box::into_raw(Box::new(OrderBookDeltas::new(instrument_id, cloned_deltas)))
47}
48
49#[unsafe(no_mangle)]
60pub unsafe extern "C" fn orderbook_deltas_drop(deltas: *mut OrderBookDeltas) {
61 abort_on_panic(|| {
62 assert!(!deltas.is_null(), "`deltas` was NULL");
63 drop(unsafe { Box::from_raw(deltas) }); });
66}
67
68#[unsafe(no_mangle)]
71pub extern "C" fn orderbook_deltas_clone(deltas: &OrderBookDeltas) -> *mut OrderBookDeltas {
72 Box::into_raw(Box::new(deltas.clone()))
73}
74
75#[unsafe(no_mangle)]
76pub extern "C" fn orderbook_deltas_instrument_id(deltas: &OrderBookDeltas) -> InstrumentId {
77 deltas.instrument_id
78}
79
80#[unsafe(no_mangle)]
81pub extern "C" fn orderbook_deltas_vec_deltas(deltas: &OrderBookDeltas) -> CVec {
82 deltas
83 .deltas
84 .iter()
85 .copied()
86 .map(OrderBookDeltaFfi::from)
87 .collect::<Vec<_>>()
88 .into()
89}
90
91#[unsafe(no_mangle)]
93pub extern "C" fn orderbook_deltas_is_snapshot(deltas: &OrderBookDeltas) -> u8 {
94 u8::from(deltas.is_snapshot())
95}
96
97#[unsafe(no_mangle)]
98pub extern "C" fn orderbook_deltas_flags(deltas: &OrderBookDeltas) -> u8 {
99 deltas.flags
100}
101
102#[unsafe(no_mangle)]
103pub extern "C" fn orderbook_deltas_sequence(deltas: &OrderBookDeltas) -> u64 {
104 deltas.sequence
105}
106
107#[unsafe(no_mangle)]
108pub extern "C" fn orderbook_deltas_ts_event(deltas: &OrderBookDeltas) -> UnixNanos {
109 deltas.ts_event
110}
111
112#[unsafe(no_mangle)]
113pub extern "C" fn orderbook_deltas_ts_init(deltas: &OrderBookDeltas) -> UnixNanos {
114 deltas.ts_init
115}
116
117#[unsafe(no_mangle)]
123pub unsafe extern "C" fn orderbook_deltas_vec_drop(v: CVec) {
124 let deltas = unsafe { v.into_vec::<OrderBookDeltaFfi>() };
125 drop(deltas); }
127
128#[cfg(test)]
129mod tests {
130 use rstest::rstest;
131
132 use super::*;
133 use crate::{
134 data::stubs::stub_delta,
135 enums::{BookAction, RecordFlag},
136 };
137
138 #[rstest]
139 fn test_empty_delta_drop_returns_without_panic() {
140 unsafe { orderbook_deltas_vec_drop(CVec::empty()) };
141 }
142
143 #[rstest]
144 fn test_orderbook_deltas_new_clones_borrowed_buffer() {
145 let delta = stub_delta();
146 let mut caller_owned = vec![OrderBookDeltaFfi::from(delta)];
147 let cvec = CVec {
148 ptr: caller_owned.as_mut_ptr().cast(),
149 len: caller_owned.len(),
150 cap: caller_owned.capacity(),
151 };
152
153 let deltas_ptr = unsafe { orderbook_deltas_new(delta.instrument_id, &cvec) };
154
155 let deltas = unsafe { &*deltas_ptr };
157 assert_eq!(deltas.deltas, vec![delta]);
158 caller_owned[0].sequence += 1;
159 assert_ne!(deltas.deltas[0].sequence, caller_owned[0].sequence);
160
161 unsafe { orderbook_deltas_drop(deltas_ptr) };
162 }
163
164 #[rstest]
165 #[case::snapshot(
166 BookAction::Add,
167 RecordFlag::F_SNAPSHOT as u8,
168 1
169 )]
170 #[case::combined_flags(
171 BookAction::Add,
172 RecordFlag::F_SNAPSHOT as u8 | RecordFlag::F_LAST as u8,
173 1
174 )]
175 #[case::not_snapshot(BookAction::Add, RecordFlag::F_MBP as u8, 0)]
176 #[case::clear_without_snapshot(BookAction::Clear, 0, 0)]
177 fn test_orderbook_deltas_is_snapshot(
178 #[case] action: BookAction,
179 #[case] flags: u8,
180 #[case] expected: u8,
181 ) {
182 let mut delta = stub_delta();
183 delta.action = action;
184 delta.flags = flags;
185 let deltas = OrderBookDeltas::new(delta.instrument_id, vec![delta]);
186
187 assert_eq!(orderbook_deltas_is_snapshot(&deltas), expected);
188 }
189}