nautilus_model/ffi/types/
currency.rs1use std::{ffi::c_char, str::FromStr};
17
18use nautilus_core::ffi::{
19 abort_on_panic,
20 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)]
71pub extern "C" fn currency_register(currency: Currency) {
72 abort_on_panic(|| {
73 CURRENCY_MAP
74 .lock()
75 .insert(currency.code.to_string(), currency);
76 });
77}
78
79#[unsafe(no_mangle)]
86pub unsafe extern "C" fn currency_exists(code_ptr: *const c_char) -> u8 {
87 abort_on_panic(|| {
88 let code = unsafe { cstr_as_str(code_ptr) };
89 u8::from(CURRENCY_MAP.lock().contains_key(code))
90 })
91}
92
93#[unsafe(no_mangle)]
103pub unsafe extern "C" fn currency_from_cstr(code_ptr: *const c_char) -> Currency {
104 abort_on_panic(|| {
105 let code = unsafe { cstr_as_str(code_ptr) };
106 Currency::from_str(code).unwrap()
107 })
108}
109
110#[cfg(test)]
111mod tests {
112 use std::ffi::{CStr, CString};
113
114 use rstest::rstest;
115
116 use super::*;
117 use crate::{enums::CurrencyType, types::Currency};
118
119 #[rstest]
120 fn test_registration() {
121 let currency = Currency::new("MYC", 4, 0, "My Currency", CurrencyType::Crypto);
122 currency_register(currency);
123 unsafe {
124 assert_eq!(currency_exists(str_to_cstr("MYC")), 1);
125 }
126 }
127
128 #[rstest]
129 fn test_currency_from_py() {
130 let code = CString::new("MYC").unwrap();
131 let name = CString::new("My Currency").unwrap();
132 let currency = unsafe {
133 super::currency_from_py(code.as_ptr(), 4, 0, name.as_ptr(), CurrencyType::Crypto)
134 };
135 assert_eq!(currency.code, "MYC");
136 assert_eq!(currency.name, "My Currency");
137 assert_eq!(currency.currency_type, CurrencyType::Crypto);
138 }
139
140 #[rstest]
141 fn test_currency_to_cstr() {
142 let currency = Currency::USD();
143 let cstr = unsafe { CStr::from_ptr(currency_to_cstr(¤cy)) };
144 let expected_output = format!("{currency:?}");
145 assert_eq!(cstr.to_str().unwrap(), expected_output);
146 }
147
148 #[rstest]
149 fn test_currency_code_to_cstr() {
150 let currency = Currency::USD();
151 let cstr = unsafe { CStr::from_ptr(currency_code_to_cstr(¤cy)) };
152 assert_eq!(cstr.to_str().unwrap(), "USD");
153 }
154
155 #[rstest]
156 fn test_currency_name_to_cstr() {
157 let currency = Currency::USD();
158 let cstr = unsafe { CStr::from_ptr(currency_name_to_cstr(¤cy)) };
159 assert_eq!(cstr.to_str().unwrap(), "United States dollar");
160 }
161
162 #[rstest]
163 fn test_currency_hash() {
164 let currency = Currency::USD();
165 let hash = super::currency_hash(¤cy);
166 assert_eq!(hash, currency.code.precomputed_hash());
167 }
168
169 #[rstest]
170 fn test_currency_from_cstr() {
171 let code = CString::new("USD").unwrap();
172 let currency = unsafe { currency_from_cstr(code.as_ptr()) };
173 assert_eq!(currency, Currency::USD());
174 }
175}