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
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub enum Endianness {
    LittleEndian,
    BigEndian
}

impl Endianness {
    #[cfg( target_endian = "little" )]
    pub const NATIVE: Endianness = Endianness::LittleEndian;

    #[cfg( target_endian = "big" )]
    pub const NATIVE: Endianness = Endianness::BigEndian;
}

impl Endianness {
    #[inline(always)]
    pub fn conversion_necessary( self ) -> bool {
        self != Endianness::NATIVE
    }

    #[inline(always)]
    pub fn swap_slice_u8( self, _: &mut [u8] ) {}

    #[inline(always)]
    pub fn swap_slice_i8( self, _: &mut [i8] ) {}
}

macro_rules! emit_wrapper {
    ($type:ty, $reader:ident, $swapper:ident, $slice_swapper:ident) => {
        impl Endianness {
            #[inline]
            pub fn $reader( self, slice: &[u8] ) -> $type {
                assert!( slice.len() == core::mem::size_of::< $type >() );

                let mut value: $type = 0;
                unsafe {
                    core::ptr::copy_nonoverlapping(
                        slice.as_ptr(),
                        &mut value as *mut $type as *mut u8,
                        core::mem::size_of::< $type >()
                    );
                }

                if self.conversion_necessary() {
                    value = value.swap_bytes();
                }

                value
            }

            #[inline]
            pub fn $swapper( self, value: &mut $type ) {
                if self.conversion_necessary() {
                    *value = value.swap_bytes();
                }
            }

            #[inline]
            pub fn $slice_swapper( self, slice: &mut [$type] ) {
                if self.conversion_necessary() {
                    for value in slice {
                        *value = value.swap_bytes();
                    }
                }
            }
        }
    }
}

emit_wrapper!( u16, read_u16, swap_u16, swap_slice_u16 );
emit_wrapper!( u32, read_u32, swap_u32, swap_slice_u32 );
emit_wrapper!( u64, read_u64, swap_u64, swap_slice_u64 );
emit_wrapper!( u128, read_u128, swap_u128, swap_slice_u128 );
emit_wrapper!( i16, read_i16, swap_i16, swap_slice_i16 );
emit_wrapper!( i32, read_i32, swap_i32, swap_slice_i32 );
emit_wrapper!( i64, read_i64, swap_i64, swap_slice_i64 );
emit_wrapper!( i128, read_i128, swap_i128, swap_slice_i128 );

impl Endianness {
    #[inline]
    pub fn read_f32( self, slice: &[u8] ) -> f32 {
        f32::from_bits( self.read_u32( slice ) )
    }

    #[inline]
    pub fn read_f64( self, slice: &[u8] ) -> f64 {
        f64::from_bits( self.read_u64( slice ) )
    }

    #[inline]
    pub fn swap_f32( self, value: &mut f32 ) {
        let value = unsafe {
            &mut *(value as *mut f32 as *mut u32)
        };

        self.swap_u32( value );
    }

    #[inline]
    pub fn swap_f64( self, value: &mut f64 ) {
        let value = unsafe {
            &mut *(value as *mut f64 as *mut u64)
        };

        self.swap_u64( value );
    }

    #[inline]
    pub fn swap_slice_f32( self, slice: &mut [f32] ) {
        let slice = unsafe {
            core::slice::from_raw_parts_mut( slice.as_mut_ptr() as *mut u32, slice.len() )
        };

        self.swap_slice_u32( slice );
    }

    #[inline]
    pub fn swap_slice_f64( self, slice: &mut [f64] ) {
        let slice = unsafe {
            core::slice::from_raw_parts_mut( slice.as_mut_ptr() as *mut u64, slice.len() )
        };

        self.swap_slice_u64( slice );
    }
}