use std::fmt;
use std::mem;
use std::slice;
use std::error::Error as StdError;
#[derive(Debug, PartialEq, Eq)]
pub enum Error {
WrongAlignment,
IncompleteNumberOfValues,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.write_str(self.description())
}
}
impl StdError for Error {
fn description(&self) -> &str {
use self::Error::*;
match *self {
WrongAlignment => "Wrong Alignment",
IncompleteNumberOfValues => "Incomplete Number of Values",
}
}
}
fn check_constraints<T, U>(data: &[T]) -> Result<usize, Error> {
let alignment = mem::align_of::<U>();
if (data.as_ptr() as usize) % alignment != 0 {
return Err(Error::WrongAlignment);
}
let size_in = mem::size_of::<T>();
let size_out = mem::size_of::<U>();
if (data.len() * size_in) % size_out != 0 {
return Err(Error::IncompleteNumberOfValues);
}
Ok((data.len() * size_in) / size_out)
}
pub unsafe trait FromByteSlice
where
Self: Sized,
{
fn from_byte_slice<T: AsRef<[u8]> + ?Sized>(&T) -> Result<&[Self], Error>;
fn from_mut_byte_slice<T: AsMut<[u8]> + ?Sized>(&mut T) -> Result<&mut [Self], Error>;
}
pub unsafe trait ToByteSlice
where
Self: Sized,
{
fn to_byte_slice<T: AsRef<[Self]> + ?Sized>(slice: &T) -> Result<&[u8], Error>;
}
pub unsafe trait ToMutByteSlice
where
Self: Sized,
{
fn to_mut_byte_slice<T: AsMut<[Self]> + ?Sized>(slice: &mut T) -> Result<&mut [u8], Error>;
}
macro_rules! impl_trait(
($to:ty) => {
unsafe impl FromByteSlice for $to {
fn from_byte_slice<T: AsRef<[u8]> + ?Sized>(slice: &T) -> Result<&[$to], Error> {
let slice = slice.as_ref();
let len = check_constraints::<u8, $to>(slice)?;
unsafe {
Ok(slice::from_raw_parts(slice.as_ptr() as *const $to, len))
}
}
fn from_mut_byte_slice<T: AsMut<[u8]> + ?Sized>(slice: &mut T) -> Result<&mut [$to], Error> {
let slice = slice.as_mut();
let len = check_constraints::<u8, $to>(slice)?;
unsafe {
Ok(slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut $to, len))
}
}
}
unsafe impl ToByteSlice for $to {
fn to_byte_slice<T: AsRef<[$to]> + ?Sized>(slice: &T) -> Result<&[u8], Error> {
let slice = slice.as_ref();
let len = check_constraints::<$to, u8>(slice)?;
unsafe {
Ok(slice::from_raw_parts(slice.as_ptr() as *const u8, len))
}
}
}
unsafe impl ToMutByteSlice for $to {
fn to_mut_byte_slice<T: AsMut<[$to]> + ?Sized>(slice: &mut T) -> Result<&mut [u8], Error> {
let slice = slice.as_mut();
let len = check_constraints::<$to, u8>(slice)?;
unsafe {
Ok(slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut u8, len))
}
}
}
};
);
impl_trait!(u8);
impl_trait!(u16);
impl_trait!(u32);
impl_trait!(u64);
impl_trait!(u128);
impl_trait!(i8);
impl_trait!(i16);
impl_trait!(i32);
impl_trait!(i64);
impl_trait!(i128);
impl_trait!(f32);
impl_trait!(f64);
pub trait AsSliceOf {
fn as_slice_of<T: FromByteSlice>(&self) -> Result<&[T], Error>;
}
impl<U: AsRef<[u8]> + ?Sized> AsSliceOf for U {
fn as_slice_of<T: FromByteSlice>(&self) -> Result<&[T], Error> {
FromByteSlice::from_byte_slice(self)
}
}
pub trait AsMutSliceOf {
fn as_mut_slice_of<T: FromByteSlice>(&mut self) -> Result<&mut [T], Error>;
}
impl<U: AsMut<[u8]> + ?Sized> AsMutSliceOf for U {
fn as_mut_slice_of<T: FromByteSlice>(&mut self) -> Result<&mut [T], Error> {
FromByteSlice::from_mut_byte_slice(self)
}
}
pub trait AsByteSlice<T> {
fn as_byte_slice(&self) -> Result<&[u8], Error>;
}
impl<T: ToByteSlice, U: AsRef<[T]> + ?Sized> AsByteSlice<T> for U {
fn as_byte_slice(&self) -> Result<&[u8], Error> {
ToByteSlice::to_byte_slice(self)
}
}
pub trait AsMutByteSlice<T> {
fn as_mut_byte_slice(&mut self) -> Result<&mut [u8], Error>;
}
impl<T: ToMutByteSlice, U: AsMut<[T]> + ?Sized> AsMutByteSlice<T> for U {
fn as_mut_byte_slice(&mut self) -> Result<&mut [u8], Error> {
ToMutByteSlice::to_mut_byte_slice(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn u8() {
let input: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
let output: &[u8] = input.as_slice_of::<u8>().unwrap();
assert_eq!(&input, output);
let output2: &[u8] = input.as_byte_slice().unwrap();
assert_eq!(&input, output2);
}
#[test]
fn u16() {
let slice: [u16; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
let bytes = slice.as_byte_slice().unwrap();
if cfg!(target_endian = "big") {
assert_eq!(bytes, &[0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7]);
} else {
assert_eq!(bytes, &[0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0]);
}
assert_eq!(
(&bytes[1..]).as_slice_of::<u16>(),
Err(Error::WrongAlignment)
);
assert_eq!(
(&bytes[0..15]).as_slice_of::<u16>(),
Err(Error::IncompleteNumberOfValues)
);
assert_eq!(bytes.as_slice_of::<u16>(), Ok(slice.as_ref()));
}
#[test]
fn u32() {
let slice: [u32; 4] = [0, 1, 2, 3];
let bytes = slice.as_byte_slice().unwrap();
if cfg!(target_endian = "big") {
assert_eq!(bytes, &[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3]);
} else {
assert_eq!(bytes, &[0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0]);
}
assert_eq!(
(&bytes[1..]).as_slice_of::<u32>(),
Err(Error::WrongAlignment)
);
assert_eq!(
(&bytes[0..15]).as_slice_of::<u32>(),
Err(Error::IncompleteNumberOfValues)
);
assert_eq!(bytes.as_slice_of::<u32>(), Ok(slice.as_ref()));
}
#[test]
fn u64() {
let slice: [u64; 2] = [0, 1];
let bytes = slice.as_byte_slice().unwrap();
if cfg!(target_endian = "big") {
assert_eq!(bytes, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
} else {
assert_eq!(bytes, &[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]);
}
assert_eq!(
(&bytes[1..]).as_slice_of::<u64>(),
Err(Error::WrongAlignment)
);
assert_eq!(
(&bytes[0..15]).as_slice_of::<u64>(),
Err(Error::IncompleteNumberOfValues)
);
assert_eq!(bytes.as_slice_of::<u64>(), Ok(slice.as_ref()));
}
#[test]
fn f32() {
let slice: [f32; 4] = [2.0, 1.0, 0.5, 0.25];
let bytes = slice.as_byte_slice().unwrap();
if cfg!(target_endian = "big") {
assert_eq!(
bytes,
[
0x40, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x3e,
0x80, 0x00, 0x00
]
);
} else {
assert_eq!(
bytes,
[
0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x3f, 0x00,
0x00, 0x80, 0x3e
]
);
};
assert_eq!(
(&bytes[1..]).as_slice_of::<f32>(),
Err(Error::WrongAlignment)
);
assert_eq!(
(&bytes[0..15]).as_slice_of::<f32>(),
Err(Error::IncompleteNumberOfValues)
);
assert_eq!(bytes.as_slice_of::<f32>(), Ok(slice.as_ref()));
}
#[test]
fn f64() {
let slice: [f64; 2] = [2.0, 0.5];
let bytes = slice.as_byte_slice().unwrap();
if cfg!(target_endian = "big") {
assert_eq!(
bytes,
[
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xe0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00
]
);
} else {
assert_eq!(
bytes,
[
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xe0, 0x3f
]
);
};
assert_eq!(
(&bytes[1..]).as_slice_of::<f64>(),
Err(Error::WrongAlignment)
);
assert_eq!(
(&bytes[0..15]).as_slice_of::<f64>(),
Err(Error::IncompleteNumberOfValues)
);
assert_eq!(bytes.as_slice_of::<f64>(), Ok(slice.as_ref()));
}
#[test]
fn u16_mut() {
let mut slice: [u16; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
let mut slice_2: [u16; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
let bytes = slice_2.as_mut_byte_slice().unwrap();
if cfg!(target_endian = "big") {
assert_eq!(bytes, &[0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7]);
} else {
assert_eq!(bytes, &[0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0]);
}
assert_eq!(
(&mut bytes[1..]).as_mut_slice_of::<u16>(),
Err(Error::WrongAlignment)
);
assert_eq!(
(&mut bytes[0..15]).as_mut_slice_of::<u16>(),
Err(Error::IncompleteNumberOfValues)
);
assert_eq!(bytes.as_mut_slice_of::<u16>(), Ok(slice.as_mut()));
}
#[test]
fn u16_vec() {
let vec: Vec<u16> = vec![0, 1, 2, 3, 4, 5, 6, 7];
let bytes = vec.as_byte_slice().unwrap();
if cfg!(target_endian = "big") {
assert_eq!(bytes, &[0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7]);
} else {
assert_eq!(bytes, &[0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0]);
}
assert_eq!(
(&bytes[1..]).as_slice_of::<u16>(),
Err(Error::WrongAlignment)
);
assert_eq!(
(&bytes[0..15]).as_slice_of::<u16>(),
Err(Error::IncompleteNumberOfValues)
);
assert_eq!(bytes.as_slice_of::<u16>(), Ok(vec.as_ref()));
}
#[test]
fn u16_mut_vec() {
let mut vec: Vec<u16> = vec![0, 1, 2, 3, 4, 5, 6, 7];
let mut vec_clone = vec.clone();
let bytes = vec_clone.as_mut_byte_slice().unwrap();
if cfg!(target_endian = "big") {
assert_eq!(bytes, &[0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7]);
} else {
assert_eq!(bytes, &[0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0]);
}
assert_eq!(
(&mut bytes[1..]).as_mut_slice_of::<u16>(),
Err(Error::WrongAlignment)
);
assert_eq!(
(&mut bytes[0..15]).as_mut_slice_of::<u16>(),
Err(Error::IncompleteNumberOfValues)
);
assert_eq!(bytes.as_mut_slice_of::<u16>(), Ok(vec.as_mut()));
}
#[test]
fn u16_box_slice() {
let vec: Box<[u16]> = vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice();
let bytes = vec.as_byte_slice().unwrap();
if cfg!(target_endian = "big") {
assert_eq!(bytes, &[0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7]);
} else {
assert_eq!(bytes, &[0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0]);
}
assert_eq!(
(&bytes[1..]).as_slice_of::<u16>(),
Err(Error::WrongAlignment)
);
assert_eq!(
(&bytes[0..15]).as_slice_of::<u16>(),
Err(Error::IncompleteNumberOfValues)
);
assert_eq!(bytes.as_slice_of::<u16>(), Ok(vec.as_ref()));
}
#[test]
fn u16_mut_box_slice() {
let mut vec: Box<[u16]> = vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice();
let mut vec_clone: Box<[u16]> = vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice();
let bytes = vec_clone.as_mut_byte_slice().unwrap();
if cfg!(target_endian = "big") {
assert_eq!(bytes, &[0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7]);
} else {
assert_eq!(bytes, &[0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0]);
}
assert_eq!(
(&mut bytes[1..]).as_mut_slice_of::<u16>(),
Err(Error::WrongAlignment)
);
assert_eq!(
(&mut bytes[0..15]).as_mut_slice_of::<u16>(),
Err(Error::IncompleteNumberOfValues)
);
assert_eq!(bytes.as_mut_slice_of::<u16>(), Ok(vec.as_mut()));
}
}