nautilus_model/ffi/types/
currency.rs1use std::{ffi::c_char, str::FromStr};
17
18use nautilus_core::ffi::string::{cstr_as_str, str_to_cstr};
19
20use crate::{currencies::CURRENCY_MAP, enums::CurrencyType, types::Currency};
21
22#[unsafe(no_mangle)]
30pub unsafe extern "C" fn currency_from_py(
31 code_ptr: *const c_char,
32 precision: u8,
33 iso4217: u16,
34 name_ptr: *const c_char,
35 currency_type: CurrencyType,
36) -> Currency {
37 Currency::new(
38 unsafe { cstr_as_str(code_ptr) },
39 precision,
40 iso4217,
41 unsafe { cstr_as_str(name_ptr) },
42 currency_type,
43 )
44}
45
46#[unsafe(no_mangle)]
47pub extern "C" fn currency_to_cstr(currency: &Currency) -> *const c_char {
48 str_to_cstr(format!("{currency:?}").as_str())
49}
50
51#[unsafe(no_mangle)]
52pub extern "C" fn currency_code_to_cstr(currency: &Currency) -> *const c_char {
53 str_to_cstr(¤cy.code)
54}
55
56#[unsafe(no_mangle)]
57pub extern "C" fn currency_name_to_cstr(currency: &Currency) -> *const c_char {
58 str_to_cstr(¤cy.name)
59}
60
61#[unsafe(no_mangle)]
62pub extern "C" fn currency_hash(currency: &Currency) -> u64 {
63 currency.code.precomputed_hash()
64}
65
66#[unsafe(no_mangle)]
72pub extern "C" fn currency_register(currency: Currency) {
73 CURRENCY_MAP
74 .lock()
75 .unwrap()
76 .insert(currency.code.to_string(), currency);
77}
78
79#[unsafe(no_mangle)]
89pub unsafe extern "C" fn currency_exists(code_ptr: *const c_char) -> u8 {
90 let code = unsafe { cstr_as_str(code_ptr) };
91 u8::from(CURRENCY_MAP.lock().unwrap().contains_key(code))
92}
93
94#[unsafe(no_mangle)]
104pub unsafe extern "C" fn currency_from_cstr(code_ptr: *const c_char) -> Currency {
105 let code = unsafe { cstr_as_str(code_ptr) };
106 Currency::from_str(code).unwrap()
107}
108
109#[cfg(test)]
113mod tests {
114 use std::ffi::{CStr, CString};
115
116 use rstest::rstest;
117
118 use super::*;
119 use crate::{enums::CurrencyType, types::Currency};
120
121 #[rstest]
122 fn test_registration() {
123 let currency = Currency::new("MYC", 4, 0, "My Currency", CurrencyType::Crypto);
124 currency_register(currency);
125 unsafe {
126 assert_eq!(currency_exists(str_to_cstr("MYC")), 1);
127 }
128 }
129
130 #[rstest]
131 fn test_currency_from_py() {
132 let code = CString::new("MYC").unwrap();
133 let name = CString::new("My Currency").unwrap();
134 let currency = unsafe {
135 super::currency_from_py(code.as_ptr(), 4, 0, name.as_ptr(), CurrencyType::Crypto)
136 };
137 assert_eq!(currency.code.as_str(), "MYC");
138 assert_eq!(currency.name.as_str(), "My Currency");
139 assert_eq!(currency.currency_type, CurrencyType::Crypto);
140 }
141
142 #[rstest]
143 fn test_currency_to_cstr() {
144 let currency = Currency::USD();
145 let cstr = unsafe { CStr::from_ptr(currency_to_cstr(¤cy)) };
146 let expected_output = format!("{currency:?}");
147 assert_eq!(cstr.to_str().unwrap(), expected_output);
148 }
149
150 #[rstest]
151 fn test_currency_code_to_cstr() {
152 let currency = Currency::USD();
153 let cstr = unsafe { CStr::from_ptr(currency_code_to_cstr(¤cy)) };
154 assert_eq!(cstr.to_str().unwrap(), "USD");
155 }
156
157 #[rstest]
158 fn test_currency_name_to_cstr() {
159 let currency = Currency::USD();
160 let cstr = unsafe { CStr::from_ptr(currency_name_to_cstr(¤cy)) };
161 assert_eq!(cstr.to_str().unwrap(), "United States dollar");
162 }
163
164 #[rstest]
165 fn test_currency_hash() {
166 let currency = Currency::USD();
167 let hash = super::currency_hash(¤cy);
168 assert_eq!(hash, currency.code.precomputed_hash());
169 }
170
171 #[rstest]
172 fn test_currency_from_cstr() {
173 let code = CString::new("USD").unwrap();
174 let currency = unsafe { currency_from_cstr(code.as_ptr()) };
175 assert_eq!(currency, Currency::USD());
176 }
177}