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
142
143
144
145
146
147
148
149
150
151
/*!
This crate provides simple methods to cast from and into byte arrays.

# Note

The crates will not take care of byte order for you. Cuz lazy.

# Usage example

```rust
extern crate lazy_bytes_cast;

use lazy_bytes_cast::{
    ToBytesCast,
    FromBytesCast
};

fn main() {
    let int_to: u32 = u32::max_value();
    println!("result={:?}", int_to.to_bytes());

    let bytes: [u8; 4] = [255, 255, 255, 255];
    let result: u32 = bytes.cast_to().unwrap();
    println!("result={}",result);
}
```

*/

///Converts data to a byte array.
///
///# Note:
///
///This function limits its usage to data that implements ```marker::Copy```
///
///But it does not guarantee that all types with such trait will be correctly converted.
///
///# Parameters:
///
///* ```data``` - Arbitrary data that can be ```memcpy```
///
///# Result:
///
///* ```Vec``` - Allocated with size equal to ```size_of::<data>```.
pub fn to_bytes<T: std::marker::Copy>(data: T) -> Vec<u8> {
    let len = std::mem::size_of::<T>();
    let mut result: Vec<u8> = vec![0; len];

    unsafe {
        std::ptr::copy_nonoverlapping(&data as *const _ as *const u8, result.as_mut_ptr(), len);
    }

    result
}

///Trait to provide ```to_bytes``` method for a arbitrary data.
///
///This trait is implemented for a basic integer that can be safely converted.
pub unsafe trait ToBytesCast : std::marker::Copy {
    fn to_bytes(&self) -> Vec<u8>;
}

macro_rules! impl_to_traits
{
    ($($t:ty), +) => {
        $(
            unsafe impl ToBytesCast for $t {
                #[inline]
                fn to_bytes(&self) -> Vec<u8> {
                    to_bytes(*self)
                }
            }
        )+
    };
}

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

///Unsafe version of ```bytes_cast```
///
///# Note:
///
///This function is able to convert only to types that implements ```marker::Copy```
///
///# Parameters:
///
///* ```bytes``` - slice of bytes to convert.
///
///# Result:
///
///* ```T``` - Converted data.
pub unsafe fn bytes_cast_lazy<T: std::marker::Copy>(bytes: &[u8]) -> T {
    let len = std::mem::size_of::<T>();

    let mut result: T = std::mem::uninitialized();
    std::ptr::copy_nonoverlapping(bytes.as_ptr(), &mut result as *mut _ as *mut u8, len);

    result
}

///Converts slice of bytes to an integer.
///
///# Note:
///
///This function allows conversion only to types that implements ```ToBytesCast```.
///
///# Parameters:
///
///* ```bytes``` - slice of bytes to convert
///
///# Result:
///
///* ```Ok``` - Converted integer.
///* ```Err``` - Insufficient bytes size for a cast.
pub fn bytes_cast<T: ToBytesCast>(bytes: &[u8]) -> Result<T, String> {
    let len = std::mem::size_of::<T>();

    if bytes.len() < len {
        return Err("Bytes size is insufficient for a cast".to_string());
    }

    unsafe {
        Ok(bytes_cast_lazy(bytes))
    }
}

///Trait to provide casting function to byte slices
pub unsafe trait FromBytesCast<T: ToBytesCast> {
    fn cast_to(&self) -> Result<T, String>;
}

unsafe impl<T: ToBytesCast> FromBytesCast<T> for Vec<u8> {
    #[inline]
    fn cast_to(&self) -> Result<T, String> {
        bytes_cast(self)
    }
}

unsafe impl<T: ToBytesCast> FromBytesCast<T> for [u8] {
    #[inline]
    fn cast_to(&self) -> Result<T, String> {
        bytes_cast(self)
    }
}

unsafe impl<'a, T: ToBytesCast> FromBytesCast<T> for &'a[u8] {
    #[inline]
    fn cast_to(&self) -> Result<T, String> {
        bytes_cast(*self)
    }
}