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