Skip to main content

automotive_wire_codec/
error.rs

1//! Primitive decode error fragments. An L1 error implements `From` of each so shared
2//! trait defaults and leaf helpers can construct errors generically.
3
4/// A read ran out of bytes: `needed` were required, only `available` present.
5#[derive(Clone, Copy, Debug, Eq, PartialEq)]
6pub struct Incomplete {
7    /// Number of bytes the read required.
8    pub needed: usize,
9    /// Number of bytes actually available.
10    pub available: usize,
11}
12
13/// Bytes remained after a `decode_exact` that should have consumed the whole buffer.
14#[derive(Clone, Copy, Debug, Eq, PartialEq)]
15pub struct TrailingBytes(pub usize);
16
17impl core::fmt::Display for Incomplete {
18    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
19        write!(
20            f,
21            "incomplete input: needed {} bytes, {} available",
22            self.needed, self.available
23        )
24    }
25}
26impl core::error::Error for Incomplete {}
27
28impl core::fmt::Display for TrailingBytes {
29    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
30        write!(f, "{} trailing bytes after decode", self.0)
31    }
32}
33impl core::error::Error for TrailingBytes {}
34
35/// A variable-width read/write was requested with an out-of-range byte width.
36///
37/// Returned (via [`ReadUintError`](crate::ReadUintError) /
38/// [`WriteUintError`](crate::WriteUintError)) instead of panicking, so a
39/// wire-controlled width is a recoverable *data* error, not a programming error.
40#[derive(Clone, Copy, Debug, Eq, PartialEq)]
41pub struct InvalidWidth {
42    /// Maximum width the operation supports.
43    pub max: usize,
44    /// Width actually requested.
45    pub got: usize,
46}
47
48/// An output slice was too small for the bytes an encode needed to write.
49///
50/// Encode-side mirror of [`Incomplete`]. Constructed by
51/// [`Encode::encode_to_slice`](crate::Encode::encode_to_slice), where both
52/// counts are knowable; generic [`embedded_io::Write`] sinks cannot report
53/// capacity, so they surface [`embedded_io::ErrorKind::WriteZero`] instead.
54#[derive(Clone, Copy, Debug, Eq, PartialEq)]
55pub struct InsufficientBuffer {
56    /// Number of bytes the encode required.
57    pub needed: usize,
58    /// Number of bytes the slice actually had.
59    pub available: usize,
60}
61
62impl core::fmt::Display for InvalidWidth {
63    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
64        write!(f, "invalid width: got {}, max {}", self.got, self.max)
65    }
66}
67impl core::error::Error for InvalidWidth {}
68
69impl core::fmt::Display for InsufficientBuffer {
70    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
71        write!(
72            f,
73            "insufficient buffer: needed {} bytes, {} available",
74            self.needed, self.available
75        )
76    }
77}
78impl core::error::Error for InsufficientBuffer {}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83    use std::string::ToString;
84
85    #[test]
86    fn incomplete_display() {
87        let e = Incomplete {
88            needed: 4,
89            available: 1,
90        };
91        assert_eq!(
92            e.to_string(),
93            "incomplete input: needed 4 bytes, 1 available"
94        );
95    }
96
97    #[test]
98    fn trailing_display() {
99        assert_eq!(
100            TrailingBytes(3).to_string(),
101            "3 trailing bytes after decode"
102        );
103    }
104
105    fn assert_is_error<T: core::error::Error>() {}
106
107    #[test]
108    fn impl_core_error() {
109        assert_is_error::<Incomplete>();
110        assert_is_error::<TrailingBytes>();
111    }
112
113    #[test]
114    fn invalid_width_display() {
115        let e = InvalidWidth { max: 16, got: 255 };
116        assert_eq!(e.to_string(), "invalid width: got 255, max 16");
117    }
118
119    #[test]
120    fn insufficient_buffer_display() {
121        let e = InsufficientBuffer {
122            needed: 8,
123            available: 4,
124        };
125        assert_eq!(
126            e.to_string(),
127            "insufficient buffer: needed 8 bytes, 4 available"
128        );
129    }
130
131    #[test]
132    fn new_fragments_impl_core_error() {
133        assert_is_error::<InvalidWidth>();
134        assert_is_error::<InsufficientBuffer>();
135    }
136}