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