1use crate::{
2 record::{CbboMsg, Cmbp1Msg},
3 BboMsg, Error, ErrorMsg, ImbalanceMsg, InstrumentDefMsg, MboMsg, Mbp10Msg, Mbp1Msg, OhlcvMsg,
4 RType, Record, RecordMut, RecordRef, StatMsg, StatusMsg, SymbolMappingMsg, SystemMsg, TradeMsg,
5};
6
7#[derive(Debug, Clone)]
12pub enum RecordEnum {
13 Mbo(MboMsg),
15 Trade(TradeMsg),
17 Mbp1(Mbp1Msg),
19 Mbp10(Mbp10Msg),
21 Ohlcv(OhlcvMsg),
23 Status(StatusMsg),
25 InstrumentDef(InstrumentDefMsg),
27 Imbalance(ImbalanceMsg),
29 Stat(StatMsg),
31 Error(ErrorMsg),
33 SymbolMapping(SymbolMappingMsg),
35 System(SystemMsg),
37 Cmbp1(Cmbp1Msg),
39 Bbo(BboMsg),
41 Cbbo(CbboMsg),
43}
44
45#[derive(Debug, Copy, Clone)]
50pub enum RecordRefEnum<'a> {
51 Mbo(&'a MboMsg),
53 Trade(&'a TradeMsg),
55 Mbp1(&'a Mbp1Msg),
57 Mbp10(&'a Mbp10Msg),
59 Ohlcv(&'a OhlcvMsg),
61 Status(&'a StatusMsg),
63 InstrumentDef(&'a InstrumentDefMsg),
65 Imbalance(&'a ImbalanceMsg),
67 Stat(&'a StatMsg),
69 Error(&'a ErrorMsg),
72 SymbolMapping(&'a SymbolMappingMsg),
74 System(&'a SystemMsg),
77 Cmbp1(&'a Cmbp1Msg),
79 Bbo(&'a BboMsg),
81 Cbbo(&'a CbboMsg),
83}
84
85impl<'a> From<&'a RecordEnum> for RecordRefEnum<'a> {
86 fn from(rec_enum: &'a RecordEnum) -> Self {
87 match rec_enum {
88 RecordEnum::Mbo(rec) => Self::Mbo(rec),
89 RecordEnum::Trade(rec) => Self::Trade(rec),
90 RecordEnum::Mbp1(rec) => Self::Mbp1(rec),
91 RecordEnum::Mbp10(rec) => Self::Mbp10(rec),
92 RecordEnum::Ohlcv(rec) => Self::Ohlcv(rec),
93 RecordEnum::Status(rec) => Self::Status(rec),
94 RecordEnum::InstrumentDef(rec) => Self::InstrumentDef(rec),
95 RecordEnum::Imbalance(rec) => Self::Imbalance(rec),
96 RecordEnum::Stat(rec) => Self::Stat(rec),
97 RecordEnum::Error(rec) => Self::Error(rec),
98 RecordEnum::SymbolMapping(rec) => Self::SymbolMapping(rec),
99 RecordEnum::System(rec) => Self::System(rec),
100 RecordEnum::Cmbp1(rec) => Self::Cmbp1(rec),
101 RecordEnum::Bbo(rec) => Self::Bbo(rec),
102 RecordEnum::Cbbo(rec) => Self::Cbbo(rec),
103 }
104 }
105}
106
107impl RecordRefEnum<'_> {
108 pub fn to_owned(&self) -> RecordEnum {
110 #[allow(clippy::clone_on_copy)] match self {
112 Self::Mbo(rec) => RecordEnum::from((*rec).clone()),
113 Self::Trade(rec) => RecordEnum::from((*rec).clone()),
114 Self::Mbp1(rec) => RecordEnum::from((*rec).clone()),
115 Self::Mbp10(rec) => RecordEnum::from((*rec).clone()),
116 Self::Ohlcv(rec) => RecordEnum::from((*rec).clone()),
117 Self::Status(rec) => RecordEnum::from((*rec).clone()),
118 Self::InstrumentDef(rec) => RecordEnum::from((*rec).clone()),
119 Self::Imbalance(rec) => RecordEnum::from((*rec).clone()),
120 Self::Stat(rec) => RecordEnum::from((*rec).clone()),
121 Self::Error(rec) => RecordEnum::from((*rec).clone()),
122 Self::SymbolMapping(rec) => RecordEnum::from((*rec).clone()),
123 Self::System(rec) => RecordEnum::from((*rec).clone()),
124 Self::Cmbp1(rec) => RecordEnum::from((*rec).clone()),
125 Self::Bbo(rec) => RecordEnum::Bbo((*rec).clone()),
126 Self::Cbbo(rec) => RecordEnum::Cbbo((*rec).clone()),
127 }
128 }
129}
130
131impl<'a> TryFrom<RecordRef<'a>> for RecordRefEnum<'a> {
132 type Error = Error;
133
134 fn try_from(rec_ref: RecordRef<'a>) -> Result<Self, Error> {
135 Ok(unsafe {
136 #[allow(deprecated)]
137 match rec_ref.rtype()? {
138 RType::Mbo => RecordRefEnum::Mbo(rec_ref.get_unchecked()),
139 RType::Mbp0 => RecordRefEnum::Trade(rec_ref.get_unchecked()),
140 RType::Mbp1 => RecordRefEnum::Mbp1(rec_ref.get_unchecked()),
141 RType::Bbo1S | RType::Bbo1M => RecordRefEnum::Bbo(rec_ref.get_unchecked()),
142 RType::Mbp10 => RecordRefEnum::Mbp10(rec_ref.get_unchecked()),
143 RType::OhlcvDeprecated
144 | RType::Ohlcv1S
145 | RType::Ohlcv1M
146 | RType::Ohlcv1H
147 | RType::Ohlcv1D
148 | RType::OhlcvEod => RecordRefEnum::Ohlcv(rec_ref.get_unchecked()),
149 RType::Status => RecordRefEnum::Status(rec_ref.get_unchecked()),
150 RType::InstrumentDef => {
151 if rec_ref.record_size() < std::mem::size_of::<InstrumentDefMsg>() {
153 return Err(Error::conversion::<Self>(
154 "earlier version of InstrumentDefMsg (must be current version)",
155 ));
156 }
157 RecordRefEnum::InstrumentDef(rec_ref.get_unchecked())
158 }
159 RType::Imbalance => RecordRefEnum::Imbalance(rec_ref.get_unchecked()),
160 RType::Statistics => {
161 if rec_ref.record_size() < std::mem::size_of::<StatMsg>() {
162 return Err(Error::conversion::<Self>(
163 "earlier version of StatMsg (must be current version)",
164 ));
165 }
166 RecordRefEnum::Stat(rec_ref.get_unchecked())
167 }
168 RType::Error => {
169 if rec_ref.record_size() < std::mem::size_of::<ErrorMsg>() {
171 return Err(Error::conversion::<Self>(
172 "earlier version of ErrorMsg (must be current version)",
173 ));
174 }
175 RecordRefEnum::Error(rec_ref.get_unchecked())
176 }
177 RType::SymbolMapping => {
178 if rec_ref.record_size() < std::mem::size_of::<SymbolMappingMsg>() {
180 return Err(Error::conversion::<Self>(
181 "earlier version of SymbolMappingMsg (must be current version)",
182 ));
183 }
184 RecordRefEnum::SymbolMapping(rec_ref.get_unchecked())
185 }
186 RType::System => {
187 if rec_ref.record_size() < std::mem::size_of::<SystemMsg>() {
189 return Err(Error::conversion::<Self>(
190 "earlier version of SystemMsg (must be current version)",
191 ));
192 }
193 RecordRefEnum::System(rec_ref.get_unchecked())
194 }
195 RType::Cmbp1 | RType::Tcbbo => RecordRefEnum::Cmbp1(rec_ref.get_unchecked()),
196 RType::Cbbo1S | RType::Cbbo1M => RecordRefEnum::Cbbo(rec_ref.get_unchecked()),
197 }
198 })
199 }
200}
201
202impl From<MboMsg> for RecordEnum {
203 fn from(rec: MboMsg) -> Self {
204 Self::Mbo(rec)
205 }
206}
207impl<'a> From<&'a MboMsg> for RecordRefEnum<'a> {
208 fn from(rec: &'a MboMsg) -> Self {
209 Self::Mbo(rec)
210 }
211}
212impl From<TradeMsg> for RecordEnum {
213 fn from(rec: TradeMsg) -> Self {
214 Self::Trade(rec)
215 }
216}
217impl<'a> From<&'a TradeMsg> for RecordRefEnum<'a> {
218 fn from(rec: &'a TradeMsg) -> Self {
219 Self::Trade(rec)
220 }
221}
222impl From<Mbp1Msg> for RecordEnum {
223 fn from(rec: Mbp1Msg) -> Self {
224 Self::Mbp1(rec)
225 }
226}
227impl<'a> From<&'a Mbp1Msg> for RecordRefEnum<'a> {
228 fn from(rec: &'a Mbp1Msg) -> Self {
229 Self::Mbp1(rec)
230 }
231}
232impl From<Mbp10Msg> for RecordEnum {
233 fn from(rec: Mbp10Msg) -> Self {
234 Self::Mbp10(rec)
235 }
236}
237impl<'a> From<&'a Mbp10Msg> for RecordRefEnum<'a> {
238 fn from(rec: &'a Mbp10Msg) -> Self {
239 Self::Mbp10(rec)
240 }
241}
242impl From<OhlcvMsg> for RecordEnum {
243 fn from(rec: OhlcvMsg) -> Self {
244 Self::Ohlcv(rec)
245 }
246}
247impl<'a> From<&'a OhlcvMsg> for RecordRefEnum<'a> {
248 fn from(rec: &'a OhlcvMsg) -> Self {
249 Self::Ohlcv(rec)
250 }
251}
252impl From<StatusMsg> for RecordEnum {
253 fn from(rec: StatusMsg) -> Self {
254 Self::Status(rec)
255 }
256}
257impl<'a> From<&'a StatusMsg> for RecordRefEnum<'a> {
258 fn from(rec: &'a StatusMsg) -> Self {
259 Self::Status(rec)
260 }
261}
262impl From<InstrumentDefMsg> for RecordEnum {
263 fn from(rec: InstrumentDefMsg) -> Self {
264 Self::InstrumentDef(rec)
265 }
266}
267impl<'a> From<&'a InstrumentDefMsg> for RecordRefEnum<'a> {
268 fn from(rec: &'a InstrumentDefMsg) -> Self {
269 Self::InstrumentDef(rec)
270 }
271}
272impl From<ImbalanceMsg> for RecordEnum {
273 fn from(rec: ImbalanceMsg) -> Self {
274 Self::Imbalance(rec)
275 }
276}
277impl<'a> From<&'a ImbalanceMsg> for RecordRefEnum<'a> {
278 fn from(rec: &'a ImbalanceMsg) -> Self {
279 Self::Imbalance(rec)
280 }
281}
282impl From<StatMsg> for RecordEnum {
283 fn from(rec: StatMsg) -> Self {
284 Self::Stat(rec)
285 }
286}
287impl<'a> From<&'a StatMsg> for RecordRefEnum<'a> {
288 fn from(rec: &'a StatMsg) -> Self {
289 Self::Stat(rec)
290 }
291}
292impl From<ErrorMsg> for RecordEnum {
293 fn from(rec: ErrorMsg) -> Self {
294 Self::Error(rec)
295 }
296}
297impl<'a> From<&'a ErrorMsg> for RecordRefEnum<'a> {
298 fn from(rec: &'a ErrorMsg) -> Self {
299 Self::Error(rec)
300 }
301}
302impl From<SymbolMappingMsg> for RecordEnum {
303 fn from(rec: SymbolMappingMsg) -> Self {
304 Self::SymbolMapping(rec)
305 }
306}
307impl<'a> From<&'a SymbolMappingMsg> for RecordRefEnum<'a> {
308 fn from(rec: &'a SymbolMappingMsg) -> Self {
309 Self::SymbolMapping(rec)
310 }
311}
312impl From<SystemMsg> for RecordEnum {
313 fn from(rec: SystemMsg) -> Self {
314 Self::System(rec)
315 }
316}
317impl<'a> From<&'a SystemMsg> for RecordRefEnum<'a> {
318 fn from(rec: &'a SystemMsg) -> Self {
319 Self::System(rec)
320 }
321}
322impl From<Cmbp1Msg> for RecordEnum {
323 fn from(rec: Cmbp1Msg) -> Self {
324 Self::Cmbp1(rec)
325 }
326}
327impl<'a> From<&'a Cmbp1Msg> for RecordRefEnum<'a> {
328 fn from(rec: &'a Cmbp1Msg) -> Self {
329 Self::Cmbp1(rec)
330 }
331}
332impl From<CbboMsg> for RecordEnum {
333 fn from(rec: CbboMsg) -> Self {
334 Self::Cbbo(rec)
335 }
336}
337impl<'a> From<&'a CbboMsg> for RecordRefEnum<'a> {
338 fn from(rec: &'a CbboMsg) -> Self {
339 Self::Cbbo(rec)
340 }
341}
342
343impl Record for RecordEnum {
344 fn header(&self) -> &crate::RecordHeader {
345 match self {
346 RecordEnum::Mbo(rec) => rec.header(),
347 RecordEnum::Trade(rec) => rec.header(),
348 RecordEnum::Mbp1(rec) => rec.header(),
349 RecordEnum::Mbp10(rec) => rec.header(),
350 RecordEnum::Ohlcv(rec) => rec.header(),
351 RecordEnum::Status(rec) => rec.header(),
352 RecordEnum::InstrumentDef(rec) => rec.header(),
353 RecordEnum::Imbalance(rec) => rec.header(),
354 RecordEnum::Stat(rec) => rec.header(),
355 RecordEnum::Error(rec) => rec.header(),
356 RecordEnum::SymbolMapping(rec) => rec.header(),
357 RecordEnum::System(rec) => rec.header(),
358 RecordEnum::Cmbp1(rec) => rec.header(),
359 RecordEnum::Bbo(rec) => rec.header(),
360 RecordEnum::Cbbo(rec) => rec.header(),
361 }
362 }
363
364 fn raw_index_ts(&self) -> u64 {
365 match self {
366 RecordEnum::Mbo(rec) => rec.raw_index_ts(),
367 RecordEnum::Trade(rec) => rec.raw_index_ts(),
368 RecordEnum::Mbp1(rec) => rec.raw_index_ts(),
369 RecordEnum::Mbp10(rec) => rec.raw_index_ts(),
370 RecordEnum::Ohlcv(rec) => rec.raw_index_ts(),
371 RecordEnum::Status(rec) => rec.raw_index_ts(),
372 RecordEnum::InstrumentDef(rec) => rec.raw_index_ts(),
373 RecordEnum::Imbalance(rec) => rec.raw_index_ts(),
374 RecordEnum::Stat(rec) => rec.raw_index_ts(),
375 RecordEnum::Error(rec) => rec.raw_index_ts(),
376 RecordEnum::SymbolMapping(rec) => rec.raw_index_ts(),
377 RecordEnum::System(rec) => rec.raw_index_ts(),
378 RecordEnum::Cmbp1(rec) => rec.raw_index_ts(),
379 RecordEnum::Bbo(rec) => rec.raw_index_ts(),
380 RecordEnum::Cbbo(rec) => rec.raw_index_ts(),
381 }
382 }
383}
384
385impl AsRef<[u8]> for RecordEnum {
386 fn as_ref(&self) -> &[u8] {
387 match self {
388 RecordEnum::Mbo(rec) => rec.as_ref(),
389 RecordEnum::Trade(rec) => rec.as_ref(),
390 RecordEnum::Mbp1(rec) => rec.as_ref(),
391 RecordEnum::Mbp10(rec) => rec.as_ref(),
392 RecordEnum::Ohlcv(rec) => rec.as_ref(),
393 RecordEnum::Status(rec) => rec.as_ref(),
394 RecordEnum::InstrumentDef(rec) => rec.as_ref(),
395 RecordEnum::Imbalance(rec) => rec.as_ref(),
396 RecordEnum::Stat(rec) => rec.as_ref(),
397 RecordEnum::Error(rec) => rec.as_ref(),
398 RecordEnum::SymbolMapping(rec) => rec.as_ref(),
399 RecordEnum::System(rec) => rec.as_ref(),
400 RecordEnum::Cmbp1(rec) => rec.as_ref(),
401 RecordEnum::Bbo(rec) => rec.as_ref(),
402 RecordEnum::Cbbo(rec) => rec.as_ref(),
403 }
404 }
405}
406
407impl RecordMut for RecordEnum {
408 fn header_mut(&mut self) -> &mut crate::RecordHeader {
409 match self {
410 RecordEnum::Mbo(rec) => rec.header_mut(),
411 RecordEnum::Trade(rec) => rec.header_mut(),
412 RecordEnum::Mbp1(rec) => rec.header_mut(),
413 RecordEnum::Mbp10(rec) => rec.header_mut(),
414 RecordEnum::Ohlcv(rec) => rec.header_mut(),
415 RecordEnum::Status(rec) => rec.header_mut(),
416 RecordEnum::InstrumentDef(rec) => rec.header_mut(),
417 RecordEnum::Imbalance(rec) => rec.header_mut(),
418 RecordEnum::Stat(rec) => rec.header_mut(),
419 RecordEnum::Error(rec) => rec.header_mut(),
420 RecordEnum::SymbolMapping(rec) => rec.header_mut(),
421 RecordEnum::System(rec) => rec.header_mut(),
422 RecordEnum::Cmbp1(rec) => rec.header_mut(),
423 RecordEnum::Bbo(rec) => rec.header_mut(),
424 RecordEnum::Cbbo(rec) => rec.header_mut(),
425 }
426 }
427}
428
429impl Record for RecordRefEnum<'_> {
430 fn header(&self) -> &crate::RecordHeader {
431 match self {
432 RecordRefEnum::Mbo(rec) => rec.header(),
433 RecordRefEnum::Trade(rec) => rec.header(),
434 RecordRefEnum::Mbp1(rec) => rec.header(),
435 RecordRefEnum::Mbp10(rec) => rec.header(),
436 RecordRefEnum::Ohlcv(rec) => rec.header(),
437 RecordRefEnum::Status(rec) => rec.header(),
438 RecordRefEnum::InstrumentDef(rec) => rec.header(),
439 RecordRefEnum::Imbalance(rec) => rec.header(),
440 RecordRefEnum::Stat(rec) => rec.header(),
441 RecordRefEnum::Error(rec) => rec.header(),
442 RecordRefEnum::SymbolMapping(rec) => rec.header(),
443 RecordRefEnum::System(rec) => rec.header(),
444 RecordRefEnum::Cmbp1(rec) => rec.header(),
445 RecordRefEnum::Bbo(rec) => rec.header(),
446 RecordRefEnum::Cbbo(rec) => rec.header(),
447 }
448 }
449
450 fn raw_index_ts(&self) -> u64 {
451 match self {
452 RecordRefEnum::Mbo(rec) => rec.raw_index_ts(),
453 RecordRefEnum::Trade(rec) => rec.raw_index_ts(),
454 RecordRefEnum::Mbp1(rec) => rec.raw_index_ts(),
455 RecordRefEnum::Mbp10(rec) => rec.raw_index_ts(),
456 RecordRefEnum::Ohlcv(rec) => rec.raw_index_ts(),
457 RecordRefEnum::Status(rec) => rec.raw_index_ts(),
458 RecordRefEnum::InstrumentDef(rec) => rec.raw_index_ts(),
459 RecordRefEnum::Imbalance(rec) => rec.raw_index_ts(),
460 RecordRefEnum::Stat(rec) => rec.raw_index_ts(),
461 RecordRefEnum::Error(rec) => rec.raw_index_ts(),
462 RecordRefEnum::SymbolMapping(rec) => rec.raw_index_ts(),
463 RecordRefEnum::System(rec) => rec.raw_index_ts(),
464 RecordRefEnum::Cmbp1(rec) => rec.raw_index_ts(),
465 RecordRefEnum::Bbo(rec) => rec.raw_index_ts(),
466 RecordRefEnum::Cbbo(rec) => rec.raw_index_ts(),
467 }
468 }
469}
470
471impl AsRef<[u8]> for RecordRefEnum<'_> {
472 fn as_ref(&self) -> &[u8] {
473 match self {
474 RecordRefEnum::Mbo(rec) => rec.as_ref(),
475 RecordRefEnum::Trade(rec) => rec.as_ref(),
476 RecordRefEnum::Mbp1(rec) => rec.as_ref(),
477 RecordRefEnum::Mbp10(rec) => rec.as_ref(),
478 RecordRefEnum::Ohlcv(rec) => rec.as_ref(),
479 RecordRefEnum::Status(rec) => rec.as_ref(),
480 RecordRefEnum::InstrumentDef(rec) => rec.as_ref(),
481 RecordRefEnum::Imbalance(rec) => rec.as_ref(),
482 RecordRefEnum::Stat(rec) => rec.as_ref(),
483 RecordRefEnum::Error(rec) => rec.as_ref(),
484 RecordRefEnum::SymbolMapping(rec) => rec.as_ref(),
485 RecordRefEnum::System(rec) => rec.as_ref(),
486 RecordRefEnum::Cmbp1(rec) => rec.as_ref(),
487 RecordRefEnum::Bbo(rec) => rec.as_ref(),
488 RecordRefEnum::Cbbo(rec) => rec.as_ref(),
489 }
490 }
491}
492
493#[cfg(test)]
494mod tests {
495 use crate::{record::*, v1, v2, HasRType};
496
497 use super::*;
498 use rstest::rstest;
499
500 #[rstest]
501 #[case::mbo(MboMsg::default(), None)]
502 #[case::trade(TradeMsg::default(), None)]
503 #[case::mbp1(Mbp1Msg::default(), None)]
504 #[case::mbp10(Mbp10Msg::default(), None)]
505 #[case::bbo(BboMsg::default_for_schema(crate::Schema::Bbo1S), None)]
506 #[case::cmbp1(Cmbp1Msg::default_for_schema(crate::Schema::Cmbp1), None)]
507 #[case::cbbo(CbboMsg::default_for_schema(crate::Schema::Cbbo1S), None)]
508 #[case::ohlcv(OhlcvMsg::default_for_schema(crate::Schema::Ohlcv1S), None)]
509 #[case::status(StatusMsg::default(), None)]
510 #[case::imbalance(ImbalanceMsg::default(), None)]
511 #[case::instrument_def_v1(
512 v1::InstrumentDefMsg::default(),
513 Some("couldn't convert earlier version of InstrumentDefMsg (must be current version) to dbn::record_enum::RecordRefEnum")
514 )]
515 #[case::instrument_def_v2(
516 v2::InstrumentDefMsg::default(),
517 Some("couldn't convert earlier version of InstrumentDefMsg (must be current version) to dbn::record_enum::RecordRefEnum")
518 )]
519 #[case::instrument_def_current(InstrumentDefMsg::default(), None)]
520 #[case::symbol_mapping_v1(
521 v1::SymbolMappingMsg::default(),
522 Some("couldn't convert earlier version of SymbolMappingMsg (must be current version) to dbn::record_enum::RecordRefEnum")
523 )]
524 #[case::symbol_mapping_current(SymbolMappingMsg::default(), None)]
525 #[case::system_v1(
526 v1::SystemMsg::default(),
527 Some("couldn't convert earlier version of SystemMsg (must be current version) to dbn::record_enum::RecordRefEnum")
528 )]
529 #[case::system_current(SystemMsg::default(), None)]
530 #[case::error_v1(
531 v1::ErrorMsg::default(),
532 Some("couldn't convert earlier version of ErrorMsg (must be current version) to dbn::record_enum::RecordRefEnum")
533 )]
534 #[case::error_current(ErrorMsg::default(), None)]
535 #[case::stat_v1(
536 v1::StatMsg::default(),
537 Some("couldn't convert earlier version of StatMsg (must be current version) to dbn::record_enum::RecordRefEnum")
538 )]
539 #[case::stat_current(StatMsg::default(), None)]
540 fn test_v1_v2_safety<R: HasRType>(#[case] rec: R, #[case] exp_err: Option<&str>) {
541 let rec_ref = RecordRef::from(&rec);
542 let res = rec_ref.as_enum();
543 dbg!(&res);
544 if let Some(exp_err) = exp_err {
545 assert!(format!("{}", res.unwrap_err()).contains(exp_err));
546 } else {
547 assert!(res.is_ok());
548 }
549 }
550}