read_from/lib.rs
1#![deny(unsafe_code)]
2/*!
3The [`ReadFrom`] and [`WriteTo`] traits.
4
5These traits allow you to represent the ability of a type to be serialized/
6deserialized into an arbitrary byte stream. Because there's no universal way to
7represent integers (outside of `u8` and `i8`), endian types are provided to
8explicitly denote the endianness when deserializing.
9
10# Serde
11This is not the same as [serde](https://docs.serde.rs/serde/)! Serde is used to
12serialize/deserialize types regardless of the data format. The [`ReadFrom`]/
13[`WriteTo`] traits are intended to be used at a lower-level, where details such
14as the ordering of bytes is important.
15*/
16
17use std::io::{self, Read, Write};
18use std::mem::size_of;
19
20/// Used to deserialize types from an input stream (i.e. a [`Read`]
21/// implementation).
22///
23/// # Example
24/// This implements [`ReadFrom`] for a simple `TinyRational` struct.
25/// ```rust
26/// use read_from::ReadFrom;
27/// use std::io::{self, Cursor, Read};
28///
29/// #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
30/// pub struct TinyRational {
31/// numer: i8,
32/// denom: u8
33/// }
34///
35/// #[derive(Debug)]
36/// pub enum TinyRationalReadError {
37/// DenomIsZero,
38/// Io(io::Error)
39/// }
40///
41/// impl ReadFrom for TinyRational {
42/// type Error = TinyRationalReadError;
43///
44/// fn read_from<R: Read>(mut inp: R) -> Result<Self, Self::Error> {
45/// let mut buf = [0; 2];
46/// inp.read_exact(&mut buf).map_err(TinyRationalReadError::Io)?;
47/// let numer = buf[0] as i8;
48/// let denom = buf[1] as u8;
49/// if denom == 0 {
50/// Err(TinyRationalReadError::DenomIsZero)
51/// } else {
52/// Ok(Self { numer, denom })
53/// }
54/// }
55/// }
56///
57/// assert_eq!(
58/// TinyRational::read_from(Cursor::new(&[3, 4])).unwrap(),
59/// TinyRational { numer: 3, denom: 4 });
60/// assert!(matches!(
61/// TinyRational::read_from(Cursor::new(&[3, 0])).unwrap_err(),
62/// TinyRationalReadError::DenomIsZero
63/// ));
64/// ```
65pub trait ReadFrom : Sized {
66 /// What error can happen when trying to read?
67 type Error;
68
69 /// Attempts to construct `Self` from the given input stream.
70 fn read_from<R: Read>(input: R) -> Result<Self, Self::Error>;
71}
72
73/// Used to serialize types into an output stream (i.e. a [`Write`]
74/// implementation).
75///
76/// # Example
77/// This implements [`WriteTo`] for a simple `TinyRational` struct.
78/// ```rust
79/// use read_from::WriteTo;
80/// use std::io::{self, Write};
81///
82/// #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
83/// pub struct TinyRational {
84/// numer: i8,
85/// denom: u8
86/// }
87///
88/// impl WriteTo for TinyRational {
89/// type Error = io::Error;
90///
91/// fn write_to<W: Write>(&self, mut out: W) -> Result<usize, Self::Error> {
92/// out.write_all(&[self.numer as u8, self.denom]).and(Ok(2))
93/// }
94/// }
95///
96/// let mut buf = Vec::new();
97/// TinyRational { numer: 3, denom: 4 }.write_to(&mut buf).unwrap();
98///
99/// assert_eq!(buf, &[3, 4]);
100/// ```
101pub trait WriteTo {
102 /// What error can happen when trying to write?
103 type Error;
104
105 /// Attempts to write `self` to the given output stream, returning the number
106 /// of bytes written on success.
107 fn write_to<W: Write>(&self, output: W) -> Result<usize, Self::Error>;
108}
109
110impl ReadFrom for u8 {
111 type Error = io::Error;
112
113 #[inline]
114 fn read_from<R: Read>(mut inp: R) -> Result<Self, Self::Error> {
115 let mut buf = [0; 1];
116 inp.read_exact(&mut buf)?;
117 let [byte] = buf;
118 Ok(byte)
119 }
120}
121
122impl ReadFrom for i8 {
123 type Error = io::Error;
124
125 #[inline]
126 fn read_from<R: Read>(mut inp: R) -> Result<Self, Self::Error> {
127 let mut buf = [0; 1];
128 inp.read_exact(&mut buf)?;
129 let [byte] = buf;
130 Ok(byte as _)
131 }
132}
133
134impl WriteTo for u8 {
135 type Error = io::Error;
136
137 #[inline]
138 fn write_to<W: Write>(&self, mut out: W) -> Result<usize, Self::Error> {
139 out.write_all(&[*self]).and(Ok(1))
140 }
141}
142
143impl WriteTo for i8 {
144 type Error = io::Error;
145
146 #[inline]
147 fn write_to<W: Write>(&self, mut out: W) -> Result<usize, Self::Error> {
148 out.write_all(&[*self as u8]).and(Ok(1))
149 }
150}
151
152macro_rules! impl_for_array {
153 ($($len:literal)*) => {
154 $(
155 impl ReadFrom for [u8; $len] {
156 type Error = io::Error;
157
158 fn read_from<R: Read>(mut inp: R) -> Result<Self, Self::Error> {
159 let mut buf = [0; $len];
160 inp.read_exact(&mut buf).and(Ok(buf))
161 }
162 }
163
164 impl WriteTo for [u8; $len] {
165 type Error = io::Error;
166
167 fn write_to<W: Write>(&self, mut out: W) -> Result<usize, Self::Error> {
168 out.write_all(self).and(Ok($len))
169 }
170 }
171 )*
172 };
173}
174
175impl_for_array!(
176 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
177 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
178 64 128 256 512 1024 2048 4096 8192
179 50 100 250 500 1000 2500 5000 10000
180);
181
182/// A type that can be used to read/write integers in a little-endian format.
183///
184/// # Example
185/// ```rust
186/// use read_from::{WriteTo, ReadFrom, LittleEndian};
187/// use std::io::Cursor;
188///
189/// let mut buf = vec![];
190/// LittleEndian(0xaabbccdd_u32).write_to(&mut buf).unwrap();
191/// assert_eq!(buf, [0xdd, 0xcc, 0xbb, 0xaa]);
192///
193/// let cursor = Cursor::new(&buf);
194/// assert_eq!(0xaabbccdd_u32, LittleEndian::read_from(cursor).unwrap().0);
195/// ```
196#[repr(transparent)]
197#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
198pub struct LittleEndian<T>(pub T);
199
200/// A type that can be used to deserialize integers in big-endian format.
201///
202/// # Example
203/// ```rust
204/// use read_from::{WriteTo, ReadFrom, BigEndian};
205/// use std::io::Cursor;
206///
207/// let mut buf = vec![];
208/// BigEndian(0xaabbccdd_u32).write_to(&mut buf).unwrap();
209/// assert_eq!(buf, [0xaa, 0xbb, 0xcc, 0xdd]);
210///
211/// let cursor = Cursor::new(&buf);
212/// assert_eq!(0xaabbccdd_u32, BigEndian::read_from(cursor).unwrap().0);
213/// ```
214#[repr(transparent)]
215#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
216pub struct BigEndian<T>(pub T);
217
218/// A type that can be used to deserialize integers in native-endian format.
219///
220/// # Example
221/// ```rust
222/// use read_from::{WriteTo, ReadFrom, NativeEndian};
223/// use std::io::Cursor;
224///
225/// let mut buf = vec![];
226/// NativeEndian(0xaabbccdd_u32).write_to(&mut buf).unwrap();
227///
228/// if cfg!(target_endian="little") {
229/// assert_eq!(buf, [0xdd, 0xcc, 0xbb, 0xaa]);
230/// } else {
231/// assert_eq!(buf, [0xaa, 0xbb, 0xcc, 0xdd]);
232/// }
233///
234/// let cursor = Cursor::new(&buf);
235/// assert_eq!(0xaabbccdd_u32, NativeEndian::read_from(cursor).unwrap().0);
236/// ```
237#[repr(transparent)]
238#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
239pub struct NativeEndian<T>(pub T);
240
241/// Network endianness is big endianness.
242pub type NetworkEndian<T> = BigEndian<T>;
243
244macro_rules! impl_endian_traits {
245 ($endian:ident $from_bytes:ident $to_bytes:ident; $($ty:ident)*) => {
246 $(
247 impl ReadFrom for $endian<$ty> {
248 type Error = io::Error;
249
250 fn read_from<R: Read>(mut inp: R) -> Result<Self, Self::Error> {
251 let mut buf = [0; size_of::<$ty>()];
252 inp.read_exact(&mut buf)?;
253 Ok(Self(<$ty>::$from_bytes(buf)))
254 }
255 }
256 )*
257 $(
258 impl WriteTo for $endian<$ty> {
259 type Error = io::Error;
260
261 fn write_to<W: Write>(&self, mut out: W)
262 -> Result<usize, Self::Error>
263 {
264 out.write_all(&self.0.$to_bytes()).and(Ok(size_of::<$ty>()))
265 }
266 }
267 )*
268
269 };
270 ($($ty:ident)*) => {
271 impl_endian_traits!(LittleEndian from_le_bytes to_le_bytes; $($ty)*);
272 impl_endian_traits!(BigEndian from_be_bytes to_be_bytes; $($ty)*);
273 impl_endian_traits!(NativeEndian from_ne_bytes to_ne_bytes; $($ty)*);
274 };
275}
276
277impl_endian_traits!(
278 u8 u16 u32 u64 u128 usize
279 i8 i16 i32 i64 i128 isize
280 f32 f64
281);
282
283// TODO: char
284