Skip to main content

nautilus_model/ffi/data/
depth.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16use std::{
17    collections::hash_map::DefaultHasher,
18    hash::{Hash, Hasher},
19};
20
21use nautilus_core::{UnixNanos, ffi::abort_on_panic};
22
23use crate::{
24    data::depth::{DEPTH10_LEN, OrderBookDepth10},
25    ffi::data::order::BookOrderFfi,
26    identifiers::InstrumentId,
27};
28
29/// The stable C representation of an [`OrderBookDepth10`].
30#[repr(C)]
31#[derive(Clone, Copy, Debug)]
32pub struct OrderBookDepth10Ffi {
33    pub instrument_id: InstrumentId,
34    pub bids: [BookOrderFfi; DEPTH10_LEN],
35    pub asks: [BookOrderFfi; DEPTH10_LEN],
36    pub bid_counts: [u32; DEPTH10_LEN],
37    pub ask_counts: [u32; DEPTH10_LEN],
38    pub flags: u8,
39    pub sequence: u64,
40    pub ts_event: UnixNanos,
41    pub ts_init: UnixNanos,
42}
43
44impl From<OrderBookDepth10Ffi> for OrderBookDepth10 {
45    fn from(value: OrderBookDepth10Ffi) -> Self {
46        Self {
47            instrument_id: value.instrument_id,
48            bids: value.bids.map(Into::into),
49            asks: value.asks.map(Into::into),
50            bid_counts: value.bid_counts,
51            ask_counts: value.ask_counts,
52            flags: value.flags,
53            sequence: value.sequence,
54            ts_event: value.ts_event,
55            ts_init: value.ts_init,
56        }
57    }
58}
59
60impl From<OrderBookDepth10> for OrderBookDepth10Ffi {
61    fn from(value: OrderBookDepth10) -> Self {
62        Self {
63            instrument_id: value.instrument_id,
64            bids: value.bids.map(Into::into),
65            asks: value.asks.map(Into::into),
66            bid_counts: value.bid_counts,
67            ask_counts: value.ask_counts,
68            flags: value.flags,
69            sequence: value.sequence,
70            ts_event: value.ts_event,
71            ts_init: value.ts_init,
72        }
73    }
74}
75
76/// # Safety
77///
78/// This function assumes:
79/// - `bids` and `asks` are valid pointers to arrays of `BookOrderFfi` of length 10.
80/// - `bid_counts` and `ask_counts` are valid pointers to arrays of `u32` of length 10.
81///
82/// # Panics
83///
84/// Panics if any input pointer is null or if slice conversion for bids or asks fails.
85#[unsafe(no_mangle)]
86#[cfg_attr(feature = "high-precision", allow(improper_ctypes_definitions))]
87pub unsafe extern "C" fn orderbook_depth10_new(
88    instrument_id: InstrumentId,
89    bids_ptr: *const BookOrderFfi,
90    asks_ptr: *const BookOrderFfi,
91    bid_counts_ptr: *const u32,
92    ask_counts_ptr: *const u32,
93    flags: u8,
94    sequence: u64,
95    ts_event: UnixNanos,
96    ts_init: UnixNanos,
97) -> OrderBookDepth10Ffi {
98    abort_on_panic(|| {
99        // SAFETY: Null checks run before slice construction. The caller still
100        // guarantees each pointer refers to `DEPTH10_LEN` initialized elements.
101        assert!(!bids_ptr.is_null());
102        assert!(!asks_ptr.is_null());
103        assert!(!bid_counts_ptr.is_null());
104        assert!(!ask_counts_ptr.is_null());
105
106        let bids_slice = unsafe { std::slice::from_raw_parts(bids_ptr, DEPTH10_LEN) };
107        let asks_slice = unsafe { std::slice::from_raw_parts(asks_ptr, DEPTH10_LEN) };
108        let bids: [BookOrderFfi; DEPTH10_LEN] = bids_slice.try_into().expect("Slice length != 10");
109        let asks: [BookOrderFfi; DEPTH10_LEN] = asks_slice.try_into().expect("Slice length != 10");
110
111        let bid_counts_slice = unsafe { std::slice::from_raw_parts(bid_counts_ptr, DEPTH10_LEN) };
112        let ask_counts_slice = unsafe { std::slice::from_raw_parts(ask_counts_ptr, DEPTH10_LEN) };
113        let bid_counts: [u32; DEPTH10_LEN] =
114            bid_counts_slice.try_into().expect("Slice length != 10");
115        let ask_counts: [u32; DEPTH10_LEN] =
116            ask_counts_slice.try_into().expect("Slice length != 10");
117
118        OrderBookDepth10::new(
119            instrument_id,
120            bids.map(Into::into),
121            asks.map(Into::into),
122            bid_counts,
123            ask_counts,
124            flags,
125            sequence,
126            ts_event,
127            ts_init,
128        )
129        .into()
130    })
131}
132
133#[unsafe(no_mangle)]
134#[cfg_attr(feature = "high-precision", allow(improper_ctypes_definitions))]
135pub extern "C" fn orderbook_depth10_clone(depth: &OrderBookDepth10Ffi) -> OrderBookDepth10Ffi {
136    *depth
137}
138
139#[unsafe(no_mangle)]
140pub extern "C" fn orderbook_depth10_eq(lhs: &OrderBookDepth10Ffi, rhs: &OrderBookDepth10Ffi) -> u8 {
141    u8::from(OrderBookDepth10::from(*lhs) == OrderBookDepth10::from(*rhs))
142}
143
144#[unsafe(no_mangle)]
145pub extern "C" fn orderbook_depth10_hash(delta: &OrderBookDepth10Ffi) -> u64 {
146    let mut hasher = DefaultHasher::new();
147    OrderBookDepth10::from(*delta).hash(&mut hasher);
148    hasher.finish()
149}
150
151#[unsafe(no_mangle)]
152pub extern "C" fn orderbook_depth10_bids_array(depth: &OrderBookDepth10Ffi) -> *const BookOrderFfi {
153    depth.bids.as_ptr()
154}
155
156#[unsafe(no_mangle)]
157pub extern "C" fn orderbook_depth10_asks_array(depth: &OrderBookDepth10Ffi) -> *const BookOrderFfi {
158    depth.asks.as_ptr()
159}
160
161#[unsafe(no_mangle)]
162pub extern "C" fn orderbook_depth10_bid_counts_array(depth: &OrderBookDepth10Ffi) -> *const u32 {
163    depth.bid_counts.as_ptr()
164}
165
166#[unsafe(no_mangle)]
167pub extern "C" fn orderbook_depth10_ask_counts_array(depth: &OrderBookDepth10Ffi) -> *const u32 {
168    depth.ask_counts.as_ptr()
169}