rw_exact_ext/
lib.rs

1use std::io::{Read, Result, Write};
2
3pub trait ReadExactExt: Read {
4    /// Read a byte array of a constant size.
5    ///
6    /// For further semantics please refer to [`Read::read_exact`].
7    ///
8    /// # Examples
9    /// ```
10    /// use rw_exact_ext::ReadExactExt;
11    /// use std::io::Cursor;
12    ///
13    /// let bytes = [0xAB, 0xCD, 0xEF, 0x42];
14    /// let array: [u8; 4] = Cursor::new(&bytes).read_array_exact().unwrap();
15    /// assert_eq!(array, bytes);
16    /// ```
17    #[allow(clippy::missing_errors_doc)]
18    fn read_array_exact<const SIZE: usize>(&mut self) -> Result<[u8; SIZE]> {
19        let mut buffer = [0; SIZE];
20        self.read_exact(&mut buffer)?;
21        Ok(buffer)
22    }
23
24    /// Read one byte and interpret it as a `bool`.
25    ///
26    /// Returns `true` if the read byte is non-zero, or `false` otherwise.
27    ///
28    /// For further semantics please refer to [`Read::read_exact`].
29    ///
30    /// # Examples
31    /// ```
32    /// use rw_exact_ext::ReadExactExt;
33    /// use std::io::Cursor;
34    ///
35    /// let bytes = [0x01, 0x00, 0xEF, 0x42];
36    /// let mut cursor = Cursor::new(&bytes);
37    /// assert!(cursor.read_bool().unwrap());
38    /// assert!(!cursor.read_bool().unwrap());
39    /// assert!(cursor.read_bool().unwrap());
40    /// assert!(cursor.read_bool().unwrap());
41    /// ```
42    #[allow(clippy::missing_errors_doc)]
43    fn read_bool(&mut self) -> Result<bool> {
44        self.read_array_exact::<1>().map(|[byte]| byte != 0)
45    }
46
47    /// Read a `Vec<u8>` of a given size.
48    ///
49    /// For further semantics please refer to [`Read::read_exact`].
50    ///
51    /// # Examples
52    /// ```
53    /// use rw_exact_ext::ReadExactExt;
54    /// use std::io::Cursor;
55    ///
56    /// let bytes = [0xAB, 0xCD, 0xEF, 0x42];
57    /// let vec = Cursor::new(&bytes).read_vec_exact(bytes.len()).unwrap();
58    /// assert_eq!(vec, Vec::from(bytes));
59    /// ```
60    #[allow(clippy::missing_errors_doc)]
61    fn read_vec_exact(&mut self, size: usize) -> Result<Vec<u8>> {
62        let mut buffer = vec![0; size];
63        self.read_exact(&mut buffer)?;
64        Ok(buffer)
65    }
66
67    /// Read a `heapless::Vec<u8>` of a constant size.
68    ///
69    /// For further semantics please refer to [`Read::read_exact`].
70    ///
71    /// # Safety
72    /// Behaviour of this method is undefined, if `size` > `SIZE`.
73    ///
74    /// # Examples
75    /// ```
76    /// use rw_exact_ext::ReadExactExt;
77    /// use std::io::Cursor;
78    ///
79    /// let bytes = [0xAB, 0xCD, 0xEF, 0x42];
80    /// let vec: heapless::Vec<u8, 4> = unsafe { Cursor::new(&bytes).read_heapless_vec_exact(4).unwrap() };
81    /// eprintln!("Capacity: {}", vec.capacity());
82    /// eprintln!("Len: {}", vec.len());
83    /// assert_eq!(&vec, &bytes);
84    /// ```
85    #[allow(clippy::missing_errors_doc)]
86    #[cfg(feature = "heapless")]
87    unsafe fn read_heapless_vec_exact<const SIZE: usize>(
88        &mut self,
89        size: usize,
90    ) -> Result<heapless::Vec<u8, SIZE>> {
91        let mut vec = heapless::Vec::<u8, SIZE>::new();
92        vec.set_len(size);
93        self.read_exact(&mut vec)?;
94        Ok(vec)
95    }
96
97    /// Read a number from a byte array in big endian.
98    ///
99    /// For further semantics please refer to [`Read::read_exact`].
100    ///
101    /// # Examples
102    /// ```
103    /// use rw_exact_ext::ReadExactExt;
104    /// use std::io::Cursor;
105    ///
106    /// let bytes = [0xAB, 0xCD, 0xEF, 0x42];
107    ///
108    /// let unsigned: u32 = Cursor::new(&bytes).read_num_be().unwrap();
109    /// assert_eq!(unsigned, 0xABCDEF42);
110    ///
111    /// let signed: i32 = Cursor::new(&bytes).read_num_be().unwrap();
112    /// assert_eq!(signed, -0x543210BE);
113    ///
114    /// let float: f32 = Cursor::new(&bytes).read_num_be().unwrap();
115    /// assert_eq!(float, -1.4632533e-12);
116    /// ```
117    #[cfg(feature = "num-traits")]
118    #[allow(clippy::missing_errors_doc)]
119    fn read_num_be<N, const SIZE: usize>(&mut self) -> Result<N>
120    where
121        N: num_traits::FromBytes<Bytes = [u8; SIZE]>,
122    {
123        self.read_array_exact()
124            .map(|bytes| N::from_be_bytes(&bytes))
125    }
126
127    /// Read a number from a byte array in little endian.
128    ///
129    /// For further semantics please refer to [`Read::read_exact`].
130    ///
131    /// # Examples
132    /// ```
133    /// use rw_exact_ext::ReadExactExt;
134    /// use std::io::Cursor;
135    ///
136    /// let bytes = [0xAB, 0xCD, 0xEF, 0x42];
137    ///
138    /// let unsigned: u32 = Cursor::new(&bytes).read_num_le().unwrap();
139    /// assert_eq!(unsigned, 0x42EFCDAB);
140    ///
141    /// let signed: i32 = Cursor::new(&bytes).read_num_le().unwrap();
142    /// assert_eq!(signed, 0x42EFCDAB);
143    ///
144    /// let float: f32 = Cursor::new(&bytes).read_num_le().unwrap();
145    /// assert_eq!(float, 119.901695);
146    /// ```
147    #[cfg(feature = "num-traits")]
148    #[allow(clippy::missing_errors_doc)]
149    fn read_num_le<N, const SIZE: usize>(&mut self) -> Result<N>
150    where
151        N: num_traits::FromBytes<Bytes = [u8; SIZE]>,
152    {
153        self.read_array_exact()
154            .map(|bytes| N::from_le_bytes(&bytes))
155    }
156
157    /// Read a number from a byte array in native endianness.
158    ///
159    /// For further semantics please refer to [`Read::read_exact`].
160    #[cfg(feature = "num-traits")]
161    #[allow(clippy::missing_errors_doc)]
162    fn read_num_ne<N, const SIZE: usize>(&mut self) -> Result<N>
163    where
164        N: num_traits::FromBytes<Bytes = [u8; SIZE]>,
165    {
166        self.read_array_exact()
167            .map(|bytes| N::from_ne_bytes(&bytes))
168    }
169}
170
171impl<T> ReadExactExt for T where T: Read {}
172
173pub trait WriteAllExt: Write {
174    /// Write a `bool` as one byte.
175    ///
176    /// For further semantics please refer to [`Read::read_exact`].
177    ///
178    /// # Examples
179    /// ```
180    /// use rw_exact_ext::WriteAllExt;
181    /// use std::io::Cursor;
182    ///
183    /// let mut bytes = vec![0xFF];
184    ///
185    /// Cursor::new(&mut bytes).write_bool(true).unwrap();
186    /// assert_eq!(bytes, [0x01]);
187    ///
188    /// Cursor::new(&mut bytes).write_bool(false).unwrap();
189    /// assert_eq!(bytes, [0x00]);
190    /// ```
191    #[allow(clippy::missing_errors_doc)]
192    fn write_bool(&mut self, boolean: bool) -> Result<()> {
193        self.write_all(&[boolean.into()])
194    }
195
196    /// Write a number to bytes in big endian.
197    ///
198    /// For further semantics please refer to [`Write::write_all`].
199    ///
200    /// # Examples
201    /// ```
202    /// use rw_exact_ext::WriteAllExt;
203    /// use std::io::Cursor;
204    ///
205    /// let mut bytes = vec![0u8; 4];
206    ///
207    /// let unsigned: u32 = 1337;
208    /// Cursor::new(&mut bytes).write_num_be(unsigned).unwrap();
209    /// assert_eq!(bytes, vec![0x00, 0x00, 0x05, 0x39]);
210    ///
211    /// let signed: i32 = -1337;
212    /// Cursor::new(&mut bytes).write_num_be(signed).unwrap();
213    /// assert_eq!(bytes, vec![0xFF, 0xFF, 0xFA, 0xC7]);
214    ///
215    /// let float: f32 = 133.7;
216    /// Cursor::new(&mut bytes).write_num_be(float).unwrap();
217    /// assert_eq!(bytes, vec![0x43, 0x05, 0xB3, 0x33]);
218    /// ```
219    #[cfg(feature = "num-traits")]
220    #[allow(clippy::missing_errors_doc)]
221    fn write_num_be<N, const SIZE: usize>(&mut self, num: N) -> Result<()>
222    where
223        N: num_traits::ToBytes<Bytes = [u8; SIZE]>,
224    {
225        self.write_all(&num.to_be_bytes())
226    }
227
228    /// Write a number to bytes in little endian.
229    ///
230    /// For further semantics please refer to [`Write::write_all`].
231    ///
232    /// # Examples
233    /// ```
234    /// use rw_exact_ext::WriteAllExt;
235    /// use std::io::Cursor;
236    ///
237    /// let mut bytes = vec![0u8; 4];
238    ///
239    /// let unsigned: u32 = 1337;
240    /// Cursor::new(&mut bytes).write_num_le(unsigned).unwrap();
241    /// assert_eq!(bytes, vec![0x39, 0x05, 0x00, 0x00]);
242    ///
243    /// let signed: i32 = -1337;
244    /// Cursor::new(&mut bytes).write_num_le(signed).unwrap();
245    /// assert_eq!(bytes, vec![0xC7, 0xFA, 0xFF, 0xFF]);
246    ///
247    /// let float: f32 = 133.7;
248    /// Cursor::new(&mut bytes).write_num_le(float).unwrap();
249    /// assert_eq!(bytes, vec![0x33, 0xB3, 0x05, 0x43]);
250    /// ```
251    #[cfg(feature = "num-traits")]
252    #[allow(clippy::missing_errors_doc)]
253    fn write_num_le<N, const SIZE: usize>(&mut self, num: N) -> Result<()>
254    where
255        N: num_traits::ToBytes<Bytes = [u8; SIZE]>,
256    {
257        self.write_all(&num.to_le_bytes())
258    }
259
260    /// Write a number to bytes in native endianness.
261    ///
262    /// For further semantics please refer to [`Write::write_all`].
263    #[cfg(feature = "num-traits")]
264    #[allow(clippy::missing_errors_doc)]
265    fn write_num_ne<N, const SIZE: usize>(&mut self, num: N) -> Result<()>
266    where
267        N: num_traits::ToBytes<Bytes = [u8; SIZE]>,
268    {
269        self.write_all(&num.to_ne_bytes())
270    }
271}
272
273impl<T> WriteAllExt for T where T: Write {}