automotive_wire_codec/
write.rs1use crate::error::InvalidWidth;
12use embedded_io::{Error, Write};
13
14pub fn write_u8(w: &mut impl Write, v: u8) -> Result<usize, embedded_io::ErrorKind> {
19 w.write_all(&[v]).map_err(|e| e.kind())?;
20 Ok(1)
21}
22
23pub fn write_u16_be(w: &mut impl Write, v: u16) -> Result<usize, embedded_io::ErrorKind> {
28 w.write_all(&v.to_be_bytes()).map_err(|e| e.kind())?;
29 Ok(2)
30}
31
32pub fn write_u32_be(w: &mut impl Write, v: u32) -> Result<usize, embedded_io::ErrorKind> {
37 w.write_all(&v.to_be_bytes()).map_err(|e| e.kind())?;
38 Ok(4)
39}
40
41pub fn write_u64_be(w: &mut impl Write, v: u64) -> Result<usize, embedded_io::ErrorKind> {
46 w.write_all(&v.to_be_bytes()).map_err(|e| e.kind())?;
47 Ok(8)
48}
49
50pub fn write_u128_be(w: &mut impl Write, v: u128) -> Result<usize, embedded_io::ErrorKind> {
55 w.write_all(&v.to_be_bytes()).map_err(|e| e.kind())?;
56 Ok(16)
57}
58
59#[derive(Clone, Copy, Debug, Eq, PartialEq)]
61pub enum WriteUintError {
62 Io(embedded_io::ErrorKind),
64 InvalidWidth(InvalidWidth),
66}
67
68impl From<embedded_io::ErrorKind> for WriteUintError {
69 fn from(e: embedded_io::ErrorKind) -> Self {
70 WriteUintError::Io(e)
71 }
72}
73impl From<InvalidWidth> for WriteUintError {
74 fn from(e: InvalidWidth) -> Self {
75 WriteUintError::InvalidWidth(e)
76 }
77}
78impl core::fmt::Display for WriteUintError {
79 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
80 match self {
81 WriteUintError::Io(kind) => write!(f, "write failed: {kind:?}"),
82 WriteUintError::InvalidWidth(e) => e.fmt(f),
83 }
84 }
85}
86impl core::error::Error for WriteUintError {}
87
88#[must_use]
97#[allow(clippy::cast_possible_truncation)] pub const fn minimal_be_len(value: u128) -> usize {
99 (u128::BITS - value.leading_zeros()).div_ceil(8) as usize
100}
101
102pub fn write_be_uint(w: &mut impl Write, value: u128, n: usize) -> Result<usize, WriteUintError> {
120 if n > 16 {
121 return Err(InvalidWidth { max: 16, got: n }.into());
122 }
123 let bytes = value.to_be_bytes(); w.write_all(&bytes[16 - n..])
125 .map_err(|e| WriteUintError::from(e.kind()))?;
126 Ok(n)
127}
128
129pub fn write_all(w: &mut impl Write, bytes: &[u8]) -> Result<usize, embedded_io::ErrorKind> {
134 w.write_all(bytes).map_err(|e| e.kind())?;
135 Ok(bytes.len())
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141 use crate::error::InvalidWidth;
142
143 #[test]
144 fn write_u16_be_writes_big_endian_and_counts() {
145 let mut buf = [0u8; 4];
146 let mut w: &mut [u8] = &mut buf;
147 let n = write_u16_be(&mut w, 0x1234).unwrap();
148 assert_eq!(n, 2);
149 assert_eq!(&buf[..2], &[0x12, 0x34]);
150 }
151
152 #[test]
153 fn write_be_uint_writes_only_low_n_bytes() {
154 let mut buf = [0u8; 3];
155 let mut w: &mut [u8] = &mut buf;
156 let n = write_be_uint(&mut w, 0xAABB_CCDD_u128, 3).unwrap();
158 assert_eq!(n, 3);
159 assert_eq!(buf, [0xBB, 0xCC, 0xDD]);
160 }
161
162 #[test]
163 fn write_all_writes_verbatim() {
164 let mut buf = [0u8; 4];
165 let mut w: &mut [u8] = &mut buf;
166 let n = write_all(&mut w, &[9, 8, 7]).unwrap();
167 assert_eq!(n, 3);
168 assert_eq!(&buf[..3], &[9, 8, 7]);
169 }
170
171 #[test]
172 fn write_into_too_small_slice_errors_not_panics() {
173 let mut buf = [0u8; 1];
174 let mut w: &mut [u8] = &mut buf;
175 assert!(write_u16_be(&mut w, 0x1234).is_err());
176 }
177
178 #[test]
179 fn write_be_uint_hostile_width_is_data_error_not_panic() {
180 let mut buf = [0u8; 300];
183 let mut w: &mut [u8] = &mut buf;
184 assert_eq!(
185 write_be_uint(&mut w, 0xABCD, 255),
186 Err(WriteUintError::InvalidWidth(InvalidWidth {
187 max: 16,
188 got: 255
189 }))
190 );
191 }
192
193 #[test]
194 fn write_be_uint_zero_width_writes_nothing() {
195 let mut buf = [0xFFu8; 2];
196 let mut w: &mut [u8] = &mut buf;
197 assert_eq!(write_be_uint(&mut w, 0xABCD, 0).unwrap(), 0);
198 assert_eq!(buf, [0xFF, 0xFF]);
199 }
200
201 #[test]
202 fn write_u128_be_writes_big_endian_and_counts() {
203 let v = 0x0102_0304_0506_0708_090A_0B0C_0D0E_0F10_u128;
204 let mut buf = [0u8; 16];
205 let mut w: &mut [u8] = &mut buf;
206 assert_eq!(write_u128_be(&mut w, v).unwrap(), 16);
207 assert_eq!(buf, v.to_be_bytes());
208 }
209
210 #[test]
211 fn minimal_be_len_boundaries() {
212 assert_eq!(minimal_be_len(0), 0);
214 assert_eq!(minimal_be_len(1), 1);
215 assert_eq!(minimal_be_len(0xFF), 1);
216 assert_eq!(minimal_be_len(0x100), 2);
217 assert_eq!(minimal_be_len(0xFFFF), 2);
218 assert_eq!(minimal_be_len(0x1_0000), 3);
219 assert_eq!(minimal_be_len(u128::from(u64::MAX)), 8);
220 assert_eq!(minimal_be_len(u128::MAX), 16);
221 }
222
223 #[test]
224 fn write_be_uint_truncates_value_wider_than_n() {
225 let mut buf = [0xEEu8; 4];
230 let mut w: &mut [u8] = &mut buf;
231 assert_eq!(write_be_uint(&mut w, 0x1_0000, 2).unwrap(), 2);
232 assert_eq!(&buf[..2], &[0x00, 0x00]); }
234
235 #[test]
236 fn minimal_be_len_pairs_with_write_be_uint() {
237 let v = 0x00AB_CDEF_u128;
240 let n = minimal_be_len(v);
241 assert_eq!(n, 3);
242 let mut buf = [0u8; 16];
243 let mut w: &mut [u8] = &mut buf;
244 assert_eq!(write_be_uint(&mut w, v, minimal_be_len(v)).unwrap(), n);
245 assert_eq!(&buf[..n], &[0xAB, 0xCD, 0xEF]);
246 }
247}