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 {}