Skip to main content

fixlite/
error.rs

1use thiserror::Error;
2
3/// Wire-format / framing errors (checksum, body length, missing separators, etc.).
4#[derive(Error, Debug, Clone, Copy, PartialEq, Eq)]
5pub enum MalformedFix {
6    #[error("Invalid FIX message framing")]
7    InvalidMessage,
8    #[error("Invalid FIX format")]
9    InvalidFormat,
10    #[error("Missing separator")]
11    MissingSeparator,
12    #[error("BodyLength mismatch")]
13    BodyLengthMismatch,
14    #[error("Checksum mismatch")]
15    ChecksumMismatch,
16    #[error("Non-ASCII byte in FIX message")]
17    NonAsciiByte,
18}
19
20#[derive(Error, Debug)]
21pub enum FixError {
22    /// Wire-format/parsing failures (these mean the byte stream is malformed).
23    #[error("{0}")]
24    Malformed(#[from] MalformedFix),
25
26    /// Semantic/typing failures (message is well-formed but doesn't match expected schema).
27    #[error("Invalid value for tag {tag}{ctx}")]
28    InvalidValue { tag: u32, ctx: String },
29
30    #[error("Invalid tag {0}")]
31    InvalidTag(u32),
32
33    #[error("Invalid enum value for tag {tag} ({ty})")]
34    InvalidEnumValue {
35        tag: u32,
36        /// Enum type name (or tag name) for debugging.
37        ty: &'static str,
38    },
39    #[error("Missing required field {name} (tag {tag})")]
40    MissingField { name: &'static str, tag: u32 },
41    #[error("Missing required component {0}")]
42    MissingComponent(&'static str),
43    #[error("UTF-8 parsing error")]
44    Utf8Error(#[from] std::str::Utf8Error),
45    #[error("DateTime parsing error")]
46    DateTimeError(#[from] chrono::ParseError),
47}
48
49impl FixError {
50    #[inline]
51    pub fn invalid_value(tag: u32) -> Self {
52        Self::InvalidValue {
53            tag,
54            ctx: String::new(),
55        }
56    }
57
58    #[inline]
59    pub fn invalid_value_ctx(tag: u32, bytes: &[u8]) -> Self {
60        const MAX: usize = 48;
61        let mut s = String::from_utf8_lossy(bytes).into_owned();
62        if s.len() > MAX {
63            s.truncate(MAX);
64            s.push('…');
65        }
66        Self::InvalidValue {
67            tag,
68            ctx: format!(" (value: {s})"),
69        }
70    }
71
72    #[inline]
73    pub fn invalid_enum_value(tag: u32, ty: &'static str) -> Self {
74        Self::InvalidEnumValue { tag, ty }
75    }
76}