use thiserror::Error;
#[derive(Error, Debug, Clone, Copy, PartialEq, Eq)]
pub enum MalformedFix {
#[error("Invalid FIX message framing")]
InvalidMessage,
#[error("Invalid FIX format")]
InvalidFormat,
#[error("Missing separator")]
MissingSeparator,
#[error("BodyLength mismatch")]
BodyLengthMismatch,
#[error("Checksum mismatch")]
ChecksumMismatch,
#[error("Non-ASCII byte in FIX message")]
NonAsciiByte,
}
#[derive(Error, Debug)]
pub enum FixError {
#[error("{0}")]
Malformed(#[from] MalformedFix),
#[error("Invalid value for tag {tag}{ctx}")]
InvalidValue { tag: u32, ctx: String },
#[error("Invalid tag {0}")]
InvalidTag(u32),
#[error("Invalid enum value for tag {tag} ({ty})")]
InvalidEnumValue {
tag: u32,
ty: &'static str,
},
#[error("Missing required field {name} (tag {tag})")]
MissingField { name: &'static str, tag: u32 },
#[error("Missing required component {0}")]
MissingComponent(&'static str),
#[error("UTF-8 parsing error")]
Utf8Error(#[from] std::str::Utf8Error),
#[error("DateTime parsing error")]
DateTimeError(#[from] chrono::ParseError),
}
impl FixError {
#[inline]
pub fn invalid_value(tag: u32) -> Self {
Self::InvalidValue {
tag,
ctx: String::new(),
}
}
#[inline]
pub fn invalid_value_ctx(tag: u32, bytes: &[u8]) -> Self {
const MAX: usize = 48;
let mut s = String::from_utf8_lossy(bytes).into_owned();
if s.len() > MAX {
s.truncate(MAX);
s.push('…');
}
Self::InvalidValue {
tag,
ctx: format!(" (value: {s})"),
}
}
#[inline]
pub fn invalid_enum_value(tag: u32, ty: &'static str) -> Self {
Self::InvalidEnumValue { tag, ty }
}
}