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
138
139
140
141
//! Slice conversion module
//!
//! Provides utilities to treat arbitrary types as slice of bytes

use core::{slice, mem};

#[inline]
///Access value as slice of bytes
pub unsafe fn as_slice<T: Sized>(val: &T) -> &[u8] {
    slice::from_raw_parts(val as *const _ as *const _, mem::size_of::<T>())
}

#[inline]
///Access value as mutable slice of bytes
pub unsafe fn as_slice_mut<T: Sized>(val: &mut T) -> &mut [u8] {
    slice::from_raw_parts_mut(val as *mut _ as *mut _, mem::size_of::<T>())
}

#[inline]
///Get reference to the value from slice, using `as_type_unchecked`
pub unsafe fn as_type<T: Sized>(slice: &[u8]) -> Option<&T> {
    if mem::size_of::<T>() == slice.len() {
        Some(as_type_unchecked(slice))
    } else {
        None
    }
}

#[inline]
///Get mutable reference to the value from slice, using `as_type_mut_unchecked`
pub unsafe fn as_type_mut<T: Sized>(slice: &mut [u8]) -> Option<&mut T> {
    if mem::size_of::<T>() == slice.len() {
        Some(as_type_mut_unchecked(slice))
    } else {
        None
    }
}

#[inline]
///Get reference to the value from slice
///
///This function is UB if `slice.len() < mem::size_of::<T>()`
///
///Also might be UB if `mem::align_if::<T>() > 1`
pub unsafe fn as_type_unchecked<T: Sized>(slice: &[u8]) -> &T {
    &*(slice.as_ptr() as *const T)
}

#[inline]
///Get mutable reference to the value from slice
///
///This function is UB if `slice.len() < mem::size_of::<T>()`
///
///Also might be UB if `mem::align_if::<T>() > 1`
pub unsafe fn as_type_mut_unchecked<T: Sized>(slice: &mut [u8]) -> &mut T {
    &mut *(slice.as_mut_ptr() as *mut T)
}

/// Trait which should be implemented for types that are safe to treat as byte
///
/// While it is possible to consider all types as bytes, it doesn't make sense for some (e.g.  `Vec`)
pub unsafe trait AsByteSlice: Sized {
    #[inline]
    ///Access value as slice of bytes
    fn as_slice(&self) -> &[u8] {
        unsafe {
            as_slice(self)
        }
    }

    #[inline]
    ///Access value as mutable slice of bytes
    fn as_slice_mut(&mut self) -> &mut [u8] {
        unsafe {
            as_slice_mut(self)
        }
    }
}

macro_rules! impl_trait {
    ($($type:ty,)+) => {
        $(
            unsafe impl AsByteSlice for $type {}
        )+
    }
}

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

///Describes a way to read byte slice into particular type.
pub trait ReadByteSlice: crate::FromByteArray + Sized {
    ///Reads from byte slice, converting consumed bytes into `Self`
    ///
    ///Modifying existing slice by taking away required bytes.
    ///
    ///When slice has insufficient size, returns `None`
    fn read_byte_slice(slice: &mut &[u8]) -> Option<Self> {
        if slice.len() < mem::size_of::<Self::Array>() {
            return None;
        }

        Some(unsafe {
            Self::read_byte_slice_unchecked(slice)
        })
    }

    ///Unsafe version of `read_byte_slice`, that doesn't perform length check.
    unsafe fn read_byte_slice_unchecked(slice: &mut &[u8]) -> Self {
        let (convert, remains) = slice.split_at(mem::size_of::<Self::Array>());
        *slice = remains;
        //This is fine because we know that slice has enough bytes
        let convert = convert.as_ptr() as *const Self::Array;

        Self::from_byte_array(*convert)
    }
}

impl<T: crate::FromByteArray> ReadByteSlice for T {}

///Describes a way to read byte slice into particular type.
pub trait FromByteSlice: crate::FromByteArray + Sized {
    #[inline]
    ///Converts slice into `Self` only if `mem::size_of::<Self>() == slice.len()`
    fn from_slice(slice: &[u8]) -> Option<Self> {
        if mem::size_of::<Self>() == slice.len() {
            Some(unsafe {
                Self::from_slice_unchecked(slice)
            })
        } else {
            None
        }
    }

    ///Converts slice into `Self` without performing any checks.
    unsafe fn from_slice_unchecked(slice: &[u8]) -> Self {
        let slice = slice.as_ptr() as *const Self::Array;
        Self::from_byte_array(*slice)
    }
}

impl<T: crate::FromByteArray> FromByteSlice for T {}