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
//!Conversions to bytes.
//!
//!# Usage
//!
//!```rust
//!use lazy_bytes_cast::to::{ToBytesCast};
//!
//!fn main() {
//!    let some_int = 666;
//!
//!    let bytes = some_int.to_bytes();
//!
//!    println!("bytes={:?}", bytes);
//!}
//!```

use core::{marker, mem, ptr};
#[cfg(not(feature = "std"))]
use alloc::{vec, vec::Vec};

///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 bytes<T: marker::Copy>(data: T) -> Vec<u8> {
    let len = mem::size_of::<T>();
    let mut result: Vec<u8> = vec![0; len];

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

    result
}

///Unsafe version of [copy_bytes](fn.copy_bytes.html)
///
///Note: Unsafe version doesn't check anything and just copies data according to its size into slice.
pub unsafe fn copy_bytes_lazy<T: marker::Copy>(data: T, to: &mut [u8]) {
    ptr::copy_nonoverlapping(&data as *const _ as *const u8, to.as_mut_ptr(), mem::size_of::<T>());
}

///Converts data to a byte array by writing it into mutable slice
///
///# 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`
///* `to` - Byte slice where to copy
///
///# Result:
///
///* `Ok` - Success.
///* `Err` - Insufficient slice size.
pub fn copy_bytes<T: marker::Copy>(data: T, to: &mut [u8]) -> Result<(), ()> {
    let len = mem::size_of::<T>();

    if to.len() < len {
        return Err(());
    }

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

    Ok(())
}

///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 : marker::Copy {
    ///Converts to bytes.
    fn to_bytes(&self) -> Vec<u8>;
    ///Writes into byte slice.
    fn copy_to_bytes(&self, to: &mut [u8]) -> Result<(), ()>;
    ///Unsafe version of `copy_to_bytes`
    unsafe fn copy_to_bytes_lazy(&self, to: &mut [u8]);
}

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

                #[inline]
                fn copy_to_bytes(&self, to: &mut [u8]) -> Result<(), ()> {
                    copy_bytes(*self, to)
                }

                #[inline]
                unsafe fn copy_to_bytes_lazy(&self, to: &mut [u8]) {
                    copy_bytes_lazy(*self, to)
                }
            }
        )+
    };
}

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