1use std::fmt;
2
3#[derive(thiserror::Error, Debug)]
5pub enum Error {
6 #[error("IO error: {0}")]
7 Io(#[from] std::io::Error),
8 #[error("invalid demo file: magic bytes mismatch (expected PBDEMS2\\0, got {got:?})")]
9 InvalidMagic { got: [u8; 8] },
10 #[error("unexpected end of data: needed {needed} bits, have {available}")]
11 Overflow { needed: usize, available: usize },
12 #[error("protobuf decode error: {0}")]
13 Decode(#[from] prost::DecodeError),
14 #[error("decompression error: {0}")]
15 Decompress(String),
16 #[error("unknown command type: {0}")]
17 UnknownCommand(u32),
18 #[error("parse error: {context}")]
19 Parse { context: String },
20}
21
22impl From<snap::Error> for Error {
25 fn from(e: snap::Error) -> Self {
26 Error::Decompress(e.to_string())
27 }
28}
29
30pub type Result<T> = std::result::Result<T, Error>;
32
33#[derive(Debug)]
35pub struct FieldValueConversionError;
36
37impl fmt::Display for FieldValueConversionError {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 write!(
40 f,
41 "incompatible types or out of range integer conversion attempted"
42 )
43 }
44}
45
46impl std::error::Error for FieldValueConversionError {}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51
52 #[test]
53 fn io_error_display() {
54 let err = Error::Io(std::io::Error::new(std::io::ErrorKind::NotFound, "gone"));
55 let msg = format!("{}", err);
56 assert!(msg.contains("IO error"));
57 }
58
59 #[test]
60 fn invalid_magic_display() {
61 let err = Error::InvalidMagic { got: [0; 8] };
62 let msg = format!("{}", err);
63 assert!(msg.contains("magic bytes"));
64 }
65
66 #[test]
67 fn overflow_display() {
68 let err = Error::Overflow {
69 needed: 64,
70 available: 8,
71 };
72 let msg = format!("{}", err);
73 assert!(msg.contains("64"));
74 assert!(msg.contains("8"));
75 }
76
77 #[test]
78 fn parse_error_display() {
79 let err = Error::Parse {
80 context: "bad data".to_string(),
81 };
82 let msg = format!("{}", err);
83 assert!(msg.contains("bad data"));
84 }
85
86 #[test]
87 fn field_value_conversion_error() {
88 let err = FieldValueConversionError;
89 let msg = format!("{}", err);
90 assert!(msg.contains("incompatible"));
91 let _: &dyn std::error::Error = &err;
93 }
94}