nautilus_model/ffi/identifiers/
instrument_id.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 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    ffi::c_char,
19    hash::{Hash, Hasher},
20    str::FromStr,
21};
22
23use nautilus_core::ffi::string::{cstr_as_str, str_to_cstr};
24
25use crate::identifiers::{InstrumentId, Symbol, Venue};
26
27#[no_mangle]
28pub extern "C" fn instrument_id_new(symbol: Symbol, venue: Venue) -> InstrumentId {
29    InstrumentId::new(symbol, venue)
30}
31
32/// Returns any [`InstrumentId`] parsing error from the provided C string pointer.
33///
34/// # Safety
35///
36/// - Assumes `ptr` is a valid C string pointer.
37#[no_mangle]
38pub unsafe extern "C" fn instrument_id_check_parsing(ptr: *const c_char) -> *const c_char {
39    match InstrumentId::from_str(cstr_as_str(ptr)) {
40        Ok(_) => str_to_cstr(""),
41        Err(e) => str_to_cstr(&e.to_string()),
42    }
43}
44
45/// Returns a Nautilus identifier from a C string pointer.
46///
47/// # Safety
48///
49/// - Assumes `ptr` is a valid C string pointer.
50#[no_mangle]
51pub unsafe extern "C" fn instrument_id_from_cstr(ptr: *const c_char) -> InstrumentId {
52    InstrumentId::from(cstr_as_str(ptr))
53}
54
55/// Returns an [`InstrumentId`] as a C string pointer.
56#[no_mangle]
57pub extern "C" fn instrument_id_to_cstr(instrument_id: &InstrumentId) -> *const c_char {
58    str_to_cstr(&instrument_id.to_string())
59}
60
61#[no_mangle]
62pub extern "C" fn instrument_id_hash(instrument_id: &InstrumentId) -> u64 {
63    let mut h = DefaultHasher::new();
64    instrument_id.hash(&mut h);
65    h.finish()
66}
67
68#[no_mangle]
69pub extern "C" fn instrument_id_is_synthetic(instrument_id: &InstrumentId) -> u8 {
70    u8::from(instrument_id.is_synthetic())
71}
72
73#[cfg(test)]
74pub mod stubs {
75    use std::str::FromStr;
76
77    use rstest::fixture;
78
79    use crate::identifiers::{stubs::*, InstrumentId, Symbol, Venue};
80
81    #[fixture]
82    pub fn btc_usdt_perp_binance() -> InstrumentId {
83        InstrumentId::from_str("BTCUSDT-PERP.BINANCE").unwrap()
84    }
85
86    #[fixture]
87    pub fn audusd_sim(symbol_aud_usd: Symbol, venue_sim: Venue) -> InstrumentId {
88        InstrumentId {
89            symbol: symbol_aud_usd,
90            venue: venue_sim,
91        }
92    }
93}
94
95////////////////////////////////////////////////////////////////////////////////
96// Tests
97////////////////////////////////////////////////////////////////////////////////
98#[cfg(test)]
99mod tests {
100    use std::ffi::CStr;
101
102    use rstest::rstest;
103
104    use super::{InstrumentId, *};
105    use crate::identifiers::{Symbol, Venue};
106
107    #[rstest]
108    fn test_to_cstr() {
109        unsafe {
110            let id = InstrumentId::from("ETH/USDT.BINANCE");
111            let result = instrument_id_to_cstr(&id);
112            assert_eq!(CStr::from_ptr(result).to_str().unwrap(), "ETH/USDT.BINANCE");
113        }
114    }
115
116    #[rstest]
117    fn test_to_cstr_and_back() {
118        unsafe {
119            let id = InstrumentId::from("ETH/USDT.BINANCE");
120            let result = instrument_id_to_cstr(&id);
121            let id2 = instrument_id_from_cstr(result);
122            assert_eq!(id, id2);
123        }
124    }
125
126    #[rstest]
127    fn test_from_symbol_and_back() {
128        unsafe {
129            let id = InstrumentId::new(Symbol::from("ETH/USDT"), Venue::from("BINANCE"));
130            let result = instrument_id_to_cstr(&id);
131            let id2 = instrument_id_from_cstr(result);
132            assert_eq!(id, id2);
133        }
134    }
135}