typed_io/
read_bytes.rs

1use crate::Endianness;
2use std::io::{Error, ErrorKind, Read, Result};
3use std::mem;
4
5/// This trait is to read an endianness fixed-length bytes.
6pub trait ReadEndianness: Sized {
7    fn read_endianness_bytes_with_callback<F, R: Read>(
8        reader: &mut R,
9        callback: F,
10        endianness: Endianness,
11    ) -> Result<Self>
12    where
13        F: Fn(&mut [u8]);
14
15    /// This method reads bytes in big-endian byte order.
16    fn read_be_bytes<R: Read>(reader: &mut R) -> Result<Self> {
17        Self::read_endianness_bytes_with_callback(reader, |_| {}, Endianness::BE)
18    }
19    /// This method reads bytes in little-endian byte order.
20    fn read_le_bytes<R: Read>(reader: &mut R) -> Result<Self> {
21        Self::read_endianness_bytes_with_callback(reader, |_| {}, Endianness::LE)
22    }
23    /// This method reads bytes in native-endian byte order.
24    ///
25    /// As the target platform’s native endianness is used, portable code should use read_be_bytes or read_le_bytes, as appropriate, instead.
26    fn read_ne_bytes<R: Read>(reader: &mut R) -> Result<Self> {
27        Self::read_endianness_bytes_with_callback(reader, |_| {}, Endianness::NE)
28    }
29}
30
31macro_rules! read_endianness_impl {
32    ( $( $t:ty ),* ) => ($(
33        impl ReadEndianness for $t {
34            fn read_endianness_bytes_with_callback<F, R: Read>(reader: &mut R, callback: F, endianness: Endianness) -> Result<Self> where F: Fn(&mut [u8]) {
35                let mut buf = [0; mem::size_of::<$t>()];
36                reader.read_exact(&mut buf)?;
37                callback(&mut buf);
38                Ok(
39                match endianness {
40                    Endianness::BE => <$t>::from_be_bytes(buf),
41                    Endianness::LE => <$t>::from_le_bytes(buf),
42                    Endianness::NE => <$t>::from_ne_bytes(buf),
43                })
44            }
45        }
46    )*)
47}
48
49read_endianness_impl!(f32, f64);
50read_endianness_impl!(isize, i8, i16, i32, i64, i128);
51read_endianness_impl!(usize, u8, u16, u32, u64, u128);
52
53/// This trait is to read a variable-length array.
54pub trait ReadVariable: Sized {
55    fn read_variable_bytes_with_callback<F, R: Read>(
56        reader: &mut R,
57        callback: F,
58        length: usize,
59    ) -> Result<Self>
60    where
61        F: Fn(&mut [u8]);
62
63    fn read_variable_bytes<R: Read>(reader: &mut R, length: usize) -> Result<Self> {
64        Self::read_variable_bytes_with_callback(reader, |_| {}, length)
65    }
66}
67impl ReadVariable for Vec<u8> {
68    fn read_variable_bytes_with_callback<F, R: Read>(
69        reader: &mut R,
70        callback: F,
71        length: usize,
72    ) -> Result<Vec<u8>>
73    where
74        F: Fn(&mut [u8]),
75    {
76        let mut buf = vec![0; length];
77        reader.read_exact(&mut buf)?;
78        callback(&mut buf);
79        Ok(buf)
80    }
81}
82impl ReadVariable for String {
83    fn read_variable_bytes_with_callback<F, R: Read>(
84        reader: &mut R,
85        callback: F,
86        length: usize,
87    ) -> Result<String>
88    where
89        F: Fn(&mut [u8]),
90    {
91        let vec = Vec::<u8>::read_variable_bytes_with_callback(reader, callback, length)?;
92        let s = String::from_utf8(vec);
93        match s {
94            Ok(s) => Ok(s),
95            Err(e) => Err(Error::new(ErrorKind::InvalidData, e)),
96        }
97    }
98}
99
100/// This trait is to read a constant-length array.
101pub trait ReadConstant<const LENGTH: usize>: Sized {
102    fn read_constant_bytes_with_callback<F, R: Read>(reader: &mut R, callback: F) -> Result<Self>
103    where
104        F: Fn(&mut [u8]);
105
106    fn read_constant_bytes<R: Read>(reader: &mut R) -> Result<Self> {
107        Self::read_constant_bytes_with_callback(reader, |_| {})
108    }
109}
110impl<const LENGTH: usize> ReadConstant<LENGTH> for [u8; LENGTH] {
111    fn read_constant_bytes_with_callback<F, R: Read>(reader: &mut R, callback: F) -> Result<Self>
112    where
113        F: Fn(&mut [u8]),
114    {
115        let mut buf = [0; LENGTH];
116        reader.read_exact(&mut buf)?;
117        callback(&mut buf);
118        Ok(buf)
119    }
120}
121impl<const LENGTH: usize> ReadConstant<LENGTH> for String {
122    fn read_constant_bytes_with_callback<F, R: Read>(reader: &mut R, callback: F) -> Result<Self>
123    where
124        F: Fn(&mut [u8]),
125    {
126        let bytes = <[u8; LENGTH]>::read_constant_bytes_with_callback(reader, callback)?;
127        let s = String::from_utf8(bytes.to_vec());
128
129        match s {
130            Ok(s) => Ok(s),
131            Err(e) => Err(Error::new(ErrorKind::InvalidData, e)),
132        }
133    }
134}