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

use ::{
    marker,
    mem,
    ptr
};

#[cfg(feature = "std")]
///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.
///
///# Note 2:
///
///This function is not available without libstd for obvious reasons.
///
///# 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 {
    #[cfg(feature = "std")]
    ///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 {
                #[cfg(feature = "std")]
                #[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);