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
#[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!( 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 );

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 );
    }
}