dstar_gateway_core/codec/dextra/
error.rs

1//! `DExtra` wire-format errors returned by the codec.
2
3use crate::error::EncodeError;
4
5/// Errors returned by the `DExtra` codec functions.
6#[derive(Debug, Clone, thiserror::Error, PartialEq, Eq)]
7#[non_exhaustive]
8pub enum DExtraError {
9    /// `DExtra` packet length is not one of the known sizes.
10    #[error("DExtra packet length {got} not valid for any known type")]
11    UnknownPacketLength {
12        /// Observed length.
13        got: usize,
14    },
15
16    /// Packet expected to be DSVT-framed but the magic at `[0..4]` is wrong.
17    #[error("expected DSVT magic at offset 0..4, got {got:02X?}")]
18    DsvtMagicMissing {
19        /// Observed bytes.
20        got: [u8; 4],
21    },
22
23    /// Stream id at offsets `[12..14]` is zero.
24    #[error("DExtra stream id is zero (reserved)")]
25    StreamIdZero,
26
27    /// LINK packet has a non-A-Z reflector or client module byte.
28    #[error("DExtra LINK has invalid module byte 0x{byte:02X} at offset {offset}")]
29    InvalidModuleByte {
30        /// Byte offset within the 11-byte packet.
31        offset: usize,
32        /// Rejected byte.
33        byte: u8,
34    },
35
36    /// Connect reply tag at `[10..13]` is neither `ACK` nor `NAK`.
37    #[error("DExtra connect reply has unknown tag {tag:02X?}")]
38    UnknownConnectTag {
39        /// The 3-byte tag observed.
40        tag: [u8; 3],
41    },
42
43    /// An encoder was called with an undersized output buffer.
44    ///
45    /// Programming error inside [`crate::session::client::SessionCore`];
46    /// surfaced as a variant rather than swallowed so callers can
47    /// still observe the fault.
48    #[error("DExtra encode buffer too small: need {need}, have {have}")]
49    EncodeBufferTooSmall {
50        /// How many bytes the encoder needed.
51        need: usize,
52        /// How many bytes the buffer actually held.
53        have: usize,
54    },
55}
56
57impl From<EncodeError> for DExtraError {
58    fn from(value: EncodeError) -> Self {
59        match value {
60            EncodeError::BufferTooSmall { need, have } => Self::EncodeBufferTooSmall { need, have },
61        }
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn unknown_length_display() {
71        let err = DExtraError::UnknownPacketLength { got: 42 };
72        assert!(err.to_string().contains("42"));
73    }
74
75    #[test]
76    fn stream_id_zero_display() {
77        let err = DExtraError::StreamIdZero;
78        assert_eq!(err.to_string(), "DExtra stream id is zero (reserved)");
79    }
80
81    #[test]
82    fn invalid_module_byte_display() {
83        let err = DExtraError::InvalidModuleByte {
84            offset: 9,
85            byte: 0x40,
86        };
87        let s = err.to_string();
88        assert!(s.contains('9'));
89        assert!(s.contains("40"));
90    }
91
92    #[test]
93    fn unknown_connect_tag_display() {
94        let err = DExtraError::UnknownConnectTag {
95            tag: [b'F', b'O', b'O'],
96        };
97        assert!(err.to_string().contains("46"));
98    }
99}