diff --git a/nautilus_core/adapters/src/databento/decode.rs b/nautilus_core/adapters/src/databento/decode.rs index 748150d4c419..7720689b5c2f 100644 --- a/nautilus_core/adapters/src/databento/decode.rs +++ b/nautilus_core/adapters/src/databento/decode.rs @@ -294,7 +294,7 @@ pub fn decode_options_contract_v1( let currency_str = unsafe { raw_ptr_to_string(msg.currency.as_ptr())? }; let cfi_str = unsafe { raw_ptr_to_string(msg.cfi.as_ptr())? }; let exchange = unsafe { raw_ptr_to_ustr(msg.exchange.as_ptr())? }; - let asset_class_opt = match instrument_id.venue.value.as_str() { + let asset_class_opt = match instrument_id.venue.as_str() { "OPRA" => Some(AssetClass::Equity), _ => { let (asset_class, _) = parse_cfi_iso10926(&cfi_str)?; @@ -338,7 +338,7 @@ pub fn decode_options_spread_v1( let currency_str = unsafe { raw_ptr_to_string(msg.currency.as_ptr())? }; let cfi_str = unsafe { raw_ptr_to_string(msg.cfi.as_ptr())? }; let exchange = unsafe { raw_ptr_to_ustr(msg.exchange.as_ptr())? }; - let asset_class_opt = match instrument_id.venue.value.as_str() { + let asset_class_opt = match instrument_id.venue.as_str() { "OPRA" => Some(AssetClass::Equity), _ => { let (asset_class, _) = parse_cfi_iso10926(&cfi_str)?; @@ -632,7 +632,7 @@ pub fn decode_ohlcv_msg( // Adjust raw prices by a display factor let mut display_factor = 1; - if instrument_id.venue.value == "GLBX" { + if instrument_id.venue.as_str() == "GLBX" { display_factor = 100; }; @@ -890,7 +890,7 @@ pub fn decode_options_contract( let currency_str = unsafe { raw_ptr_to_string(msg.currency.as_ptr())? }; let cfi_str = unsafe { raw_ptr_to_string(msg.cfi.as_ptr())? }; let exchange = unsafe { raw_ptr_to_ustr(msg.exchange.as_ptr())? }; - let asset_class_opt = match instrument_id.venue.value.as_str() { + let asset_class_opt = match instrument_id.venue.as_str() { "OPRA" => Some(AssetClass::Equity), _ => { let (asset_class, _) = parse_cfi_iso10926(&cfi_str)?; @@ -933,7 +933,7 @@ pub fn decode_options_spread( ) -> anyhow::Result { let currency_str = unsafe { raw_ptr_to_string(msg.currency.as_ptr())? }; let cfi_str = unsafe { raw_ptr_to_string(msg.cfi.as_ptr())? }; - let asset_class_opt = match instrument_id.venue.value.as_str() { + let asset_class_opt = match instrument_id.venue.as_str() { "OPRA" => Some(AssetClass::Equity), _ => { let (asset_class, _) = parse_cfi_iso10926(&cfi_str)?; diff --git a/nautilus_core/adapters/src/databento/live.rs b/nautilus_core/adapters/src/databento/live.rs index 2951766a6dee..626e1989109d 100644 --- a/nautilus_core/adapters/src/databento/live.rs +++ b/nautilus_core/adapters/src/databento/live.rs @@ -40,7 +40,6 @@ use tokio::{ time::{timeout, Duration}, }; use tracing::{debug, error, info, trace}; -use ustr::Ustr; use super::{ decode::{decode_imbalance_msg, decode_statistics_msg}, @@ -357,9 +356,7 @@ fn update_instrument_id_map( .get_for_rec(record) .expect("Cannot resolve `raw_symbol` from `symbol_map`"); - let symbol = Symbol { - value: Ustr::from(raw_symbol), - }; + let symbol = Symbol::from_str_unchecked(raw_symbol); let publisher_id = header.publisher_id; let venue = publisher_venue_map @@ -378,10 +375,7 @@ fn handle_instrument_def_msg( ) -> anyhow::Result { let c_str: &CStr = unsafe { CStr::from_ptr(msg.raw_symbol.as_ptr()) }; let raw_symbol: &str = c_str.to_str().map_err(to_pyvalue_err)?; - - let symbol = Symbol { - value: Ustr::from(raw_symbol), - }; + let symbol = Symbol::from(raw_symbol); let publisher_id = msg.header().publisher_id; let venue = publisher_venue_map diff --git a/nautilus_core/adapters/src/databento/loader.rs b/nautilus_core/adapters/src/databento/loader.rs index ffc63c65a338..de0631b9f0c3 100644 --- a/nautilus_core/adapters/src/databento/loader.rs +++ b/nautilus_core/adapters/src/databento/loader.rs @@ -165,7 +165,7 @@ impl DatabentoDataLoader { raw_ptr_to_ustr(rec.raw_symbol.as_ptr()) .expect("Error obtaining `raw_symbol` pointer") }; - let symbol = Symbol { value: raw_symbol }; + let symbol = Symbol::from(raw_symbol); let venue = self .publisher_venue_map diff --git a/nautilus_core/adapters/src/databento/python/historical.rs b/nautilus_core/adapters/src/databento/python/historical.rs index a8d6b576db91..4388c5833e73 100644 --- a/nautilus_core/adapters/src/databento/python/historical.rs +++ b/nautilus_core/adapters/src/databento/python/historical.rs @@ -151,7 +151,7 @@ impl DatabentoHistoricalClient { while let Ok(Some(msg)) = decoder.decode_record::().await { let raw_symbol = unsafe { raw_ptr_to_ustr(msg.raw_symbol.as_ptr()).unwrap() }; - let symbol = Symbol { value: raw_symbol }; + let symbol = Symbol::from(raw_symbol); let publisher = msg.hd.publisher().expect("Invalid `publisher` for record"); let venue = publisher_venue_map diff --git a/nautilus_core/common/src/redis.rs b/nautilus_core/common/src/redis.rs index 19568fc1d460..444fd4ebc2fa 100644 --- a/nautilus_core/common/src/redis.rs +++ b/nautilus_core/common/src/redis.rs @@ -249,7 +249,7 @@ fn get_stream_name( } if let Some(json!(true)) = config.get("use_trader_id") { - stream_name.push_str(trader_id.value.as_str()); + stream_name.push_str(trader_id.as_str()); stream_name.push(DELIMITER); } diff --git a/nautilus_core/common/src/xrate.rs b/nautilus_core/common/src/xrate.rs index f57fa7b88590..e1d45886eb7f 100644 --- a/nautilus_core/common/src/xrate.rs +++ b/nautilus_core/common/src/xrate.rs @@ -77,7 +77,7 @@ pub fn get_exchange_rate( // Build quote table for (symbol, quote) in calculation_quotes.iter() { - let pieces: Vec<&str> = symbol.value.as_str().split('/').collect(); + let pieces: Vec<&str> = symbol.as_str().split('/').collect(); let code_lhs = Ustr::from(pieces[0]); let code_rhs = Ustr::from(pieces[1]); diff --git a/nautilus_core/infrastructure/src/redis.rs b/nautilus_core/infrastructure/src/redis.rs index 94488769363e..0a51def7b26e 100644 --- a/nautilus_core/infrastructure/src/redis.rs +++ b/nautilus_core/infrastructure/src/redis.rs @@ -570,7 +570,7 @@ fn get_trader_key( key.push_str("trader-"); } - key.push_str(trader_id.value.as_str()); + key.push_str(trader_id.as_str()); if let Some(json!(true)) = config.get("use_instance_id") { key.push(DELIMITER); diff --git a/nautilus_core/model/src/ffi/data/quote.rs b/nautilus_core/model/src/ffi/data/quote.rs index df5b705db186..4c09bd62e9d1 100644 --- a/nautilus_core/model/src/ffi/data/quote.rs +++ b/nautilus_core/model/src/ffi/data/quote.rs @@ -61,11 +61,8 @@ pub extern "C" fn quote_tick_eq(lhs: &QuoteTick, rhs: &QuoteTick) -> u8 { assert_eq!(lhs.bid_size, rhs.bid_size); assert_eq!(lhs.ts_event, rhs.ts_event); assert_eq!(lhs.ts_init, rhs.ts_init); - assert_eq!( - lhs.instrument_id.symbol.value, - rhs.instrument_id.symbol.value - ); - assert_eq!(lhs.instrument_id.venue.value, rhs.instrument_id.venue.value); + assert_eq!(lhs.instrument_id.symbol, rhs.instrument_id.symbol); + assert_eq!(lhs.instrument_id.venue, rhs.instrument_id.venue); u8::from(lhs == rhs) } diff --git a/nautilus_core/model/src/ffi/identifiers/account_id.rs b/nautilus_core/model/src/ffi/identifiers/account_id.rs index c1868fce08fd..43a642effeeb 100644 --- a/nautilus_core/model/src/ffi/identifiers/account_id.rs +++ b/nautilus_core/model/src/ffi/identifiers/account_id.rs @@ -31,7 +31,7 @@ pub unsafe extern "C" fn account_id_new(ptr: *const c_char) -> AccountId { #[no_mangle] pub extern "C" fn account_id_hash(id: &AccountId) -> u64 { - id.value.precomputed_hash() + id.inner().precomputed_hash() } //////////////////////////////////////////////////////////////////////////////// @@ -51,7 +51,7 @@ mod tests { let c_string = CString::new(s).unwrap(); let ptr = c_string.as_ptr(); let account_id = unsafe { account_id_new(ptr) }; - let char_ptr = account_id.value.as_char_ptr(); + let char_ptr = account_id.inner().as_char_ptr(); let account_id_2 = unsafe { account_id_new(char_ptr) }; assert_eq!(account_id, account_id_2); } @@ -62,7 +62,7 @@ mod tests { let c_string = CString::new(s).unwrap(); let ptr = c_string.as_ptr(); let account_id = unsafe { account_id_new(ptr) }; - let cstr_ptr = account_id.value.as_char_ptr(); + let cstr_ptr = account_id.inner().as_char_ptr(); let c_str = unsafe { CStr::from_ptr(cstr_ptr) }; assert_eq!(c_str.to_str().unwrap(), s); } diff --git a/nautilus_core/model/src/ffi/identifiers/client_id.rs b/nautilus_core/model/src/ffi/identifiers/client_id.rs index 3d797e02b7db..6eba2857bc71 100644 --- a/nautilus_core/model/src/ffi/identifiers/client_id.rs +++ b/nautilus_core/model/src/ffi/identifiers/client_id.rs @@ -31,7 +31,7 @@ pub unsafe extern "C" fn client_id_new(ptr: *const c_char) -> ClientId { #[no_mangle] pub extern "C" fn client_id_hash(id: &ClientId) -> u64 { - id.value.precomputed_hash() + id.inner().precomputed_hash() } //////////////////////////////////////////////////////////////////////////////// @@ -49,7 +49,7 @@ mod tests { #[rstest] fn test_client_id_to_cstr_c() { let id = ClientId::from("BINANCE"); - let c_string = id.value.as_char_ptr(); + let c_string = id.inner().as_char_ptr(); let rust_string = unsafe { CStr::from_ptr(c_string) }.to_str().unwrap(); assert_eq!(rust_string, "BINANCE"); } diff --git a/nautilus_core/model/src/ffi/identifiers/client_order_id.rs b/nautilus_core/model/src/ffi/identifiers/client_order_id.rs index 325e3396d39a..d55dc538bba5 100644 --- a/nautilus_core/model/src/ffi/identifiers/client_order_id.rs +++ b/nautilus_core/model/src/ffi/identifiers/client_order_id.rs @@ -31,5 +31,5 @@ pub unsafe extern "C" fn client_order_id_new(ptr: *const c_char) -> ClientOrderI #[no_mangle] pub extern "C" fn client_order_id_hash(id: &ClientOrderId) -> u64 { - id.value.precomputed_hash() + id.inner().precomputed_hash() } diff --git a/nautilus_core/model/src/ffi/identifiers/component_id.rs b/nautilus_core/model/src/ffi/identifiers/component_id.rs index efa696daf088..ec45f1b18b85 100644 --- a/nautilus_core/model/src/ffi/identifiers/component_id.rs +++ b/nautilus_core/model/src/ffi/identifiers/component_id.rs @@ -31,5 +31,5 @@ pub unsafe extern "C" fn component_id_new(ptr: *const c_char) -> ComponentId { #[no_mangle] pub extern "C" fn component_id_hash(id: &ComponentId) -> u64 { - id.value.precomputed_hash() + id.inner().precomputed_hash() } diff --git a/nautilus_core/model/src/ffi/identifiers/exec_algorithm_id.rs b/nautilus_core/model/src/ffi/identifiers/exec_algorithm_id.rs index a031f0a80c0d..b622b7b0bc98 100644 --- a/nautilus_core/model/src/ffi/identifiers/exec_algorithm_id.rs +++ b/nautilus_core/model/src/ffi/identifiers/exec_algorithm_id.rs @@ -31,5 +31,5 @@ pub unsafe extern "C" fn exec_algorithm_id_new(ptr: *const c_char) -> ExecAlgori #[no_mangle] pub extern "C" fn exec_algorithm_id_hash(id: &ExecAlgorithmId) -> u64 { - id.value.precomputed_hash() + id.inner().precomputed_hash() } diff --git a/nautilus_core/model/src/ffi/identifiers/order_list_id.rs b/nautilus_core/model/src/ffi/identifiers/order_list_id.rs index 0f74753e1f4c..ebc0f68146e3 100644 --- a/nautilus_core/model/src/ffi/identifiers/order_list_id.rs +++ b/nautilus_core/model/src/ffi/identifiers/order_list_id.rs @@ -31,5 +31,5 @@ pub unsafe extern "C" fn order_list_id_new(ptr: *const c_char) -> OrderListId { #[no_mangle] pub extern "C" fn order_list_id_hash(id: &OrderListId) -> u64 { - id.value.precomputed_hash() + id.inner().precomputed_hash() } diff --git a/nautilus_core/model/src/ffi/identifiers/position_id.rs b/nautilus_core/model/src/ffi/identifiers/position_id.rs index c68425c56b74..b7e39b942945 100644 --- a/nautilus_core/model/src/ffi/identifiers/position_id.rs +++ b/nautilus_core/model/src/ffi/identifiers/position_id.rs @@ -31,5 +31,5 @@ pub unsafe extern "C" fn position_id_new(ptr: *const c_char) -> PositionId { #[no_mangle] pub extern "C" fn position_id_hash(id: &PositionId) -> u64 { - id.value.precomputed_hash() + id.inner().precomputed_hash() } diff --git a/nautilus_core/model/src/ffi/identifiers/strategy_id.rs b/nautilus_core/model/src/ffi/identifiers/strategy_id.rs index 8fc42eb56542..fe980c405ac2 100644 --- a/nautilus_core/model/src/ffi/identifiers/strategy_id.rs +++ b/nautilus_core/model/src/ffi/identifiers/strategy_id.rs @@ -31,5 +31,5 @@ pub unsafe extern "C" fn strategy_id_new(ptr: *const c_char) -> StrategyId { #[no_mangle] pub extern "C" fn strategy_id_hash(id: &StrategyId) -> u64 { - id.value.precomputed_hash() + id.inner().precomputed_hash() } diff --git a/nautilus_core/model/src/ffi/identifiers/symbol.rs b/nautilus_core/model/src/ffi/identifiers/symbol.rs index dee1c443cb29..0b1eb1b87b39 100644 --- a/nautilus_core/model/src/ffi/identifiers/symbol.rs +++ b/nautilus_core/model/src/ffi/identifiers/symbol.rs @@ -31,5 +31,5 @@ pub unsafe extern "C" fn symbol_new(ptr: *const c_char) -> Symbol { #[no_mangle] pub extern "C" fn symbol_hash(id: &Symbol) -> u64 { - id.value.precomputed_hash() + id.inner().precomputed_hash() } diff --git a/nautilus_core/model/src/ffi/identifiers/trader_id.rs b/nautilus_core/model/src/ffi/identifiers/trader_id.rs index b1bfd540acd8..bf076cb17baf 100644 --- a/nautilus_core/model/src/ffi/identifiers/trader_id.rs +++ b/nautilus_core/model/src/ffi/identifiers/trader_id.rs @@ -31,5 +31,5 @@ pub unsafe extern "C" fn trader_id_new(ptr: *const c_char) -> TraderId { #[no_mangle] pub extern "C" fn trader_id_hash(id: &TraderId) -> u64 { - id.value.precomputed_hash() + id.inner().precomputed_hash() } diff --git a/nautilus_core/model/src/ffi/identifiers/venue.rs b/nautilus_core/model/src/ffi/identifiers/venue.rs index 7dc2c66fd7d2..a6763d6030d3 100644 --- a/nautilus_core/model/src/ffi/identifiers/venue.rs +++ b/nautilus_core/model/src/ffi/identifiers/venue.rs @@ -31,7 +31,7 @@ pub unsafe extern "C" fn venue_new(ptr: *const c_char) -> Venue { #[no_mangle] pub extern "C" fn venue_hash(id: &Venue) -> u64 { - id.value.precomputed_hash() + id.inner().precomputed_hash() } #[no_mangle] diff --git a/nautilus_core/model/src/ffi/identifiers/venue_order_id.rs b/nautilus_core/model/src/ffi/identifiers/venue_order_id.rs index e9f0d4aa8a44..2d300716c9c6 100644 --- a/nautilus_core/model/src/ffi/identifiers/venue_order_id.rs +++ b/nautilus_core/model/src/ffi/identifiers/venue_order_id.rs @@ -31,5 +31,5 @@ pub unsafe extern "C" fn venue_order_id_new(ptr: *const c_char) -> VenueOrderId #[no_mangle] pub extern "C" fn venue_order_id_hash(id: &VenueOrderId) -> u64 { - id.value.precomputed_hash() + id.inner().precomputed_hash() } diff --git a/nautilus_core/model/src/identifiers/account_id.rs b/nautilus_core/model/src/identifiers/account_id.rs index b4bb1634d4b5..dd9a3f1ef125 100644 --- a/nautilus_core/model/src/identifiers/account_id.rs +++ b/nautilus_core/model/src/identifiers/account_id.rs @@ -34,39 +34,55 @@ use ustr::Ustr; feature = "python", pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model") )] -pub struct AccountId { - /// The account ID value. - pub value: Ustr, -} +pub struct AccountId(Ustr); impl AccountId { + /// Creates a new `AccountId` from the given identifier value. + /// + /// # Panics + /// + /// Panics if the value is not a valid string, or does not contain a hyphen '-' separator. pub fn new(value: &str) -> anyhow::Result { check_valid_string(value, stringify!(value))?; check_string_contains(value, "-", stringify!(value))?; - Ok(Self { - value: Ustr::from(value), - }) + Ok(Self(Ustr::from(value))) + } + + /// Sets the inner identifier value. + pub(crate) fn set_inner(&mut self, value: &str) { + self.0 = Ustr::from(value); + } + + /// Returns the inner identifier value. + #[must_use] + pub fn inner(&self) -> Ustr { + self.0 + } + + /// Returns the inner identifier value as a string slice. + #[must_use] + pub fn as_str(&self) -> &str { + self.0.as_str() } } impl Default for AccountId { fn default() -> Self { - Self { - value: Ustr::from("SIM-001"), - } + // SAFETY: Default value is safe + Self::new("SIM-001").unwrap() } } impl Debug for AccountId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.value) + write!(f, "{:?}", self.0) } } impl Display for AccountId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.value) + write!(f, "{}", self.0) } } @@ -110,6 +126,6 @@ mod tests { #[rstest] fn test_string_reprs(account_ib: AccountId) { - assert_eq!(account_ib.to_string(), "IB-1234567890"); + assert_eq!(account_ib.as_str(), "IB-1234567890"); } } diff --git a/nautilus_core/model/src/identifiers/client_id.rs b/nautilus_core/model/src/identifiers/client_id.rs index d943c5259250..e0f2b32c2228 100644 --- a/nautilus_core/model/src/identifiers/client_id.rs +++ b/nautilus_core/model/src/identifiers/client_id.rs @@ -28,38 +28,54 @@ use ustr::Ustr; feature = "python", pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model") )] -pub struct ClientId { - /// The client ID value. - pub value: Ustr, -} +pub struct ClientId(Ustr); impl ClientId { + /// Creates a new `ClientId` from the given identifier value. + /// + /// # Panics + /// + /// Panics if the value is not a valid string. pub fn new(value: &str) -> anyhow::Result { check_valid_string(value, stringify!(value))?; - Ok(Self { - value: Ustr::from(value), - }) + Ok(Self(Ustr::from(value))) + } + + /// Sets the inner identifier value. + pub(crate) fn set_inner(&mut self, value: &str) { + self.0 = Ustr::from(value); + } + + /// Returns the inner identifier value. + #[must_use] + pub fn inner(&self) -> Ustr { + self.0 + } + + /// Returns the inner identifier value as a string slice. + #[must_use] + pub fn as_str(&self) -> &str { + self.0.as_str() } } impl Default for ClientId { fn default() -> Self { - Self { - value: Ustr::from("SIM"), - } + // SAFETY: Default value is safe + Self::new("SIM").unwrap() } } impl Debug for ClientId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.value) + write!(f, "{:?}", self.0) } } impl Display for ClientId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.value) + write!(f, "{}", self.0) } } @@ -81,7 +97,7 @@ mod tests { #[rstest] fn test_string_reprs(client_id_binance: ClientId) { - assert_eq!(client_id_binance.to_string(), "BINANCE"); + assert_eq!(client_id_binance.as_str(), "BINANCE"); assert_eq!(format!("{client_id_binance}"), "BINANCE"); } } diff --git a/nautilus_core/model/src/identifiers/client_order_id.rs b/nautilus_core/model/src/identifiers/client_order_id.rs index 3bbb7dfd79fe..3a72fa4ae754 100644 --- a/nautilus_core/model/src/identifiers/client_order_id.rs +++ b/nautilus_core/model/src/identifiers/client_order_id.rs @@ -28,38 +28,52 @@ use ustr::Ustr; feature = "python", pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model") )] -pub struct ClientOrderId { - /// The client order ID value. - pub value: Ustr, -} +pub struct ClientOrderId(Ustr); impl ClientOrderId { + /// Creates a new `ClientOrderId` from the given identifier value. + /// + /// # Panics + /// + /// Panics if the value is not a valid string. pub fn new(value: &str) -> anyhow::Result { check_valid_string(value, stringify!(value))?; - Ok(Self { - value: Ustr::from(value), - }) + Ok(Self(Ustr::from(value))) + } + + /// Sets the inner identifier value. + pub(crate) fn set_inner(&mut self, value: &str) { + self.0 = Ustr::from(value); + } + + /// Returns the inner identifier value. + pub fn inner(&self) -> Ustr { + self.0 + } + + /// Returns the inner identifier value as a string slice. + pub fn as_str(&self) -> &str { + self.0.as_str() } } impl Default for ClientOrderId { fn default() -> Self { - Self { - value: Ustr::from("O-123456789"), - } + // SAFETY: Default value is safe + Self::new("O-123456789").unwrap() } } impl Debug for ClientOrderId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.value) + write!(f, "{:?}", self.0) } } impl Display for ClientOrderId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.value) + write!(f, "{}", self.0) } } @@ -79,7 +93,7 @@ pub fn optional_vec_client_order_ids_to_ustr(vec: Option>) -> vec.map(|client_order_ids| { let s: String = client_order_ids .into_iter() - .map(|id| id.value.to_string()) + .map(|id| id.to_string()) .collect::>() .join(","); Ustr::from(&s) @@ -110,7 +124,7 @@ mod tests { #[rstest] fn test_string_reprs(client_order_id: ClientOrderId) { - assert_eq!(client_order_id.to_string(), "O-20200814-102234-001-001-1"); + assert_eq!(client_order_id.as_str(), "O-20200814-102234-001-001-1"); assert_eq!(format!("{client_order_id}"), "O-20200814-102234-001-001-1"); } @@ -122,9 +136,9 @@ mod tests { // Test with Some let ustr = Ustr::from("id1,id2,id3"); let client_order_ids = optional_ustr_to_vec_client_order_ids(Some(ustr)).unwrap(); - assert_eq!(client_order_ids[0].value.to_string(), "id1"); - assert_eq!(client_order_ids[1].value.to_string(), "id2"); - assert_eq!(client_order_ids[2].value.to_string(), "id3"); + assert_eq!(client_order_ids[0].as_str(), "id1"); + assert_eq!(client_order_ids[1].as_str(), "id2"); + assert_eq!(client_order_ids[2].as_str(), "id3"); } #[rstest] diff --git a/nautilus_core/model/src/identifiers/component_id.rs b/nautilus_core/model/src/identifiers/component_id.rs index 0b607f7fae1f..e15b7ade4847 100644 --- a/nautilus_core/model/src/identifiers/component_id.rs +++ b/nautilus_core/model/src/identifiers/component_id.rs @@ -28,30 +28,47 @@ use ustr::Ustr; feature = "python", pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model") )] -pub struct ComponentId { - /// The component ID value. - pub value: Ustr, -} +pub struct ComponentId(Ustr); impl ComponentId { + /// Creates a new `ComponentId` from the given identifier value. + /// + /// # Panics + /// + /// Panics if the value is not a valid string. pub fn new(value: &str) -> anyhow::Result { check_valid_string(value, stringify!(value))?; - Ok(Self { - value: Ustr::from(value), - }) + Ok(Self(Ustr::from(value))) + } + + /// Sets the inner identifier value. + pub(crate) fn set_inner(&mut self, value: &str) { + self.0 = Ustr::from(value); + } + + /// Returns the inner identifier value. + #[must_use] + pub fn inner(&self) -> Ustr { + self.0 + } + + /// Returns the inner identifier value as a string slice. + #[must_use] + pub fn as_str(&self) -> &str { + self.0.as_str() } } impl Debug for ComponentId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.value) + write!(f, "{:?}", self.0) } } impl Display for ComponentId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.value) + write!(f, "{}", self.0) } } @@ -73,7 +90,7 @@ mod tests { #[rstest] fn test_string_reprs(component_risk_engine: ComponentId) { - assert_eq!(component_risk_engine.to_string(), "RiskEngine"); + assert_eq!(component_risk_engine.as_str(), "RiskEngine"); assert_eq!(format!("{component_risk_engine}"), "RiskEngine"); } } diff --git a/nautilus_core/model/src/identifiers/exec_algorithm_id.rs b/nautilus_core/model/src/identifiers/exec_algorithm_id.rs index 7cb4d9f967d0..7df77ca52221 100644 --- a/nautilus_core/model/src/identifiers/exec_algorithm_id.rs +++ b/nautilus_core/model/src/identifiers/exec_algorithm_id.rs @@ -28,30 +28,47 @@ use ustr::Ustr; feature = "python", pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model") )] -pub struct ExecAlgorithmId { - /// The execution algorithm ID value. - pub value: Ustr, -} +pub struct ExecAlgorithmId(Ustr); impl ExecAlgorithmId { + /// Creates a new `ExecAlgorithmId` from the given identifier value. + /// + /// # Panics + /// + /// Panics if the value is not a valid string. pub fn new(value: &str) -> anyhow::Result { check_valid_string(value, stringify!(value))?; - Ok(Self { - value: Ustr::from(value), - }) + Ok(Self(Ustr::from(value))) + } + + /// Sets the inner identifier value. + pub(crate) fn set_inner(&mut self, value: &str) { + self.0 = Ustr::from(value); + } + + /// Returns the inner identifier value. + #[must_use] + pub fn inner(&self) -> Ustr { + self.0 + } + + /// Returns the inner identifier value as a string slice. + #[must_use] + pub fn as_str(&self) -> &str { + self.0.as_str() } } impl Debug for ExecAlgorithmId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.value) + write!(f, "{:?}", self.0) } } impl Display for ExecAlgorithmId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.value) + write!(f, "{}", self.0) } } @@ -73,7 +90,7 @@ mod tests { #[rstest] fn test_string_reprs(exec_algorithm_id: ExecAlgorithmId) { - assert_eq!(exec_algorithm_id.to_string(), "001"); + assert_eq!(exec_algorithm_id.as_str(), "001"); assert_eq!(format!("{exec_algorithm_id}"), "001"); } } diff --git a/nautilus_core/model/src/identifiers/instrument_id.rs b/nautilus_core/model/src/identifiers/instrument_id.rs index ef154a93310a..e865e336462a 100644 --- a/nautilus_core/model/src/identifiers/instrument_id.rs +++ b/nautilus_core/model/src/identifiers/instrument_id.rs @@ -40,6 +40,7 @@ pub struct InstrumentId { } impl InstrumentId { + /// Creates a new `InstrumentId` from the given `Symbol` and `Venue`. #[must_use] pub fn new(symbol: Symbol, venue: Venue) -> Self { Self { symbol, venue } diff --git a/nautilus_core/model/src/identifiers/macros.rs b/nautilus_core/model/src/identifiers/macros.rs index 827b73e3110c..9b9194d15a76 100644 --- a/nautilus_core/model/src/identifiers/macros.rs +++ b/nautilus_core/model/src/identifiers/macros.rs @@ -20,7 +20,7 @@ macro_rules! impl_serialization_for_identifier { where S: Serializer, { - self.value.serialize(serializer) + self.inner().serialize(serializer) } } diff --git a/nautilus_core/model/src/identifiers/order_list_id.rs b/nautilus_core/model/src/identifiers/order_list_id.rs index 6165204f5197..05d14d8bcf2e 100644 --- a/nautilus_core/model/src/identifiers/order_list_id.rs +++ b/nautilus_core/model/src/identifiers/order_list_id.rs @@ -28,30 +28,47 @@ use ustr::Ustr; feature = "python", pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model") )] -pub struct OrderListId { - /// The order list ID value. - pub value: Ustr, -} +pub struct OrderListId(Ustr); impl OrderListId { + /// Creates a new `OrderListId` from the given identifier value. + /// + /// # Panics + /// + /// Panics if the value is not a valid string. pub fn new(value: &str) -> anyhow::Result { check_valid_string(value, stringify!(value))?; - Ok(Self { - value: Ustr::from(value), - }) + Ok(Self(Ustr::from(value))) + } + + /// Sets the inner identifier value. + pub(crate) fn set_inner(&mut self, value: &str) { + self.0 = Ustr::from(value); + } + + /// Returns the inner identifier value. + #[must_use] + pub fn inner(&self) -> Ustr { + self.0 + } + + /// Returns the inner identifier value as a string slice. + #[must_use] + pub fn as_str(&self) -> &str { + self.0.as_str() } } impl Debug for OrderListId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.value) + write!(f, "{:?}", self.0) } } impl Display for OrderListId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.value) + write!(f, "{}", self.0) } } @@ -73,7 +90,7 @@ mod tests { #[rstest] fn test_string_reprs(order_list_id_test: OrderListId) { - assert_eq!(order_list_id_test.to_string(), "001"); + assert_eq!(order_list_id_test.as_str(), "001"); assert_eq!(format!("{order_list_id_test}"), "001"); } } diff --git a/nautilus_core/model/src/identifiers/position_id.rs b/nautilus_core/model/src/identifiers/position_id.rs index 954ac04a2cf3..fb95867fc40d 100644 --- a/nautilus_core/model/src/identifiers/position_id.rs +++ b/nautilus_core/model/src/identifiers/position_id.rs @@ -28,37 +28,53 @@ use ustr::Ustr; feature = "python", pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model") )] -pub struct PositionId { - /// The position ID value. - pub value: Ustr, -} +pub struct PositionId(Ustr); impl PositionId { + /// Creates a new `PositionId` from the given identifier value. + /// + /// # Panics + /// + /// Panics if the value is not a valid string. pub fn new(value: &str) -> anyhow::Result { check_valid_string(value, stringify!(value))?; - Ok(Self { - value: Ustr::from(value), - }) + Ok(Self(Ustr::from(value))) + } + + /// Sets the inner identifier value. + pub(crate) fn set_inner(&mut self, value: &str) { + self.0 = Ustr::from(value); + } + + /// Returns the inner identifier value. + #[must_use] + pub fn inner(&self) -> Ustr { + self.0 + } + + /// Returns the inner identifier value as a string slice. + #[must_use] + pub fn as_str(&self) -> &str { + self.0.as_str() } } impl Default for PositionId { fn default() -> Self { - Self { - value: Ustr::from("P-001"), - } + // SAFETY: Default value is safe + Self::new("P-001").unwrap() } } impl Debug for PositionId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.value) + write!(f, "{:?}", self.0) } } impl Display for PositionId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.value) + write!(f, "{}", self.0) } } @@ -80,7 +96,7 @@ mod tests { #[rstest] fn test_string_reprs(position_id_test: PositionId) { - assert_eq!(position_id_test.to_string(), "P-123456789"); + assert_eq!(position_id_test.as_str(), "P-123456789"); assert_eq!(format!("{position_id_test}"), "P-123456789"); } } diff --git a/nautilus_core/model/src/identifiers/strategy_id.rs b/nautilus_core/model/src/identifiers/strategy_id.rs index ee218db4503d..15803b87f664 100644 --- a/nautilus_core/model/src/identifiers/strategy_id.rs +++ b/nautilus_core/model/src/identifiers/strategy_id.rs @@ -37,59 +37,74 @@ const EXTERNAL_STRATEGY_ID: &str = "EXTERNAL"; feature = "python", pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model") )] -pub struct StrategyId { - /// The strategy ID value. - pub value: Ustr, -} +pub struct StrategyId(Ustr); impl StrategyId { + /// Creates a new `StrategyId` from the given identifier value. + /// + /// # Panics + /// + /// Panics if the value is not a valid string, or does not contain a hyphen '-' separator. pub fn new(value: &str) -> anyhow::Result { check_valid_string(value, stringify!(value))?; if value != EXTERNAL_STRATEGY_ID { check_string_contains(value, "-", stringify!(value))?; } - Ok(Self { - value: Ustr::from(value), - }) + Ok(Self(Ustr::from(value))) + } + + /// Sets the inner identifier value. + pub(crate) fn set_inner(&mut self, value: &str) { + self.0 = Ustr::from(value); + } + + /// Returns the inner identifier value. + #[must_use] + pub fn inner(&self) -> Ustr { + self.0 + } + + /// Returns the inner identifier value as a string slice. + #[must_use] + pub fn as_str(&self) -> &str { + self.0.as_str() } #[must_use] pub fn external() -> Self { - Self { - value: Ustr::from(EXTERNAL_STRATEGY_ID), - } + // SAFETY:: Constant value is safe + Self::new(EXTERNAL_STRATEGY_ID).unwrap() } #[must_use] pub fn is_external(&self) -> bool { - self.value == EXTERNAL_STRATEGY_ID + self.0 == EXTERNAL_STRATEGY_ID } #[must_use] pub fn get_tag(&self) -> &str { // SAFETY: Unwrap safe as value previously validated - self.value.split('-').last().unwrap() + self.0.split('-').last().unwrap() } } impl Default for StrategyId { fn default() -> Self { - Self { - value: Ustr::from("S-001"), - } + // SAFETY: Default value is safe + Self::new("S-001").unwrap() } } impl Debug for StrategyId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.value) + write!(f, "{:?}", self.0) } } impl Display for StrategyId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.value) + write!(f, "{}", self.0) } } @@ -111,13 +126,13 @@ mod tests { #[rstest] fn test_string_reprs(strategy_id_ema_cross: StrategyId) { - assert_eq!(strategy_id_ema_cross.to_string(), "EMACross-001"); + assert_eq!(strategy_id_ema_cross.as_str(), "EMACross-001"); assert_eq!(format!("{strategy_id_ema_cross}"), "EMACross-001"); } #[rstest] fn test_get_external() { - assert_eq!(StrategyId::external().value, "EXTERNAL"); + assert_eq!(StrategyId::external().as_str(), "EXTERNAL"); } #[rstest] diff --git a/nautilus_core/model/src/identifiers/symbol.rs b/nautilus_core/model/src/identifiers/symbol.rs index 62118daf5419..6724734b798c 100644 --- a/nautilus_core/model/src/identifiers/symbol.rs +++ b/nautilus_core/model/src/identifiers/symbol.rs @@ -28,45 +28,65 @@ use ustr::Ustr; feature = "python", pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model") )] -pub struct Symbol { - /// The ticker symbol ID value. - pub value: Ustr, -} +pub struct Symbol(Ustr); impl Symbol { + /// Creates a new `Symbol` from the given identifier value. + /// + /// # Panics + /// + /// Panics if the value is not a valid string. pub fn new(value: &str) -> anyhow::Result { check_valid_string(value, stringify!(value))?; - Ok(Self { - value: Ustr::from(value), - }) + Ok(Self(Ustr::from(value))) + } + + /// Sets the inner identifier value. + pub(crate) fn set_inner(&mut self, value: &str) { + self.0 = Ustr::from(value); } #[must_use] pub fn from_str_unchecked(s: &str) -> Self { - Self { - value: Ustr::from(s), - } + Self(Ustr::from(s)) + } + + /// Returns the inner identifier value. + #[must_use] + pub fn inner(&self) -> Ustr { + self.0 + } + + /// Returns the inner identifier value as a string slice. + #[must_use] + pub fn as_str(&self) -> &str { + self.0.as_str() } } impl Default for Symbol { fn default() -> Self { - Self { - value: Ustr::from("AUD/USD"), - } + // SAFETY: Default value is safe + Self::new("AUD/USD").unwrap() } } impl Debug for Symbol { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.value) + write!(f, "{:?}", self.0) } } impl Display for Symbol { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.value) + write!(f, "{}", self.0) + } +} + +impl From for Symbol { + fn from(input: Ustr) -> Self { + Self(input) } } @@ -87,7 +107,7 @@ mod tests { #[rstest] fn test_string_reprs(symbol_eth_perp: Symbol) { - assert_eq!(symbol_eth_perp.to_string(), "ETH-PERP"); + assert_eq!(symbol_eth_perp.as_str(), "ETH-PERP"); assert_eq!(format!("{symbol_eth_perp}"), "ETH-PERP"); } } diff --git a/nautilus_core/model/src/identifiers/trade_id.rs b/nautilus_core/model/src/identifiers/trade_id.rs index 797d3cf48169..8d22e1d453c6 100644 --- a/nautilus_core/model/src/identifiers/trade_id.rs +++ b/nautilus_core/model/src/identifiers/trade_id.rs @@ -45,6 +45,11 @@ pub struct TradeId { } impl TradeId { + /// Creates a new `TradeId` from the given identifier value. + /// + /// # Panics + /// + /// Panics if the value is not a valid string, or value length is greater than 36. pub fn new(value: &str) -> anyhow::Result { let cstr = CString::new(value).expect("`CString` conversion failed"); Self::from_cstr(cstr) diff --git a/nautilus_core/model/src/identifiers/trader_id.rs b/nautilus_core/model/src/identifiers/trader_id.rs index d71bfb1af5e1..9a4c8fb1f61b 100644 --- a/nautilus_core/model/src/identifiers/trader_id.rs +++ b/nautilus_core/model/src/identifiers/trader_id.rs @@ -34,45 +34,61 @@ use ustr::Ustr; feature = "python", pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model") )] -pub struct TraderId { - /// The trader ID value. - pub value: Ustr, -} +pub struct TraderId(Ustr); impl TraderId { + /// Creates a new `TraderId` from the given identifier value. + /// + /// # Panics + /// + /// Panics if the value is not a valid string, or does not contain a hyphen '-' separator. pub fn new(value: &str) -> anyhow::Result { check_valid_string(value, stringify!(value))?; check_string_contains(value, "-", stringify!(value))?; - Ok(Self { - value: Ustr::from(value), - }) + Ok(Self(Ustr::from(value))) + } + + /// Sets the inner identifier value. + pub(crate) fn set_inner(&mut self, value: &str) { + self.0 = Ustr::from(value); + } + + /// Returns the inner identifier value. + #[must_use] + pub fn inner(&self) -> Ustr { + self.0 + } + + /// Returns the inner identifier value as a string slice. + #[must_use] + pub fn as_str(&self) -> &str { + self.0.as_str() } #[must_use] pub fn get_tag(&self) -> &str { // SAFETY: Unwrap safe as value previously validated - self.value.split('-').last().unwrap() + self.0.split('-').last().unwrap() } } impl Default for TraderId { fn default() -> Self { - Self { - value: Ustr::from("TRADER-000"), - } + // SAFETY: Default value is safe + Self(Ustr::from("TRADER-000")) } } impl Debug for TraderId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.value) + write!(f, "{:?}", self.0) } } impl Display for TraderId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.value) + write!(f, "{}", self.0) } } @@ -93,7 +109,7 @@ mod tests { #[rstest] fn test_string_reprs(trader_id: TraderId) { - assert_eq!(trader_id.to_string(), "TRADER-001"); + assert_eq!(trader_id.as_str(), "TRADER-001"); assert_eq!(format!("{trader_id}"), "TRADER-001"); } diff --git a/nautilus_core/model/src/identifiers/venue.rs b/nautilus_core/model/src/identifiers/venue.rs index 544aa98bd816..7a635dd80667 100644 --- a/nautilus_core/model/src/identifiers/venue.rs +++ b/nautilus_core/model/src/identifiers/venue.rs @@ -32,25 +32,40 @@ pub const SYNTHETIC_VENUE: &str = "SYNTH"; feature = "python", pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model") )] -pub struct Venue { - /// The venue ID value. - pub value: Ustr, -} +pub struct Venue(Ustr); impl Venue { + /// Creates a new `Venue` from the given identifier value. + /// + /// # Panics + /// + /// Panics if the value is not a valid string. pub fn new(value: &str) -> anyhow::Result { check_valid_string(value, stringify!(value))?; - Ok(Self { - value: Ustr::from(value), - }) + Ok(Self(Ustr::from(value))) + } + + /// Sets the inner identifier value. + pub(crate) fn set_inner(&mut self, value: &str) { + self.0 = Ustr::from(value); + } + + /// Returns the inner identifier value. + #[must_use] + pub fn inner(&self) -> Ustr { + self.0 + } + + /// Returns the inner value as a string slice. + #[must_use] + pub fn as_str(&self) -> &str { + self.0.as_str() } #[must_use] pub fn from_str_unchecked(s: &str) -> Self { - Self { - value: Ustr::from(s), - } + Self(Ustr::from(s)) } pub fn from_code(code: &str) -> anyhow::Result { @@ -71,27 +86,26 @@ impl Venue { #[must_use] pub fn is_synthetic(&self) -> bool { - self.value.as_str() == SYNTHETIC_VENUE + self.0.as_str() == SYNTHETIC_VENUE } } impl Default for Venue { fn default() -> Self { - Self { - value: Ustr::from("SIM"), - } + // SAFETY: Default value is safe + Self::new("SIM").unwrap() } } impl Debug for Venue { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.value) + write!(f, "{:?}", self.0) } } impl Display for Venue { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.value) + write!(f, "{}", self.0) } } @@ -112,7 +126,7 @@ mod tests { #[rstest] fn test_string_reprs(venue_binance: Venue) { - assert_eq!(venue_binance.to_string(), "BINANCE"); + assert_eq!(venue_binance.as_str(), "BINANCE"); assert_eq!(format!("{venue_binance}"), "BINANCE"); } } diff --git a/nautilus_core/model/src/identifiers/venue_order_id.rs b/nautilus_core/model/src/identifiers/venue_order_id.rs index e347fdb89b07..f36fdd60b38b 100644 --- a/nautilus_core/model/src/identifiers/venue_order_id.rs +++ b/nautilus_core/model/src/identifiers/venue_order_id.rs @@ -28,38 +28,54 @@ use ustr::Ustr; feature = "python", pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model") )] -pub struct VenueOrderId { - /// The venue assigned order ID value. - pub value: Ustr, -} +pub struct VenueOrderId(Ustr); impl VenueOrderId { + /// Creates a new `VenueOrderId` from the given identifier value. + /// + /// # Panics + /// + /// Panics if the value is not a valid string. pub fn new(value: &str) -> anyhow::Result { check_valid_string(value, stringify!(value))?; - Ok(Self { - value: Ustr::from(value), - }) + Ok(Self(Ustr::from(value))) + } + + /// Sets the inner identifier value. + pub(crate) fn set_inner(&mut self, value: &str) { + self.0 = Ustr::from(value); + } + + /// Returns the inner identifier value. + #[must_use] + pub fn inner(&self) -> Ustr { + self.0 + } + + /// Returns the inner identifier value as a string slice. + #[must_use] + pub fn as_str(&self) -> &str { + self.0.as_str() } } impl Default for VenueOrderId { fn default() -> Self { - Self { - value: Ustr::from("001"), - } + // SAFETY: Default value is safe + Self::new("001").unwrap() } } impl Debug for VenueOrderId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.value) + write!(f, "{:?}", self.0) } } impl Display for VenueOrderId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.value) + write!(f, "{}", self.0) } } @@ -80,7 +96,7 @@ mod tests { #[rstest] fn test_string_reprs(venue_order_id: VenueOrderId) { - assert_eq!(venue_order_id.to_string(), "001"); + assert_eq!(venue_order_id.as_str(), "001"); assert_eq!(format!("{venue_order_id}"), "001"); } } diff --git a/nautilus_core/model/src/instruments/stubs.rs b/nautilus_core/model/src/instruments/stubs.rs index f7f2207976cd..acd64aa6ac32 100644 --- a/nautilus_core/model/src/instruments/stubs.rs +++ b/nautilus_core/model/src/instruments/stubs.rs @@ -227,8 +227,8 @@ pub fn currency_pair_ethusdt() -> CurrencyPair { pub fn default_fx_ccy(symbol: Symbol, venue: Option) -> CurrencyPair { let target_venue = venue.unwrap_or(Venue::from("SIM")); let instrument_id = InstrumentId::new(symbol, target_venue); - let base_currency = symbol.value.split('/').next().unwrap(); - let quote_currency = symbol.value.split('/').last().unwrap(); + let base_currency = symbol.as_str().split('/').next().unwrap(); + let quote_currency = symbol.as_str().split('/').last().unwrap(); let price_precision = if quote_currency == "JPY" { 3 } else { 5 }; let price_increment = Price::new(1.0 / 10.0f64, price_precision).unwrap(); CurrencyPair::new( diff --git a/nautilus_core/model/src/orders/stubs.rs b/nautilus_core/model/src/orders/stubs.rs index 48f78ce86274..07f2bbe31f30 100644 --- a/nautilus_core/model/src/orders/stubs.rs +++ b/nautilus_core/model/src/orders/stubs.rs @@ -62,7 +62,7 @@ impl TestOrderEventStubs { .account_id() .unwrap_or(AccountId::new("SIM-001").unwrap()); let trade_id = trade_id.unwrap_or( - TradeId::new(order.client_order_id().value.replace('O', "E").as_str()).unwrap(), + TradeId::new(order.client_order_id().as_str().replace('O', "E").as_str()).unwrap(), ); let liquidity_side = order.liquidity_side().unwrap_or(LiquiditySide::Maker); let event = UUID4::new(); diff --git a/nautilus_core/model/src/python/identifiers/mod.rs b/nautilus_core/model/src/python/identifiers/mod.rs index df98f4c032f0..2027ca542773 100644 --- a/nautilus_core/model/src/python/identifiers/mod.rs +++ b/nautilus_core/model/src/python/identifiers/mod.rs @@ -21,7 +21,6 @@ use pyo3::{ pyclass::CompareOp, types::{PyString, PyTuple}, }; -use ustr::Ustr; use crate::identifier_for_python; diff --git a/nautilus_core/model/src/python/macros.rs b/nautilus_core/model/src/python/macros.rs index be32abc1b555..104079322bd6 100644 --- a/nautilus_core/model/src/python/macros.rs +++ b/nautilus_core/model/src/python/macros.rs @@ -28,13 +28,13 @@ macro_rules! identifier_for_python { fn __setstate__(&mut self, py: Python, state: PyObject) -> PyResult<()> { let value: (&PyString,) = state.extract(py)?; - let value_str: String = value.0.extract()?; - self.value = Ustr::from_str(&value_str).map_err(to_pyvalue_err)?; + let value: &str = value.0.extract()?; + self.set_inner(value); Ok(()) } fn __getstate__(&self, py: Python) -> PyResult { - Ok((self.value.to_string(),).to_object(py)) + Ok((self.to_string(),).to_object(py)) } fn __reduce__(&self, py: Python) -> PyResult { @@ -60,25 +60,25 @@ macro_rules! identifier_for_python { } fn __hash__(&self) -> isize { - self.value.precomputed_hash() as isize + self.inner().precomputed_hash() as isize } fn __str__(&self) -> &'static str { - self.value.as_str() + self.inner().as_str() } fn __repr__(&self) -> String { format!( "{}('{}')", stringify!($ty).split("::").last().unwrap_or(""), - self.value + self.as_str() ) } #[getter] #[pyo3(name = "value")] fn py_value(&self) -> String { - self.value.to_string() + self.to_string() } } }; diff --git a/nautilus_core/model/src/venues.rs b/nautilus_core/model/src/venues.rs index 9ae31d5d8ca8..b479f2207bce 100644 --- a/nautilus_core/model/src/venues.rs +++ b/nautilus_core/model/src/venues.rs @@ -19,7 +19,6 @@ use std::{ }; use once_cell::sync::Lazy; -use ustr::Ustr; use crate::identifiers::venue::Venue; @@ -35,63 +34,47 @@ static XNYM_LOCK: OnceLock = OnceLock::new(); impl Venue { #[allow(non_snake_case)] pub fn CBCM() -> Self { - *CBCM_LOCK.get_or_init(|| Self { - value: Ustr::from("CBCM"), - }) + *CBCM_LOCK.get_or_init(|| Self::from("CBCM")) } #[allow(non_snake_case)] pub fn GLBX() -> Self { - *GLBX_LOCK.get_or_init(|| Self { - value: Ustr::from("GLBX"), - }) + *GLBX_LOCK.get_or_init(|| Self::from("GLBX")) } #[allow(non_snake_case)] pub fn NYUM() -> Self { - *NYUM_LOCK.get_or_init(|| Self { - value: Ustr::from("NYUM"), - }) + *NYUM_LOCK.get_or_init(|| Self::from("NYUM")) } #[allow(non_snake_case)] pub fn XCBT() -> Self { - *XCBT_LOCK.get_or_init(|| Self { - value: Ustr::from("XCBT"), - }) + *XCBT_LOCK.get_or_init(|| Self::from("XCBT")) } #[allow(non_snake_case)] pub fn XCEC() -> Self { - *XCEC_LOCK.get_or_init(|| Self { - value: Ustr::from("XCEC"), - }) + *XCEC_LOCK.get_or_init(|| Self::from("XCEC")) } #[allow(non_snake_case)] pub fn XCME() -> Self { - *XCME_LOCK.get_or_init(|| Self { - value: Ustr::from("XCME"), - }) + *XCME_LOCK.get_or_init(|| Self::from("XCME")) } #[allow(non_snake_case)] pub fn XFXS() -> Self { - *XFXS_LOCK.get_or_init(|| Self { - value: Ustr::from("XFXS"), - }) + *XFXS_LOCK.get_or_init(|| Self::from("XFXS")) } #[allow(non_snake_case)] pub fn XNYM() -> Self { - *XNYM_LOCK.get_or_init(|| Self { - value: Ustr::from("XNYM"), - }) + *XNYM_LOCK.get_or_init(|| Self::from("XNYM")) } } pub static VENUE_MAP: Lazy>> = Lazy::new(|| { let mut map = HashMap::new(); - map.insert(Venue::CBCM().value.as_str(), Venue::CBCM()); - map.insert(Venue::GLBX().value.as_str(), Venue::GLBX()); - map.insert(Venue::NYUM().value.as_str(), Venue::NYUM()); - map.insert(Venue::XCBT().value.as_str(), Venue::XCBT()); - map.insert(Venue::XCEC().value.as_str(), Venue::XCEC()); - map.insert(Venue::XCME().value.as_str(), Venue::XCME()); - map.insert(Venue::XFXS().value.as_str(), Venue::XFXS()); - map.insert(Venue::XNYM().value.as_str(), Venue::XNYM()); + map.insert(Venue::CBCM().inner().as_str(), Venue::CBCM()); + map.insert(Venue::GLBX().inner().as_str(), Venue::GLBX()); + map.insert(Venue::NYUM().inner().as_str(), Venue::NYUM()); + map.insert(Venue::XCBT().inner().as_str(), Venue::XCBT()); + map.insert(Venue::XCEC().inner().as_str(), Venue::XCEC()); + map.insert(Venue::XCME().inner().as_str(), Venue::XCME()); + map.insert(Venue::XFXS().inner().as_str(), Venue::XFXS()); + map.insert(Venue::XNYM().inner().as_str(), Venue::XNYM()); Mutex::new(map) }); diff --git a/nautilus_trader/core/includes/model.h b/nautilus_trader/core/includes/model.h index 260a673a1473..5c8145bbb525 100644 --- a/nautilus_trader/core/includes/model.h +++ b/nautilus_trader/core/includes/model.h @@ -731,20 +731,14 @@ typedef struct SyntheticInstrument SyntheticInstrument; * Represents a valid ticker symbol ID for a tradable financial market instrument. */ typedef struct Symbol_t { - /** - * The ticker symbol ID value. - */ - char* value; + char* _0; } Symbol_t; /** * Represents a valid trading venue ID. */ typedef struct Venue_t { - /** - * The venue ID value. - */ - char* value; + char* _0; } Venue_t; /** @@ -1099,10 +1093,7 @@ typedef struct Data_t { * do not collide with those from another node instance. */ typedef struct TraderId_t { - /** - * The trader ID value. - */ - char* value; + char* _0; } TraderId_t; /** @@ -1118,20 +1109,14 @@ typedef struct TraderId_t { * do not collide with those from another strategy within the node instance. */ typedef struct StrategyId_t { - /** - * The strategy ID value. - */ - char* value; + char* _0; } StrategyId_t; /** * Represents a valid client order ID (assigned by the Nautilus system). */ typedef struct ClientOrderId_t { - /** - * The client order ID value. - */ - char* value; + char* _0; } ClientOrderId_t; typedef struct OrderDenied_t { @@ -1176,10 +1161,7 @@ typedef struct OrderReleased_t { * Example: "IB-D02851908". */ typedef struct AccountId_t { - /** - * The account ID value. - */ - char* value; + char* _0; } AccountId_t; typedef struct OrderSubmitted_t { @@ -1197,10 +1179,7 @@ typedef struct OrderSubmitted_t { * Represents a valid venue order ID (assigned by a trading venue). */ typedef struct VenueOrderId_t { - /** - * The venue assigned order ID value. - */ - char* value; + char* _0; } VenueOrderId_t; typedef struct OrderAccepted_t { @@ -1233,50 +1212,35 @@ typedef struct OrderRejected_t { * Represents a system client ID. */ typedef struct ClientId_t { - /** - * The client ID value. - */ - char* value; + char* _0; } ClientId_t; /** * Represents a valid component ID. */ typedef struct ComponentId_t { - /** - * The component ID value. - */ - char* value; + char* _0; } ComponentId_t; /** * Represents a valid execution algorithm ID. */ typedef struct ExecAlgorithmId_t { - /** - * The execution algorithm ID value. - */ - char* value; + char* _0; } ExecAlgorithmId_t; /** * Represents a valid order list ID (assigned by the Nautilus system). */ typedef struct OrderListId_t { - /** - * The order list ID value. - */ - char* value; + char* _0; } OrderListId_t; /** * Represents a valid position ID. */ typedef struct PositionId_t { - /** - * The position ID value. - */ - char* value; + char* _0; } PositionId_t; /** diff --git a/nautilus_trader/core/rust/model.pxd b/nautilus_trader/core/rust/model.pxd index 7d6c758a26a6..a38941b86c6c 100644 --- a/nautilus_trader/core/rust/model.pxd +++ b/nautilus_trader/core/rust/model.pxd @@ -400,13 +400,11 @@ cdef extern from "../includes/model.h": # Represents a valid ticker symbol ID for a tradable financial market instrument. cdef struct Symbol_t: - # The ticker symbol ID value. - char* value; + char* _0; # Represents a valid trading venue ID. cdef struct Venue_t: - # The venue ID value. - char* value; + char* _0; # Represents a valid instrument ID. # @@ -605,8 +603,7 @@ cdef extern from "../includes/model.h": # The reason for the numerical component of the ID is so that order and position IDs # do not collide with those from another node instance. cdef struct TraderId_t: - # The trader ID value. - char* value; + char* _0; # Represents a valid strategy ID. # @@ -619,13 +616,11 @@ cdef extern from "../includes/model.h": # The reason for the numerical component of the ID is so that order and position IDs # do not collide with those from another strategy within the node instance. cdef struct StrategyId_t: - # The strategy ID value. - char* value; + char* _0; # Represents a valid client order ID (assigned by the Nautilus system). cdef struct ClientOrderId_t: - # The client order ID value. - char* value; + char* _0; cdef struct OrderDenied_t: TraderId_t trader_id; @@ -664,8 +659,7 @@ cdef extern from "../includes/model.h": # # Example: "IB-D02851908". cdef struct AccountId_t: - # The account ID value. - char* value; + char* _0; cdef struct OrderSubmitted_t: TraderId_t trader_id; @@ -679,8 +673,7 @@ cdef extern from "../includes/model.h": # Represents a valid venue order ID (assigned by a trading venue). cdef struct VenueOrderId_t: - # The venue assigned order ID value. - char* value; + char* _0; cdef struct OrderAccepted_t: TraderId_t trader_id; @@ -708,28 +701,23 @@ cdef extern from "../includes/model.h": # Represents a system client ID. cdef struct ClientId_t: - # The client ID value. - char* value; + char* _0; # Represents a valid component ID. cdef struct ComponentId_t: - # The component ID value. - char* value; + char* _0; # Represents a valid execution algorithm ID. cdef struct ExecAlgorithmId_t: - # The execution algorithm ID value. - char* value; + char* _0; # Represents a valid order list ID (assigned by the Nautilus system). cdef struct OrderListId_t: - # The order list ID value. - char* value; + char* _0; # Represents a valid position ID. cdef struct PositionId_t: - # The position ID value. - char* value; + char* _0; # Provides a C compatible Foreign Function Interface (FFI) for an underlying # [`SyntheticInstrument`]. diff --git a/nautilus_trader/model/identifiers.pyx b/nautilus_trader/model/identifiers.pyx index a6b5ef0a6e0f..cb921aee5c4a 100644 --- a/nautilus_trader/model/identifiers.pyx +++ b/nautilus_trader/model/identifiers.pyx @@ -139,7 +139,7 @@ cdef class Symbol(Identifier): def __eq__(self, Symbol other) -> bool: if other is None: raise RuntimeError("other was None in __eq__") - return strcmp(self._mem.value, other._mem.value) == 0 + return strcmp(self._mem._0, other._mem._0) == 0 def __hash__(self) -> int: return hash(self.to_str()) @@ -151,7 +151,7 @@ cdef class Symbol(Identifier): return symbol cdef str to_str(self): - return ustr_to_pystr(self._mem.value) + return ustr_to_pystr(self._mem._0) cdef class Venue(Identifier): @@ -182,13 +182,13 @@ cdef class Venue(Identifier): def __eq__(self, Venue other) -> bool: if other is None: raise RuntimeError("other was None in __eq__") - return strcmp(self._mem.value, other._mem.value) == 0 + return strcmp(self._mem._0, other._mem._0) == 0 def __hash__(self) -> int: return hash(self.to_str()) cdef str to_str(self): - return ustr_to_pystr(self._mem.value) + return ustr_to_pystr(self._mem._0) @staticmethod cdef Venue from_mem_c(Venue_t mem): @@ -294,7 +294,7 @@ cdef class InstrumentId(Identifier): def __eq__(self, InstrumentId other) -> bool: if other is None: raise RuntimeError("other was None in __eq__") - return strcmp(self._mem.symbol.value, other._mem.symbol.value) == 0 and strcmp(self._mem.venue.value, other._mem.venue.value) == 0 + return strcmp(self._mem.symbol._0, other._mem.symbol._0) == 0 and strcmp(self._mem.venue._0, other._mem.venue._0) == 0 def __hash__(self) -> int: return hash(self.to_str()) @@ -390,7 +390,7 @@ cdef class ComponentId(Identifier): def __eq__(self, ComponentId other) -> bool: if other is None: raise RuntimeError("other was None in __eq__") - return strcmp(self._mem.value, other._mem.value) == 0 + return strcmp(self._mem._0, other._mem._0) == 0 def __hash__(self) -> int: return hash(self.to_str()) @@ -402,7 +402,7 @@ cdef class ComponentId(Identifier): return component_id cdef str to_str(self): - return ustr_to_pystr(self._mem.value) + return ustr_to_pystr(self._mem._0) cdef class ClientId(Identifier): @@ -437,7 +437,7 @@ cdef class ClientId(Identifier): def __eq__(self, ClientId other) -> bool: if other is None: raise RuntimeError("other was None in __eq__") - return strcmp(self._mem.value, other._mem.value) == 0 + return strcmp(self._mem._0, other._mem._0) == 0 def __hash__(self) -> int: return hash(self.to_str()) @@ -449,7 +449,7 @@ cdef class ClientId(Identifier): return client_id cdef str to_str(self): - return ustr_to_pystr(self._mem.value) + return ustr_to_pystr(self._mem._0) cdef class TraderId(Identifier): @@ -493,7 +493,7 @@ cdef class TraderId(Identifier): def __eq__(self, TraderId other) -> bool: if other is None: raise RuntimeError("other was None in __eq__") - return strcmp(self._mem.value, other._mem.value) == 0 + return strcmp(self._mem._0, other._mem._0) == 0 def __hash__(self) -> int: return hash(self.to_str()) @@ -505,7 +505,7 @@ cdef class TraderId(Identifier): return trader_id cdef str to_str(self): - return ustr_to_pystr(self._mem.value) + return ustr_to_pystr(self._mem._0) cpdef str get_tag(self): """ @@ -566,7 +566,7 @@ cdef class StrategyId(Identifier): def __eq__(self, StrategyId other) -> bool: if other is None: raise RuntimeError("other was None in __eq__") - return strcmp(self._mem.value, other._mem.value) == 0 + return strcmp(self._mem._0, other._mem._0) == 0 def __hash__(self) -> int: return hash(self.to_str()) @@ -582,7 +582,7 @@ cdef class StrategyId(Identifier): return EXTERNAL_STRATEGY_ID cdef str to_str(self): - return ustr_to_pystr(self._mem.value) + return ustr_to_pystr(self._mem._0) cpdef str get_tag(self): """ @@ -637,7 +637,7 @@ cdef class ExecAlgorithmId(Identifier): def __eq__(self, ExecAlgorithmId other) -> bool: if other is None: raise RuntimeError("other was None in __eq__") - return strcmp(self._mem.value, other._mem.value) == 0 + return strcmp(self._mem._0, other._mem._0) == 0 def __hash__(self) -> int: return hash(self.to_str()) @@ -649,7 +649,7 @@ cdef class ExecAlgorithmId(Identifier): return exec_algorithm_id cdef str to_str(self): - return ustr_to_pystr(self._mem.value) + return ustr_to_pystr(self._mem._0) @@ -692,7 +692,7 @@ cdef class AccountId(Identifier): def __eq__(self, AccountId other) -> bool: if other is None: raise RuntimeError("other was None in __eq__") - return strcmp(self._mem.value, other._mem.value) == 0 + return strcmp(self._mem._0, other._mem._0) == 0 def __hash__(self) -> int: return hash(self.to_str()) @@ -704,7 +704,7 @@ cdef class AccountId(Identifier): return account_id cdef str to_str(self): - return ustr_to_pystr(self._mem.value) + return ustr_to_pystr(self._mem._0) cpdef str get_issuer(self): """ @@ -761,7 +761,7 @@ cdef class ClientOrderId(Identifier): def __eq__(self, ClientOrderId other) -> bool: if other is None: raise RuntimeError("other was None in __eq__") - return strcmp(self._mem.value, other._mem.value) == 0 + return strcmp(self._mem._0, other._mem._0) == 0 def __hash__(self) -> int: return hash(self.to_str()) @@ -773,7 +773,7 @@ cdef class ClientOrderId(Identifier): return client_order_id cdef str to_str(self): - return ustr_to_pystr(self._mem.value) + return ustr_to_pystr(self._mem._0) cpdef bint is_this_trader(self, TraderId trader_id): """ @@ -826,7 +826,7 @@ cdef class VenueOrderId(Identifier): def __eq__(self, VenueOrderId other) -> bool: if other is None: raise RuntimeError("other was None in __eq__") - return strcmp(self._mem.value, other._mem.value) == 0 + return strcmp(self._mem._0, other._mem._0) == 0 def __hash__(self) -> int: return hash(self.to_str()) @@ -838,7 +838,7 @@ cdef class VenueOrderId(Identifier): return venue_order_id cdef str to_str(self): - return ustr_to_pystr(self._mem.value) + return ustr_to_pystr(self._mem._0) cdef class OrderListId(Identifier): @@ -869,7 +869,7 @@ cdef class OrderListId(Identifier): def __eq__(self, OrderListId other) -> bool: if other is None: raise RuntimeError("other was None in __eq__") - return strcmp(self._mem.value, other._mem.value) == 0 + return strcmp(self._mem._0, other._mem._0) == 0 def __hash__(self) -> int: return hash(self.to_str()) @@ -881,7 +881,7 @@ cdef class OrderListId(Identifier): return order_list_id cdef str to_str(self): - return ustr_to_pystr(self._mem.value) + return ustr_to_pystr(self._mem._0) cdef class PositionId(Identifier): @@ -912,7 +912,7 @@ cdef class PositionId(Identifier): def __eq__(self, PositionId other) -> bool: if other is None: raise RuntimeError("other was None in __eq__") - return strcmp(self._mem.value, other._mem.value) == 0 + return strcmp(self._mem._0, other._mem._0) == 0 def __hash__(self) -> int: return hash(self.to_str()) @@ -924,7 +924,7 @@ cdef class PositionId(Identifier): return position_id cdef str to_str(self): - return ustr_to_pystr(self._mem.value) + return ustr_to_pystr(self._mem._0) cdef bint is_virtual_c(self): return self.to_str().startswith("P-")