1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/*!
read-primitives provides traits to read primitive types from any type that implements [`std::io::Read`](https://doc.rust-lang.org/std/io/trait.Read.html)

 # Examples

```
    use read_primitives::ReadF64;
    let bytes: [u8; 8] = [24, 45, 68, 84, 251, 33, 9, 64];
    let float = bytes.as_slice().read_le_f64().unwrap();
    assert_eq!(std::f64::consts::PI, float)
```
*/

use std::io::{self, Read};

macro_rules! impl_traits {
    ($($type:ty),+) => {
        $(
            ::paste::paste!{
                #[doc = "Trait to read "$type "."]
                #[doc = "# Errors"]
                #[doc = "errors exactly when [`Read::read_exact`](https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact) errors"]
                pub trait [<Read $type:camel>]: Read {
                    #[doc = "Read " $type "in native byte order"]
                    fn [<read_ne_  $type>](&mut self) -> io::Result<$type> {
                        let mut bytes = [0u8; std::mem::size_of::<$type>()];
                        self.read_exact(&mut bytes)?;
                        Ok($type::from_ne_bytes(bytes))
                    }
                    #[doc = "Read " $type "in little endian byte order"]
                    #[doc = "# Errors"]
                    #[doc = "errors exactly when [`Read::read_exact`](https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact) errors"]
                    fn [<read_le_  $type>](&mut self) -> io::Result<$type> {
                        let mut bytes = [0u8; std::mem::size_of::<$type>()];
                        self.read_exact(&mut bytes)?;
                        Ok($type::from_le_bytes(bytes))
                    }
                    #[doc = "Read " $type "in big endian byte order"]
                    #[doc = "# Errors"]
                    #[doc = "errors exactly when [`Read::read_exact`](https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact) errors"]
                    fn [<read_be_  $type>](&mut self) -> io::Result<$type> {
                        let mut bytes = [0u8; std::mem::size_of::<$type>()];
                        self.read_exact(&mut bytes)?;
                        Ok($type::from_be_bytes(bytes))
                    }
                }
                impl<T:Read> [<Read $type:camel>] for T{}
            }
        )+
    };
}

impl_traits!(u16, i16, u32, i32, u64, i64, u128, i128, usize, isize, f32, f64);

/// Trait to read u8
pub trait ReadU8: Read {
    /// Read a u8
    /// # Errors
    /// errors exactly when [`Read::read_exact`](https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact) errors
    fn read_u8(&mut self) -> io::Result<u8> {
        let mut bytes = [0u8; 1];
        self.read_exact(&mut bytes)?;
        Ok(u8::from_ne_bytes(bytes))
    }
}
impl<R> ReadU8 for R where R: Read {}

/// Trait to read char
pub trait ReadChar: Read {
    /// Read a char
    ///  It is a assumed that the char is represented in native byte order
    /// # Errors
    /// errors exactly when [`Read::read_exact`](https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact) errors
    fn read_char(&mut self) -> io::Result<Option<char>> {
        let mut bytes = [0u8; 4];
        self.read_exact(&mut bytes)?;
        Ok(char::from_u32(u32::from_ne_bytes(bytes)))
    }
}
impl<R> ReadChar for R where R: Read {}

/// Trait to read bool
pub trait ReadBool: Read {
    /// Read a bool
    /// # Errors
    /// errors exactly when [`Read::read_exact`](https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact) errors
    fn read_bool(&mut self) -> io::Result<bool> {
        let mut bytes = [0u8; 1];
        self.read_exact(&mut bytes)?;
        Ok(u8::from_ne_bytes(bytes) != 0)
    }
}
impl<R> ReadBool for R where R: Read {}

#[cfg(test)]
mod test {
    use crate::*;

    macro_rules! impl_tests {
        ($($type:ty),+) => {
            $(
                ::paste::paste! {
                    #[test]
                    fn [<read_ne_ $type>]() {
                        let bytes = [<37 $type>].to_ne_bytes();
                        let number = bytes.as_slice().[<read_ne_ $type>]().unwrap();
                        assert_eq!([<37 $type>], number)
                    }
                }
                ::paste::paste! {
                    #[test]
                    fn [<read_le_ $type>]() {
                        let bytes = [<37 $type>].to_le_bytes();
                        let number = bytes.as_slice().[<read_le_ $type>]().unwrap();
                        assert_eq!([<37 $type>], number)
                    }
                }
                ::paste::paste! {
                    #[test]
                    fn [<read_be_ $type>]() {
                        let bytes = [<37 $type>].to_be_bytes();
                        let number = bytes.as_slice().[<read_be_ $type>]().unwrap();
                        assert_eq!([<37 $type>], number)
                    }
                }
            )+
        };
    }
    impl_tests!(u16, i16, u32, i32, u64, i64, u128, i128, usize, isize, f32, f64);

    #[test]
    fn read_u8() {
        let bytes = 37u8.to_ne_bytes();
        let byte = bytes.as_slice().read_u8().unwrap();
        assert_eq!(37, byte)
    }
}