Skip to main content

simple_someip/protocol/
byte_order.rs

1use crate::protocol::Error;
2use embedded_io::Error as _;
3
4/// Extension trait for writing big-endian values to a byte stream.
5///
6/// The only required method is [`write_bytes`](WriteBytesExt::write_bytes).
7/// Backed by `embedded_io::Write` via a blanket impl.
8pub trait WriteBytesExt {
9    /// Write all bytes from `buf` to the stream.
10    ///
11    /// # Errors
12    /// Returns [`Error::Io`] if the underlying writer fails.
13    fn write_bytes(&mut self, buf: &[u8]) -> Result<(), Error>;
14
15    /// Write a single `u8`.
16    ///
17    /// # Errors
18    /// Returns [`Error::Io`] if the underlying writer fails.
19    fn write_u8(&mut self, val: u8) -> Result<(), Error> {
20        self.write_bytes(&[val])
21    }
22
23    /// Write an `i8`.
24    ///
25    /// # Errors
26    /// Returns [`Error::Io`] if the underlying writer fails.
27    fn write_i8(&mut self, val: i8) -> Result<(), Error> {
28        self.write_bytes(&[val.cast_unsigned()])
29    }
30
31    /// Write a `u16` in big-endian byte order.
32    ///
33    /// # Errors
34    /// Returns [`Error::Io`] if the underlying writer fails.
35    fn write_u16_be(&mut self, val: u16) -> Result<(), Error> {
36        self.write_bytes(&val.to_be_bytes())
37    }
38
39    /// Write an `i16` in big-endian byte order.
40    ///
41    /// # Errors
42    /// Returns [`Error::Io`] if the underlying writer fails.
43    fn write_i16_be(&mut self, val: i16) -> Result<(), Error> {
44        self.write_bytes(&val.to_be_bytes())
45    }
46
47    /// Write the lower 3 bytes of a `u32` in big-endian byte order.
48    ///
49    /// # Errors
50    /// Returns [`Error::Io`] if the underlying writer fails.
51    fn write_u24_be(&mut self, val: u32) -> Result<(), Error> {
52        self.write_bytes(&val.to_be_bytes()[1..])
53    }
54
55    /// Write a `u32` in big-endian byte order.
56    ///
57    /// # Errors
58    /// Returns [`Error::Io`] if the underlying writer fails.
59    fn write_u32_be(&mut self, val: u32) -> Result<(), Error> {
60        self.write_bytes(&val.to_be_bytes())
61    }
62
63    /// Write an `i32` in big-endian byte order.
64    ///
65    /// # Errors
66    /// Returns [`Error::Io`] if the underlying writer fails.
67    fn write_i32_be(&mut self, val: i32) -> Result<(), Error> {
68        self.write_bytes(&val.to_be_bytes())
69    }
70
71    /// Write a `u64` in big-endian byte order.
72    ///
73    /// # Errors
74    /// Returns [`Error::Io`] if the underlying writer fails.
75    fn write_u64_be(&mut self, val: u64) -> Result<(), Error> {
76        self.write_bytes(&val.to_be_bytes())
77    }
78
79    /// Write an `i64` in big-endian byte order.
80    ///
81    /// # Errors
82    /// Returns [`Error::Io`] if the underlying writer fails.
83    fn write_i64_be(&mut self, val: i64) -> Result<(), Error> {
84        self.write_bytes(&val.to_be_bytes())
85    }
86
87    /// Write a `u128` in big-endian byte order.
88    ///
89    /// # Errors
90    /// Returns [`Error::Io`] if the underlying writer fails.
91    fn write_u128_be(&mut self, val: u128) -> Result<(), Error> {
92        self.write_bytes(&val.to_be_bytes())
93    }
94
95    /// Write an `i128` in big-endian byte order.
96    ///
97    /// # Errors
98    /// Returns [`Error::Io`] if the underlying writer fails.
99    fn write_i128_be(&mut self, val: i128) -> Result<(), Error> {
100        self.write_bytes(&val.to_be_bytes())
101    }
102
103    /// Write an `f32` in big-endian byte order.
104    ///
105    /// # Errors
106    /// Returns [`Error::Io`] if the underlying writer fails.
107    fn write_f32_be(&mut self, val: f32) -> Result<(), Error> {
108        self.write_bytes(&val.to_be_bytes())
109    }
110
111    /// Write an `f64` in big-endian byte order.
112    ///
113    /// # Errors
114    /// Returns [`Error::Io`] if the underlying writer fails.
115    fn write_f64_be(&mut self, val: f64) -> Result<(), Error> {
116        self.write_bytes(&val.to_be_bytes())
117    }
118}
119
120impl<T: embedded_io::Write> WriteBytesExt for T {
121    fn write_bytes(&mut self, buf: &[u8]) -> Result<(), Error> {
122        self.write_all(buf).map_err(|e| Error::Io(e.kind()))
123    }
124}
125
126#[cfg(test)]
127// Strict float equality is correct here: these tests verify byte-level
128// encoding via `to_be_bytes`, where the result must be bitwise-identical
129// to the input.
130#[allow(clippy::float_cmp)]
131mod tests {
132    use super::*;
133
134    struct FailingWriter;
135
136    impl embedded_io::ErrorType for FailingWriter {
137        type Error = embedded_io::ErrorKind;
138    }
139
140    impl embedded_io::Write for FailingWriter {
141        fn write(&mut self, _buf: &[u8]) -> Result<usize, Self::Error> {
142            Err(embedded_io::ErrorKind::BrokenPipe)
143        }
144
145        fn flush(&mut self) -> Result<(), Self::Error> {
146            Ok(())
147        }
148    }
149
150    // --- Error mapping ---
151
152    #[test]
153    fn write_io_error_maps_to_error_io() {
154        assert!(matches!(
155            FailingWriter.write_u8(0),
156            Err(Error::Io(embedded_io::ErrorKind::BrokenPipe))
157        ));
158    }
159
160    // --- WriteBytesExt ---
161
162    #[test]
163    fn write_u8_encodes_correctly() {
164        let mut buf = [0u8; 1];
165        buf.as_mut_slice().write_u8(0xAB).unwrap();
166        assert_eq!(buf, [0xAB]);
167    }
168
169    #[test]
170    fn write_i8_encodes_correctly() {
171        let mut buf = [0u8; 1];
172        buf.as_mut_slice().write_i8(-1).unwrap();
173        assert_eq!(buf, [0xFF]);
174    }
175
176    #[test]
177    fn write_u16_be_encodes_correctly() {
178        let mut buf = [0u8; 2];
179        buf.as_mut_slice().write_u16_be(0x0102).unwrap();
180        assert_eq!(buf, [0x01, 0x02]);
181    }
182
183    #[test]
184    fn write_i16_be_encodes_correctly() {
185        let mut buf = [0u8; 2];
186        buf.as_mut_slice().write_i16_be(-2).unwrap();
187        assert_eq!(buf, [0xFF, 0xFE]);
188    }
189
190    #[test]
191    fn write_u24_be_encodes_correctly() {
192        let mut buf = [0u8; 3];
193        buf.as_mut_slice().write_u24_be(0x0001_0203).unwrap();
194        assert_eq!(buf, [0x01, 0x02, 0x03]);
195    }
196
197    #[test]
198    fn write_u32_be_encodes_correctly() {
199        let mut buf = [0u8; 4];
200        buf.as_mut_slice().write_u32_be(0x0102_0304).unwrap();
201        assert_eq!(buf, [0x01, 0x02, 0x03, 0x04]);
202    }
203
204    #[test]
205    fn write_i32_be_encodes_correctly() {
206        let mut buf = [0u8; 4];
207        buf.as_mut_slice().write_i32_be(-2).unwrap();
208        assert_eq!(buf, [0xFF, 0xFF, 0xFF, 0xFE]);
209    }
210
211    #[test]
212    fn write_u64_be_encodes_correctly() {
213        let mut buf = [0u8; 8];
214        buf.as_mut_slice()
215            .write_u64_be(0x0102_0304_0506_0708)
216            .unwrap();
217        assert_eq!(buf, [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]);
218    }
219
220    #[test]
221    fn write_i64_be_encodes_correctly() {
222        let mut buf = [0u8; 8];
223        buf.as_mut_slice().write_i64_be(-2).unwrap();
224        assert_eq!(buf, [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE]);
225    }
226
227    #[test]
228    fn write_u128_be_encodes_correctly() {
229        let mut buf = [0u8; 16];
230        buf.as_mut_slice().write_u128_be(1).unwrap();
231        assert_eq!(buf, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01]);
232    }
233
234    #[test]
235    fn write_i128_be_encodes_correctly() {
236        let mut buf = [0u8; 16];
237        buf.as_mut_slice().write_i128_be(-2).unwrap();
238        let expected = (-2_i128).to_be_bytes();
239        assert_eq!(buf, expected);
240    }
241
242    #[test]
243    fn write_f32_be_encodes_correctly() {
244        let val: f32 = 1.0;
245        let mut buf = [0u8; 4];
246        buf.as_mut_slice().write_f32_be(val).unwrap();
247        assert_eq!(buf, val.to_be_bytes());
248    }
249
250    #[test]
251    fn write_f64_be_encodes_correctly() {
252        let val: f64 = 1.0;
253        let mut buf = [0u8; 8];
254        buf.as_mut_slice().write_f64_be(val).unwrap();
255        assert_eq!(buf, val.to_be_bytes());
256    }
257}