nautilus_databento/arrow/
mod.rs1pub mod imbalance;
19pub mod statistics;
20
21use std::{collections::HashMap, fmt::Display, str::FromStr, sync::Arc};
22
23use arrow::array::{Array, UInt8Array};
24use nautilus_model::{enums::FromU8, identifiers::InstrumentId};
25use nautilus_serialization::arrow::{
26 EncodingError, KEY_INSTRUMENT_ID, KEY_PRICE_PRECISION, KEY_SIZE_PRECISION, StringColumnRef,
27 enum_dictionary_data_type,
28};
29
30fn parse_metadata(
31 metadata: &HashMap<String, String>,
32) -> Result<(InstrumentId, u8, u8), EncodingError> {
33 let instrument_id_str = metadata
34 .get(KEY_INSTRUMENT_ID)
35 .ok_or_else(|| EncodingError::MissingMetadata(KEY_INSTRUMENT_ID))?;
36 let instrument_id = InstrumentId::from_str(instrument_id_str)
37 .map_err(|e| EncodingError::ParseError(KEY_INSTRUMENT_ID, e.to_string()))?;
38
39 let price_precision = metadata
40 .get(KEY_PRICE_PRECISION)
41 .ok_or_else(|| EncodingError::MissingMetadata(KEY_PRICE_PRECISION))?
42 .parse::<u8>()
43 .map_err(|e| EncodingError::ParseError(KEY_PRICE_PRECISION, e.to_string()))?;
44
45 let size_precision = metadata
46 .get(KEY_SIZE_PRECISION)
47 .ok_or_else(|| EncodingError::MissingMetadata(KEY_SIZE_PRECISION))?
48 .parse::<u8>()
49 .map_err(|e| EncodingError::ParseError(KEY_SIZE_PRECISION, e.to_string()))?;
50
51 Ok((instrument_id, price_precision, size_precision))
52}
53
54enum EnumColumn<'a> {
55 Strings(StringColumnRef<'a>, &'static str),
56 Codes(&'a UInt8Array, &'static str),
57}
58
59impl<'a> EnumColumn<'a> {
60 fn try_from_column(
61 column: &'a Arc<dyn Array>,
62 field: &'static str,
63 index: usize,
64 ) -> Result<Self, EncodingError> {
65 if let Some(values) = StringColumnRef::try_from_array(column.as_ref()) {
66 return Ok(Self::Strings(values, field));
67 }
68 column
69 .as_any()
70 .downcast_ref::<UInt8Array>()
71 .map(|values| Self::Codes(values, field))
72 .ok_or_else(|| {
73 EncodingError::InvalidColumnType(
74 field,
75 index,
76 enum_dictionary_data_type(),
77 column.data_type().clone(),
78 )
79 })
80 }
81
82 fn decode<T>(&self, row: usize) -> Result<T, EncodingError>
83 where
84 T: FromStr + FromU8,
85 T::Err: Display,
86 {
87 match self {
88 Self::Strings(values, field) => values
89 .value(row)
90 .parse::<T>()
91 .map_err(|e| EncodingError::ParseError(field, format!("row {row}: {e}"))),
92 Self::Codes(values, field) => {
93 let value = values.value(row);
94 T::from_u8(value).ok_or_else(|| {
95 EncodingError::ParseError(field, format!("Invalid enum value, was {value}"))
96 })
97 }
98 }
99 }
100
101 fn decode_optional<T, F>(
102 &self,
103 row: usize,
104 legacy_none: &str,
105 decode_code: F,
106 ) -> Result<Option<T>, EncodingError>
107 where
108 T: FromStr,
109 T::Err: Display,
110 F: Fn(u8) -> Option<T>,
111 {
112 match self {
113 Self::Strings(values, field) => {
114 let value = values.value(row);
115 if value.eq_ignore_ascii_case(legacy_none) {
116 Ok(None)
117 } else {
118 value
119 .parse::<T>()
120 .map(Some)
121 .map_err(|e| EncodingError::ParseError(field, format!("row {row}: {e}")))
122 }
123 }
124 Self::Codes(values, field) => {
125 let value = values.value(row);
126 if value == 0 {
127 Ok(None)
128 } else {
129 decode_code(value).map(Some).ok_or_else(|| {
130 EncodingError::ParseError(field, format!("Invalid enum value, was {value}"))
131 })
132 }
133 }
134 }
135 }
136}