podio/
lib.rs

1//! Additional methods for Read and Write
2//!
3//! The additional methods implemented allow reading and writing integers and floats
4//! in the specified endianness.
5//!
6//! # Usage
7//!
8//! Basically, you need to `use` the trait WritePodExt or ReadPodExt.
9//!
10//! # Examples
11//!
12//! ## Reading
13//!
14//! To read some value from a reader, import ReadPodExt and the needed endianness.
15//!
16//! ```
17//! use podio::{ReadPodExt, BigEndian};
18//!
19//! let slice: &[u8] = &[0x10, 0x20, 0x30, 0x40];
20//! let mut reader = std::io::Cursor::new(slice);
21//!
22//! let value = reader.read_u32::<BigEndian>().unwrap();
23//!
24//! assert_eq!(value, 0x10203040);
25//! ```
26//!
27//! ## Writing
28//!
29//! For writing, you need to import the trait WritePodExt.
30//!
31//! ```
32//! use podio::{WritePodExt, LittleEndian};
33//!
34//! let slice: &mut [u8] = &mut [0; 2];
35//! let mut writer = std::io::Cursor::new(slice);
36//!
37//! writer.write_u16::<LittleEndian>(0x8802).unwrap();
38//!
39//! assert_eq!(writer.into_inner(), &[0x02, 0x88]);
40//! ```
41//!
42//! ## Read exact
43//!
44//! One additional method, not really dealing with POD, is `read_exact`.
45//!
46//! ```
47//! use podio::ReadPodExt;
48//!
49//! let slice: &[u8] = &[0, 1, 2, 3];
50//! let mut reader = std::io::Cursor::new(slice);
51//!
52//! assert_eq!(reader.read_exact(1).unwrap(), [0]);
53//! assert_eq!(reader.read_exact(2).unwrap(), [1,2]);
54//! assert_eq!(reader.read_exact(0).unwrap(), []);
55//! assert_eq!(reader.read_exact(1).unwrap(), [3]);
56//! assert!(reader.read_exact(1).is_err());
57
58#![warn(missing_docs)]
59
60use std::io;
61use std::io::prelude::*;
62
63/// Little endian. The number `0xABCD` is stored `[0xCD, 0xAB]`
64pub enum LittleEndian {}
65/// Big endian. The number `0xABCD` is stored `[0xAB, 0xCD]`
66pub enum BigEndian {}
67
68/// Trait to determine the conversion methods for a specific endianness
69pub trait Endianness {
70    /// Converts a value between little-endian and the specified endianness
71    fn is_little_endian() -> bool;
72}
73
74/// Additional write methods for a io::Write
75pub trait WritePodExt {
76    /// Write a u64
77    fn write_u64<T: Endianness>(&mut self, u64) -> io::Result<()>;
78    /// Write a u32
79    fn write_u32<T: Endianness>(&mut self, u32) -> io::Result<()>;
80    /// Write a u16
81    fn write_u16<T: Endianness>(&mut self, u16) -> io::Result<()>;
82    /// Write a u8
83    fn write_u8(&mut self, u8) -> io::Result<()>;
84    /// Write a i64
85    fn write_i64<T: Endianness>(&mut self, i64) -> io::Result<()>;
86    /// Write a i32
87    fn write_i32<T: Endianness>(&mut self, i32) -> io::Result<()>;
88    /// Write a i16
89    fn write_i16<T: Endianness>(&mut self, i16) -> io::Result<()>;
90    /// Write a i8
91    fn write_i8(&mut self, i8) -> io::Result<()>;
92    /// Write a f32
93    fn write_f32<T: Endianness>(&mut self, f32) -> io::Result<()>;
94    /// Write a f64
95    fn write_f64<T: Endianness>(&mut self, f64) -> io::Result<()>;
96}
97
98/// Additional read methods for a io::Read
99pub trait ReadPodExt {
100    /// Read a u64
101    fn read_u64<T: Endianness>(&mut self) -> io::Result<u64>;
102    /// Read a u32
103    fn read_u32<T: Endianness>(&mut self) -> io::Result<u32>;
104    /// Read a u16
105    fn read_u16<T: Endianness>(&mut self) -> io::Result<u16>;
106    /// Read a u8
107    fn read_u8(&mut self) -> io::Result<u8>;
108    /// Read a i64
109    fn read_i64<T: Endianness>(&mut self) -> io::Result<i64>;
110    /// Read a i32
111    fn read_i32<T: Endianness>(&mut self) -> io::Result<i32>;
112    /// Read a i16
113    fn read_i16<T: Endianness>(&mut self) -> io::Result<i16>;
114    /// Read a i8
115    fn read_i8(&mut self) -> io::Result<i8>;
116    /// Read a f32
117    fn read_f32<T: Endianness>(&mut self) -> io::Result<f32>;
118    /// Read a f64
119    fn read_f64<T: Endianness>(&mut self) -> io::Result<f64>;
120    /// Read a specific number of bytes
121    fn read_exact(&mut self, usize) -> io::Result<Vec<u8>>;
122}
123
124impl Endianness for LittleEndian {
125    fn is_little_endian() -> bool {
126        true
127    }
128}
129
130impl Endianness for BigEndian {
131    fn is_little_endian() -> bool {
132        false
133    }
134}
135
136impl<W: Write> WritePodExt for W {
137    fn write_u64<T: Endianness>(&mut self, val: u64) -> io::Result<()> {
138        let buf = match <T as Endianness>::is_little_endian() {
139            true => u64::to_le_bytes(val),
140            false => u64::to_be_bytes(val),
141        };
142        self.write_all(&buf)
143    }
144
145    fn write_u32<T: Endianness>(&mut self, val: u32) -> io::Result<()> {
146        let buf = match <T as Endianness>::is_little_endian() {
147            true => u32::to_le_bytes(val),
148            false => u32::to_be_bytes(val),
149        };
150        self.write_all(&buf)
151    }
152
153    fn write_u16<T: Endianness>(&mut self, val: u16) -> io::Result<()> {
154        let buf = match <T as Endianness>::is_little_endian() {
155            true => u16::to_le_bytes(val),
156            false => u16::to_be_bytes(val),
157        };
158        self.write_all(&buf)
159    }
160
161    fn write_u8(&mut self, val: u8) -> io::Result<()> {
162        self.write_all(&[val])
163    }
164
165    fn write_i64<T: Endianness>(&mut self, val: i64) -> io::Result<()> {
166        self.write_u64::<T>(val as u64)
167    }
168
169    fn write_i32<T: Endianness>(&mut self, val: i32) -> io::Result<()> {
170        self.write_u32::<T>(val as u32)
171    }
172
173    fn write_i16<T: Endianness>(&mut self, val: i16) -> io::Result<()> {
174        self.write_u16::<T>(val as u16)
175    }
176
177    fn write_i8(&mut self, val: i8) -> io::Result<()> {
178        self.write_u8(val as u8)
179    }
180
181    fn write_f32<T: Endianness>(&mut self, val: f32) -> io::Result<()> {
182        let tval: u32 = val.to_bits();
183        self.write_u32::<T>(tval)
184    }
185
186    fn write_f64<T: Endianness>(&mut self, val: f64) -> io::Result<()> {
187        let tval: u64 = val.to_bits();
188        self.write_u64::<T>(tval)
189    }
190}
191
192#[inline]
193fn fill_buf<R: Read>(reader: &mut R, buf: &mut [u8]) -> io::Result<()> {
194    let mut idx = 0;
195    while idx != buf.len() {
196        match reader.read(&mut buf[idx..]) {
197            Ok(0) => return Err(io::Error::new(io::ErrorKind::Other, "Could not read enough bytes")),
198            Ok(v) => { idx += v; }
199            Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
200            Err(e) => return Err(e),
201        }
202    }
203    Ok(())
204}
205
206impl<R: Read> ReadPodExt for R {
207    fn read_u64<T: Endianness>(&mut self) -> io::Result<u64> {
208        let mut buf = [0u8; 8];
209        fill_buf(self, &mut buf)?;
210        let val = match <T as Endianness>::is_little_endian() {
211            true => u64::from_le_bytes(buf),
212            false => u64::from_be_bytes(buf),
213        };
214        Ok(val)
215    }
216
217    fn read_u32<T: Endianness>(&mut self) -> io::Result<u32> {
218        let mut buf = [0u8; 4];
219        fill_buf(self, &mut buf)?;
220        let val = match <T as Endianness>::is_little_endian() {
221            true => u32::from_le_bytes(buf),
222            false => u32::from_be_bytes(buf),
223        };
224        Ok(val)
225    }
226
227    fn read_u16<T: Endianness>(&mut self) -> io::Result<u16> {
228        let mut buf = [0u8; 2];
229        fill_buf(self, &mut buf)?;
230        let val = match <T as Endianness>::is_little_endian() {
231            true => u16::from_le_bytes(buf),
232            false => u16::from_be_bytes(buf),
233        };
234        Ok(val)
235    }
236
237    fn read_u8(&mut self) -> io::Result<u8> {
238        let buf = &mut [0u8; 1];
239        fill_buf(self, buf)?;
240        Ok(buf[0])
241    }
242
243    fn read_i64<T: Endianness>(&mut self) -> io::Result<i64> {
244        self.read_u64::<T>().map(|v| v as i64)
245    }
246
247    fn read_i32<T: Endianness>(&mut self) -> io::Result<i32> {
248        self.read_u32::<T>().map(|v| v as i32)
249    }
250
251    fn read_i16<T: Endianness>(&mut self) -> io::Result<i16> {
252        self.read_u16::<T>().map(|v| v as i16)
253    }
254
255    fn read_i8(&mut self) -> io::Result<i8> {
256        self.read_u8().map(|v| v as i8)
257    }
258
259    fn read_f64<T: Endianness>(&mut self) -> io::Result<f64> {
260        self.read_u64::<T>().map(|v| f64::from_bits(v))
261    }
262
263    fn read_f32<T: Endianness>(&mut self) -> io::Result<f32> {
264        self.read_u32::<T>().map(|v| f32::from_bits(v))
265    }
266
267    fn read_exact(&mut self, len: usize) -> io::Result<Vec<u8>> {
268        let mut res = vec![0; len];
269        fill_buf(self, &mut res)?;
270        Ok(res)
271    }
272}