use core::{mem, slice};
use {Error, Plain};
#[inline]
pub fn is_aligned<T>(bytes: &[u8]) -> bool {
((bytes.as_ptr() as usize) % mem::align_of::<T>()) == 0
}
#[inline(always)]
fn check_alignment<T>(bytes: &[u8]) -> Result<(), Error> {
if is_aligned::<T>(bytes) {
Ok(())
} else {
Err(Error::BadAlignment)
}
}
#[inline(always)]
fn check_length<T>(bytes: &[u8], len: usize) -> Result<(), Error> {
if mem::size_of::<T>() > 0 && (bytes.len() / mem::size_of::<T>()) < len {
Err(Error::TooShort)
} else {
Ok(())
}
}
#[inline(always)]
pub unsafe fn as_bytes<S>(s: &S) -> &[u8]
where
S: ?Sized,
{
let bptr = s as *const S as *const u8;
let bsize = mem::size_of_val(s);
slice::from_raw_parts(bptr, bsize)
}
#[inline(always)]
pub unsafe fn as_mut_bytes<S>(s: &mut S) -> &mut [u8]
where
S: Plain + ?Sized,
{
let bptr = s as *mut S as *mut u8;
let bsize = mem::size_of_val(s);
slice::from_raw_parts_mut(bptr, bsize)
}
#[inline]
pub fn from_bytes<T>(bytes: &[u8]) -> Result<&T, Error>
where
T: Plain,
{
try!(check_alignment::<T>(bytes));
try!(check_length::<T>(bytes, 1));
Ok(unsafe { &*(bytes.as_ptr() as *const T) })
}
#[inline]
pub fn slice_from_bytes<T>(bytes: &[u8]) -> Result<&[T], Error>
where
T: Plain,
{
let len = bytes.len() / mem::size_of::<T>();
slice_from_bytes_len(bytes, len)
}
#[inline]
pub fn slice_from_bytes_len<T>(bytes: &[u8], len: usize) -> Result<&[T], Error>
where
T: Plain,
{
try!(check_alignment::<T>(bytes));
try!(check_length::<T>(bytes, len));
Ok(unsafe {
slice::from_raw_parts(bytes.as_ptr() as *const T, len)
})
}
#[inline]
pub fn from_mut_bytes<T>(bytes: &mut [u8]) -> Result<&mut T, Error>
where
T: Plain,
{
try!(check_alignment::<T>(bytes));
try!(check_length::<T>(bytes, 1));
Ok(unsafe { &mut *(bytes.as_mut_ptr() as *mut T) })
}
#[inline]
pub fn slice_from_mut_bytes<T>(bytes: &mut [u8]) -> Result<&mut [T], Error>
where
T: Plain,
{
let len = bytes.len() / mem::size_of::<T>();
slice_from_mut_bytes_len(bytes, len)
}
#[inline]
pub fn slice_from_mut_bytes_len<T>(bytes: &mut [u8], len: usize) -> Result<&mut [T], Error>
where
T: Plain,
{
try!(check_alignment::<T>(bytes));
try!(check_length::<T>(bytes, len));
Ok(unsafe {
slice::from_raw_parts_mut(bytes.as_ptr() as *mut T, len)
})
}
#[inline]
pub fn copy_from_bytes<T>(into: &mut T, bytes: &[u8]) -> Result<(), Error>
where
T: Plain + ?Sized,
{
let sz = mem::size_of_val(into);
if bytes.len() < sz {
return Err(Error::TooShort);
}
unsafe {
as_mut_bytes(into).copy_from_slice(&bytes[..sz]);
}
Ok(())
}