1#[cfg(feature = "databento")]
2use crate::exchange::databento::DatabentoErrorKind;
3use crate::subscription::SubKind;
4use rustrade_instrument::{exchange::ExchangeId, index::error::IndexError};
5use rustrade_integration::{error::SocketError, subscription::SubscriptionId};
6use serde::{Deserialize, Serialize};
7use thiserror::Error;
8
9#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize, Error)]
11pub enum DataError {
12 #[error("failed to index market data Subscriptions: {0}")]
13 Index(#[from] IndexError),
14
15 #[error("failed to initialise reconnecting MarketStream due to empty subscriptions")]
16 SubscriptionsEmpty,
17
18 #[error("unsupported DynamicStreams Subscription SubKind: {0}")]
19 UnsupportedSubKind(SubKind),
20
21 #[error("initial snapshot missing for: {0}")]
22 InitialSnapshotMissing(SubscriptionId),
23
24 #[error("initial snapshot invalid: {0}")]
25 InitialSnapshotInvalid(String),
26
27 #[error("SocketError: {0}")]
28 Socket(String),
29
30 #[cfg(feature = "databento")]
32 #[error("Databento {kind} error ({context}): {message}")]
33 Databento {
34 kind: DatabentoErrorKind,
35 context: String,
36 message: String,
37 },
38
39 #[error("unsupported dynamic Subscription for exchange: {exchange}, kind: {sub_kind}")]
40 Unsupported {
41 exchange: ExchangeId,
42 sub_kind: SubKind,
43 },
44
45 #[error(
46 "\
47 InvalidSequence: first_update_id {first_update_id} does not follow on from the \
48 prev_last_update_id {prev_last_update_id} \
49 "
50 )]
51 InvalidSequence {
52 prev_last_update_id: u64,
53 first_update_id: u64,
54 },
55}
56
57impl DataError {
58 #[allow(clippy::match_like_matches_macro)]
60 pub fn is_terminal(&self) -> bool {
61 match self {
62 DataError::InvalidSequence { .. } => true,
63 _ => false,
64 }
65 }
66}
67
68impl From<SocketError> for DataError {
69 fn from(value: SocketError) -> Self {
70 Self::Socket(value.to_string())
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn test_data_error_is_terminal() {
80 struct TestCase {
81 input: DataError,
82 expected: bool,
83 }
84
85 let tests = vec![
86 TestCase {
87 input: DataError::InvalidSequence {
89 prev_last_update_id: 0,
90 first_update_id: 0,
91 },
92 expected: true,
93 },
94 TestCase {
95 input: DataError::from(SocketError::Sink),
97 expected: false,
98 },
99 ];
100
101 for (index, test) in tests.into_iter().enumerate() {
102 let actual = test.input.is_terminal();
103 assert_eq!(actual, test.expected, "TC{} failed", index);
104 }
105 }
106}