meterbus_wired_datalink/frame/
nack.rs1use core::fmt;
33
34#[cfg(feature = "alloc")]
35use alloc::{vec, vec::Vec};
36
37#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
39pub struct NackFrame;
40
41impl NackFrame {
42 pub const BYTE: u8 = 0xa2;
44 pub const LEN: usize = 1;
46
47 #[must_use]
49 pub const fn new() -> Self {
50 Self
51 }
52
53 pub fn decode(bytes: &[u8]) -> Result<Self, NackFrameError> {
55 if bytes.len() != Self::LEN {
56 return Err(NackFrameError::InvalidLength {
57 actual: bytes.len(),
58 });
59 }
60 if bytes[0] != Self::BYTE {
61 return Err(NackFrameError::InvalidByte { actual: bytes[0] });
62 }
63 Ok(Self)
64 }
65
66 pub fn encode_into<'a>(&self, output: &'a mut [u8]) -> Result<&'a [u8], NackFrameError> {
68 if output.len() < Self::LEN {
69 return Err(NackFrameError::OutputTooSmall {
70 actual: output.len(),
71 });
72 }
73 output[0] = Self::BYTE;
74 Ok(&output[..Self::LEN])
75 }
76
77 #[cfg(feature = "alloc")]
79 pub fn encode(&self) -> Vec<u8> {
80 vec![Self::BYTE]
81 }
82}
83
84#[derive(Clone, Copy, Debug, Eq, PartialEq)]
86#[allow(missing_docs)]
87pub enum NackFrameError {
88 InvalidLength { actual: usize },
90 InvalidByte { actual: u8 },
92 OutputTooSmall { actual: usize },
94}
95
96impl fmt::Display for NackFrameError {
97 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
98 match self {
99 Self::InvalidLength { actual } => write!(
100 formatter,
101 "invalid NACK frame length: expected 1, got {actual}"
102 ),
103 Self::InvalidByte { actual } => write!(
104 formatter,
105 "invalid NACK frame byte: expected 0xa2, got 0x{actual:02x}"
106 ),
107 Self::OutputTooSmall { actual } => write!(
108 formatter,
109 "NACK output buffer too small: expected 1, got {actual}"
110 ),
111 }
112 }
113}
114
115impl core::error::Error for NackFrameError {}
116
117#[cfg(test)]
118#[cfg_attr(coverage_nightly, coverage(off))]
119mod tests {
120 use super::*;
121 #[cfg(feature = "alloc")]
122 use alloc::string::ToString;
123
124 #[test]
125 fn encodes_and_decodes() {
126 let mut output = [0; 1];
127 assert_eq!(NackFrame::new().encode_into(&mut output).unwrap(), [0xa2]);
128 assert_eq!(NackFrame::decode(&output), Ok(NackFrame));
129 }
130
131 #[cfg(feature = "alloc")]
132 #[test]
133 fn allocates_encoded_frame() {
134 assert_eq!(NackFrame.encode(), [0xa2]);
135 }
136
137 #[test]
138 fn rejects_invalid_inputs_and_output() {
139 assert_eq!(
140 NackFrame::decode(&[]),
141 Err(NackFrameError::InvalidLength { actual: 0 })
142 );
143 assert_eq!(
144 NackFrame::decode(&[0xa2, 0]),
145 Err(NackFrameError::InvalidLength { actual: 2 })
146 );
147 assert_eq!(
148 NackFrame::decode(&[0xe5]),
149 Err(NackFrameError::InvalidByte { actual: 0xe5 })
150 );
151 assert_eq!(
152 NackFrame.encode_into(&mut []),
153 Err(NackFrameError::OutputTooSmall { actual: 0 })
154 );
155 }
156
157 #[cfg(feature = "alloc")]
158 #[test]
159 fn formats_errors() {
160 assert_eq!(
161 NackFrameError::InvalidLength { actual: 0 }.to_string(),
162 "invalid NACK frame length: expected 1, got 0"
163 );
164 assert_eq!(
165 NackFrameError::InvalidByte { actual: 0 }.to_string(),
166 "invalid NACK frame byte: expected 0xa2, got 0x00"
167 );
168 assert_eq!(
169 NackFrameError::OutputTooSmall { actual: 0 }.to_string(),
170 "NACK output buffer too small: expected 1, got 0"
171 );
172 }
173}