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