use core::{mem, slice}; use {Error, Plain}; /// Check if a byte slice is aligned suitably for type T. #[inline] pub fn is_aligned(bytes: &[u8]) -> bool { ((bytes.as_ptr() as usize) % mem::align_of::()) == 0 } #[inline(always)] fn check_alignment(bytes: &[u8]) -> Result<(), Error> { if is_aligned::(bytes) { Ok(()) } else { Err(Error::BadAlignment) } } #[inline(always)] fn check_length(bytes: &[u8], len: usize) -> Result<(), Error> { if mem::size_of::() > 0 && (bytes.len() / mem::size_of::()) < len { Err(Error::TooShort) } else { Ok(()) } } /// Interpret data as bytes. Not safe for data with padding. #[inline(always)] pub unsafe fn as_bytes(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) } /// Interpret data as mutable bytes. /// Reading is not safe for data with padding. Writing is ok. #[inline(always)] pub unsafe fn as_mut_bytes(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) } /// Safely converts a byte slice to a reference. /// /// However, if the byte slice is not long enough /// to contain target type, or if it doesn't /// satisfy the type's alignment requirements, /// the function returns an error. /// /// The function will not fail when the /// byte slice is longer than necessary, since it is /// a common practice to interpret the beginning of /// a slice as a fixed-size header. /// /// In many cases it is preferrable to allocate /// a value/slice of the target type and use /// [`copy_from_bytes()`](fn.copy_from_bytes.html) to copy /// data instead. That way, any issues with alignment /// are implicitly avoided. /// #[inline] pub fn from_bytes(bytes: &[u8]) -> Result<&T, Error> where T: Plain, { try!(check_alignment::(bytes)); try!(check_length::(bytes, 1)); Ok(unsafe { &*(bytes.as_ptr() as *const T) }) } /// Similar to [`from_bytes()`](fn.from_bytes.html), /// except that the output is a slice of T, instead /// of a reference to a single T. All concerns about /// alignment also apply here, but size is handled /// differently. /// /// The result slice's length is set to be /// `bytes.len() / size_of::()`, and there /// are no requirements for input size. I.e. /// the result may be empty slice, and the input /// slice doesn't necessarily have to end on `T`'s /// boundary. The latter has pragmatic reasons: If the /// length of the array is not known in advance, /// e.g. if it's terminated by a special element, /// it's perfectly legal to turn the whole rest /// of data into `&[T]` and set the proper length /// after inspecting the array. /// /// In many cases it is preferrable to allocate /// a value/slice of the target type and use /// [`copy_from_bytes()`](fn.copy_from_bytes.html) to copy /// data instead. That way, any issues with alignment /// are implicitly avoided. /// #[inline] pub fn slice_from_bytes(bytes: &[u8]) -> Result<&[T], Error> where T: Plain, { let len = bytes.len() / mem::size_of::(); slice_from_bytes_len(bytes, len) } /// Same as [`slice_from_bytes()`](fn.slice_from_bytes.html), /// except that it takes explicit length of the result slice. /// /// If the input slice cannot satisfy the length, returns error. /// The input slice is allowed to be longer than necessary. /// #[inline] pub fn slice_from_bytes_len(bytes: &[u8], len: usize) -> Result<&[T], Error> where T: Plain, { try!(check_alignment::(bytes)); try!(check_length::(bytes, len)); Ok(unsafe { slice::from_raw_parts(bytes.as_ptr() as *const T, len) }) } /// See [`from_bytes()`](fn.from_bytes.html). /// /// Does the same, except with mutable references. /// #[inline] pub fn from_mut_bytes(bytes: &mut [u8]) -> Result<&mut T, Error> where T: Plain, { try!(check_alignment::(bytes)); try!(check_length::(bytes, 1)); Ok(unsafe { &mut *(bytes.as_mut_ptr() as *mut T) }) } /// See [`slice_from_bytes()`](fn.slice_from_bytes.html). /// /// Does the same, except with mutable references. /// #[inline] pub fn slice_from_mut_bytes(bytes: &mut [u8]) -> Result<&mut [T], Error> where T: Plain, { let len = bytes.len() / mem::size_of::(); slice_from_mut_bytes_len(bytes, len) } /// See [`slice_from_bytes_len()`](fn.slice_from_bytes_len.html). /// /// Does the same, except with mutable references. /// #[inline] pub fn slice_from_mut_bytes_len(bytes: &mut [u8], len: usize) -> Result<&mut [T], Error> where T: Plain, { try!(check_alignment::(bytes)); try!(check_length::(bytes, len)); Ok(unsafe { slice::from_raw_parts_mut(bytes.as_ptr() as *mut T, len) }) } /// Copies data from a byte slice into existing memory. /// Suitable when [`from_bytes()`](fn.from_bytes.html) would normally /// be used, but the data is not aligned properly in memory. /// /// For an example how to use it, see crate-level documentation. /// #[inline] pub fn copy_from_bytes(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(()) }