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
60 use std::io;
61 use std::io::prelude::*;
62
63 /// Little endian. The number `0xABCD` is stored `[0xCD, 0xAB]`
64 pub enum LittleEndian {}
65 /// Big endian. The number `0xABCD` is stored `[0xAB, 0xCD]`
66 pub enum BigEndian {}
67
68 /// Trait implementing conversion methods for a specific endianness
69 pub trait Endianness {
70 /// Converts a value from the platform type to the specified endianness
int_to_target<T: EndianConvert>(val: T) -> T71 fn int_to_target<T: EndianConvert>(val: T) -> T;
72 /// Converts a value from the sepcified endianness to the platform type
int_from_target<T: EndianConvert>(val: T) -> T73 fn int_from_target<T: EndianConvert>(val: T) -> T;
74 }
75
76 /// Generic trait for endian conversions on integers
77 pub trait EndianConvert {
78 /// Convert self to a big-endian value
to_be(self) -> Self79 fn to_be(self) -> Self;
80 /// Convert self to a little-endian value
to_le(self) -> Self81 fn to_le(self) -> Self;
82 /// Convert a big-endian value to the target endianness
from_be(x: Self) -> Self83 fn from_be(x: Self) -> Self;
84 /// Convert a little-endian value to the target endiannes
from_le(x: Self) -> Self85 fn from_le(x: Self) -> Self;
86 }
87
88 /// Additional write methods for a io::Write
89 pub trait WritePodExt {
90 /// Write a u64
write_u64<T: Endianness>(&mut self, u64) -> io::Result<()>91 fn write_u64<T: Endianness>(&mut self, u64) -> io::Result<()>;
92 /// Write a u32
write_u32<T: Endianness>(&mut self, u32) -> io::Result<()>93 fn write_u32<T: Endianness>(&mut self, u32) -> io::Result<()>;
94 /// Write a u16
write_u16<T: Endianness>(&mut self, u16) -> io::Result<()>95 fn write_u16<T: Endianness>(&mut self, u16) -> io::Result<()>;
96 /// Write a u8
write_u8(&mut self, u8) -> io::Result<()>97 fn write_u8(&mut self, u8) -> io::Result<()>;
98 /// Write a i64
write_i64<T: Endianness>(&mut self, i64) -> io::Result<()>99 fn write_i64<T: Endianness>(&mut self, i64) -> io::Result<()>;
100 /// Write a i32
write_i32<T: Endianness>(&mut self, i32) -> io::Result<()>101 fn write_i32<T: Endianness>(&mut self, i32) -> io::Result<()>;
102 /// Write a i16
write_i16<T: Endianness>(&mut self, i16) -> io::Result<()>103 fn write_i16<T: Endianness>(&mut self, i16) -> io::Result<()>;
104 /// Write a i8
write_i8(&mut self, i8) -> io::Result<()>105 fn write_i8(&mut self, i8) -> io::Result<()>;
106 /// Write a f32
write_f32<T: Endianness>(&mut self, f32) -> io::Result<()>107 fn write_f32<T: Endianness>(&mut self, f32) -> io::Result<()>;
108 /// Write a f64
write_f64<T: Endianness>(&mut self, f64) -> io::Result<()>109 fn write_f64<T: Endianness>(&mut self, f64) -> io::Result<()>;
110 }
111
112 /// Additional read methods for a io::Read
113 pub trait ReadPodExt {
114 /// Read a u64
read_u64<T: Endianness>(&mut self) -> io::Result<u64>115 fn read_u64<T: Endianness>(&mut self) -> io::Result<u64>;
116 /// Read a u32
read_u32<T: Endianness>(&mut self) -> io::Result<u32>117 fn read_u32<T: Endianness>(&mut self) -> io::Result<u32>;
118 /// Read a u16
read_u16<T: Endianness>(&mut self) -> io::Result<u16>119 fn read_u16<T: Endianness>(&mut self) -> io::Result<u16>;
120 /// Read a u8
read_u8(&mut self) -> io::Result<u8>121 fn read_u8(&mut self) -> io::Result<u8>;
122 /// Read a i64
read_i64<T: Endianness>(&mut self) -> io::Result<i64>123 fn read_i64<T: Endianness>(&mut self) -> io::Result<i64>;
124 /// Read a i32
read_i32<T: Endianness>(&mut self) -> io::Result<i32>125 fn read_i32<T: Endianness>(&mut self) -> io::Result<i32>;
126 /// Read a i16
read_i16<T: Endianness>(&mut self) -> io::Result<i16>127 fn read_i16<T: Endianness>(&mut self) -> io::Result<i16>;
128 /// Read a i8
read_i8(&mut self) -> io::Result<i8>129 fn read_i8(&mut self) -> io::Result<i8>;
130 /// Read a f32
read_f32<T: Endianness>(&mut self) -> io::Result<f32>131 fn read_f32<T: Endianness>(&mut self) -> io::Result<f32>;
132 /// Read a f64
read_f64<T: Endianness>(&mut self) -> io::Result<f64>133 fn read_f64<T: Endianness>(&mut self) -> io::Result<f64>;
134 /// Read a specific number of bytes
read_exact(&mut self, usize) -> io::Result<Vec<u8>>135 fn read_exact(&mut self, usize) -> io::Result<Vec<u8>>;
136 }
137
138 impl Endianness for LittleEndian {
139 #[inline]
int_to_target<T: EndianConvert>(val: T) -> T140 fn int_to_target<T: EndianConvert>(val: T) -> T {
141 val.to_le()
142 }
143 #[inline]
int_from_target<T: EndianConvert>(val: T) -> T144 fn int_from_target<T: EndianConvert>(val: T) -> T {
145 <T as EndianConvert>::from_le(val)
146 }
147 }
148
149 impl Endianness for BigEndian {
150 #[inline]
int_to_target<T: EndianConvert>(val: T) -> T151 fn int_to_target<T: EndianConvert>(val: T) -> T {
152 val.to_be()
153 }
154 #[inline]
int_from_target<T: EndianConvert>(val: T) -> T155 fn int_from_target<T: EndianConvert>(val: T) -> T {
156 <T as EndianConvert>::from_be(val)
157 }
158 }
159
160 macro_rules! impl_platform_convert {
161 ($T:ty) => {
162 impl EndianConvert for $T {
163 #[inline]
164 fn to_be(self) -> $T {
165 self.to_be()
166 }
167
168 #[inline]
169 fn to_le(self) -> $T {
170 self.to_le()
171 }
172
173 #[inline]
174 fn from_be(x: $T) -> $T {
175 if cfg!(target_endian = "big") { x } else { x.swap_bytes() }
176 }
177
178 #[inline]
179 fn from_le(x: $T) -> $T {
180 if cfg!(target_endian = "little") { x } else { x.swap_bytes() }
181 }
182 }
183 };
184 }
185
186 impl_platform_convert!(u8);
187 impl_platform_convert!(u16);
188 impl_platform_convert!(u32);
189 impl_platform_convert!(u64);
190
191 #[cfg(target_endian = "little")]
192 macro_rules! val_to_buf {
193 ($val:ident, $T:expr) => {
194 {
195 let mut buf = [0; $T];
196 for i in 0..buf.len() {
197 buf[i] = ($val >> (i * 8)) as u8;
198 }
199 buf
200 }
201 };
202 }
203
204 #[cfg(target_endian = "big")]
205 macro_rules! val_to_buf {
206 ($val:ident, $T:expr) => {
207 {
208 let mut buf = [0; $T];
209 for i in 0..buf.len() {
210 buf[buf.len() - 1 - i] = ($val >> (i * 8)) as u8;
211 }
212 buf
213 }
214 };
215 }
216
217 impl<W: Write> WritePodExt for W {
write_u64<T: Endianness>(&mut self, val: u64) -> io::Result<()>218 fn write_u64<T: Endianness>(&mut self, val: u64) -> io::Result<()> {
219 let tval = <T as Endianness>::int_to_target(val);
220 let buf = val_to_buf!(tval, 8);
221 self.write_all(&buf)
222 }
223
write_u32<T: Endianness>(&mut self, val: u32) -> io::Result<()>224 fn write_u32<T: Endianness>(&mut self, val: u32) -> io::Result<()> {
225 let tval = <T as Endianness>::int_to_target(val);
226 let buf = val_to_buf!(tval, 4);
227 self.write_all(&buf)
228 }
229
write_u16<T: Endianness>(&mut self, val: u16) -> io::Result<()>230 fn write_u16<T: Endianness>(&mut self, val: u16) -> io::Result<()> {
231 let tval = <T as Endianness>::int_to_target(val);
232 let buf = val_to_buf!(tval, 2);
233 self.write_all(&buf)
234 }
235
write_u8(&mut self, val: u8) -> io::Result<()>236 fn write_u8(&mut self, val: u8) -> io::Result<()> {
237 self.write_all(&[val])
238 }
239
write_i64<T: Endianness>(&mut self, val: i64) -> io::Result<()>240 fn write_i64<T: Endianness>(&mut self, val: i64) -> io::Result<()> {
241 self.write_u64::<T>(val as u64)
242 }
243
write_i32<T: Endianness>(&mut self, val: i32) -> io::Result<()>244 fn write_i32<T: Endianness>(&mut self, val: i32) -> io::Result<()> {
245 self.write_u32::<T>(val as u32)
246 }
247
write_i16<T: Endianness>(&mut self, val: i16) -> io::Result<()>248 fn write_i16<T: Endianness>(&mut self, val: i16) -> io::Result<()> {
249 self.write_u16::<T>(val as u16)
250 }
251
write_i8(&mut self, val: i8) -> io::Result<()>252 fn write_i8(&mut self, val: i8) -> io::Result<()> {
253 self.write_u8(val as u8)
254 }
255
write_f32<T: Endianness>(&mut self, val: f32) -> io::Result<()>256 fn write_f32<T: Endianness>(&mut self, val: f32) -> io::Result<()> {
257 let tval: u32 = val.to_bits();
258 self.write_u32::<T>(tval)
259 }
260
write_f64<T: Endianness>(&mut self, val: f64) -> io::Result<()>261 fn write_f64<T: Endianness>(&mut self, val: f64) -> io::Result<()> {
262 let tval: u64 = val.to_bits();
263 self.write_u64::<T>(tval)
264 }
265 }
266
267 #[inline]
fill_buf<R: Read>(reader: &mut R, buf: &mut [u8]) -> io::Result<()>268 fn fill_buf<R: Read>(reader: &mut R, buf: &mut [u8]) -> io::Result<()> {
269 let mut idx = 0;
270 while idx != buf.len() {
271 match reader.read(&mut buf[idx..]) {
272 Ok(0) => return Err(io::Error::new(io::ErrorKind::Other, "Could not read enough bytes")),
273 Ok(v) => { idx += v; }
274 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
275 Err(e) => return Err(e),
276 }
277 }
278 Ok(())
279 }
280
281 #[cfg(target_endian = "little")]
282 macro_rules! buf_to_val {
283 ($buf:ident, $T:ty) => {
284 {
285 let mut val: $T = 0;
286 for i in 0..$buf.len() {
287 val |= ($buf[i] as $T) << (i * 8);
288 }
289 val
290 }
291 };
292 }
293
294 #[cfg(target_endian = "big")]
295 macro_rules! buf_to_val {
296 ($buf:ident, $T:ty) => {
297 {
298 let mut val: $T = 0;
299 for i in 0..$buf.len() {
300 val |= ($buf[$buf.len() - 1 - i] as $T) << (i * 8);
301 }
302 val
303 }
304 };
305 }
306
307 impl<R: Read> ReadPodExt for R {
read_u64<T: Endianness>(&mut self) -> io::Result<u64>308 fn read_u64<T: Endianness>(&mut self) -> io::Result<u64> {
309 let buf = &mut [0u8; 8];
310 try!(fill_buf(self, buf));
311 let tval = buf_to_val!(buf, u64);
312 Ok(<T as Endianness>::int_from_target(tval))
313 }
314
read_u32<T: Endianness>(&mut self) -> io::Result<u32>315 fn read_u32<T: Endianness>(&mut self) -> io::Result<u32> {
316 let buf = &mut [0u8; 4];
317 try!(fill_buf(self, buf));
318 let tval = buf_to_val!(buf, u32);
319 Ok(<T as Endianness>::int_from_target(tval))
320 }
321
read_u16<T: Endianness>(&mut self) -> io::Result<u16>322 fn read_u16<T: Endianness>(&mut self) -> io::Result<u16> {
323 let buf = &mut [0u8; 2];
324 try!(fill_buf(self, buf));
325 let tval = buf_to_val!(buf, u16);
326 Ok(<T as Endianness>::int_from_target(tval))
327 }
328
read_u8(&mut self) -> io::Result<u8>329 fn read_u8(&mut self) -> io::Result<u8> {
330 let buf = &mut [0u8; 1];
331 try!(fill_buf(self, buf));
332 Ok(buf[0])
333 }
334
read_i64<T: Endianness>(&mut self) -> io::Result<i64>335 fn read_i64<T: Endianness>(&mut self) -> io::Result<i64> {
336 self.read_u64::<T>().map(|v| v as i64)
337 }
338
read_i32<T: Endianness>(&mut self) -> io::Result<i32>339 fn read_i32<T: Endianness>(&mut self) -> io::Result<i32> {
340 self.read_u32::<T>().map(|v| v as i32)
341 }
342
read_i16<T: Endianness>(&mut self) -> io::Result<i16>343 fn read_i16<T: Endianness>(&mut self) -> io::Result<i16> {
344 self.read_u16::<T>().map(|v| v as i16)
345 }
346
read_i8(&mut self) -> io::Result<i8>347 fn read_i8(&mut self) -> io::Result<i8> {
348 self.read_u8().map(|v| v as i8)
349 }
350
read_f64<T: Endianness>(&mut self) -> io::Result<f64>351 fn read_f64<T: Endianness>(&mut self) -> io::Result<f64> {
352 self.read_u64::<T>().map(|v| f64::from_bits(v))
353 }
354
read_f32<T: Endianness>(&mut self) -> io::Result<f32>355 fn read_f32<T: Endianness>(&mut self) -> io::Result<f32> {
356 self.read_u32::<T>().map(|v| f32::from_bits(v))
357 }
358
read_exact(&mut self, len: usize) -> io::Result<Vec<u8>>359 fn read_exact(&mut self, len: usize) -> io::Result<Vec<u8>> {
360 let mut res = vec![0; len];
361 try!(fill_buf(self, &mut res));
362 Ok(res)
363 }
364 }
365