#![feature(refcell_map_split)]
#![cfg_attr(not(test), no_std)]
#[cfg(test)]
extern crate core;
use core::cell::{Ref, RefMut};
use core::fmt::{self, Debug, Display, Formatter};
use core::marker::PhantomData;
use core::mem;
use core::ops::{Deref, DerefMut};
macro_rules! impl_for_primitives {
($trait:ident) => (
impl_for_primitives!(@inner $trait, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize);
);
(@inner $trait:ident, $type:ty) => (
unsafe impl $trait for $type {}
);
(@inner $trait:ident, $type:ty, $($types:ty),*) => (
unsafe impl $trait for $type {}
impl_for_primitives!(@inner $trait, $($types),*);
);
}
macro_rules! impl_for_array_sizes {
($trait:ident) => (
impl_for_array_sizes!(@inner $trait, 0, 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);
);
(@inner $trait:ident, $n:expr) => (
unsafe impl<T: $trait> $trait for [T; $n] {}
);
(@inner $trait:ident, $n:expr, $($ns:expr),*) => (
unsafe impl<T: $trait> $trait for [T; $n] {}
impl_for_array_sizes!(@inner $trait, $($ns),*);
);
}
pub unsafe trait FromBytes {}
pub unsafe trait AsBytes {}
impl_for_primitives!(FromBytes);
impl_for_primitives!(AsBytes);
impl_for_array_sizes!(FromBytes);
impl_for_array_sizes!(AsBytes);
pub unsafe trait Unaligned {}
unsafe impl Unaligned for u8 {}
unsafe impl Unaligned for i8 {}
impl_for_array_sizes!(Unaligned);
pub struct LayoutVerified<B, T>(B, PhantomData<T>);
impl<B, T> LayoutVerified<B, T>
where
B: ByteSlice,
{
#[inline]
pub fn new(bytes: B) -> Option<LayoutVerified<B, T>> {
if bytes.len() != mem::size_of::<T>() || !aligned_to(bytes.deref(), mem::align_of::<T>()) {
return None;
}
Some(LayoutVerified(bytes, PhantomData))
}
#[inline]
pub fn new_from_prefix(bytes: B) -> Option<(LayoutVerified<B, T>, B)> {
if bytes.len() < mem::size_of::<T>() || !aligned_to(bytes.deref(), mem::align_of::<T>()) {
return None;
}
let (bytes, suffix) = bytes.split_at(mem::size_of::<T>());
Some((LayoutVerified(bytes, PhantomData), suffix))
}
#[inline]
pub fn new_from_suffix(bytes: B) -> Option<(B, LayoutVerified<B, T>)> {
let bytes_len = bytes.len();
if bytes_len < mem::size_of::<T>() {
return None;
}
let (prefix, bytes) = bytes.split_at(bytes_len - mem::size_of::<T>());
if !aligned_to(bytes.deref(), mem::align_of::<T>()) {
return None;
}
Some((prefix, LayoutVerified(bytes, PhantomData)))
}
#[inline]
pub fn bytes(&self) -> &[u8] {
&self.0
}
}
fn map_zeroed<B: ByteSliceMut, T>(
opt: Option<LayoutVerified<B, T>>,
) -> Option<LayoutVerified<B, T>> {
match opt {
Some(mut lv) => {
for b in lv.0.iter_mut() {
*b = 0;
}
Some(lv)
}
None => None,
}
}
fn map_prefix_tuple_zeroed<B: ByteSliceMut, T>(
opt: Option<(LayoutVerified<B, T>, B)>,
) -> Option<(LayoutVerified<B, T>, B)> {
match opt {
Some((mut lv, rest)) => {
for b in lv.0.iter_mut() {
*b = 0;
}
Some((lv, rest))
}
None => None,
}
}
fn map_suffix_tuple_zeroed<B: ByteSliceMut, T>(
opt: Option<(B, LayoutVerified<B, T>)>,
) -> Option<(B, LayoutVerified<B, T>)> {
map_prefix_tuple_zeroed(opt.map(|(a, b)| (b, a))).map(|(a, b)| (b, a))
}
impl<B, T> LayoutVerified<B, T>
where
B: ByteSliceMut,
{
#[inline]
pub fn new_zeroed(bytes: B) -> Option<LayoutVerified<B, T>> {
map_zeroed(Self::new(bytes))
}
#[inline]
pub fn new_from_prefix_zeroed(bytes: B) -> Option<(LayoutVerified<B, T>, B)> {
map_prefix_tuple_zeroed(Self::new_from_prefix(bytes))
}
#[inline]
pub fn new_from_suffix_zeroed(bytes: B) -> Option<(B, LayoutVerified<B, T>)> {
map_suffix_tuple_zeroed(Self::new_from_suffix(bytes))
}
}
impl<B, T> LayoutVerified<B, T>
where
B: ByteSlice,
T: Unaligned,
{
#[inline]
pub fn new_unaligned(bytes: B) -> Option<LayoutVerified<B, T>> {
if bytes.len() != mem::size_of::<T>() {
return None;
}
Some(LayoutVerified(bytes, PhantomData))
}
#[inline]
pub fn new_unaligned_from_prefix(bytes: B) -> Option<(LayoutVerified<B, T>, B)> {
if bytes.len() < mem::size_of::<T>() {
return None;
}
let (bytes, suffix) = bytes.split_at(mem::size_of::<T>());
Some((LayoutVerified(bytes, PhantomData), suffix))
}
#[inline]
pub fn new_unaligned_from_suffix(bytes: B) -> Option<(B, LayoutVerified<B, T>)> {
let bytes_len = bytes.len();
if bytes_len < mem::size_of::<T>() {
return None;
}
let (prefix, bytes) = bytes.split_at(bytes_len - mem::size_of::<T>());
Some((prefix, LayoutVerified(bytes, PhantomData)))
}
}
impl<B, T> LayoutVerified<B, T>
where
B: ByteSliceMut,
T: Unaligned,
{
#[inline]
pub fn new_unaligned_zeroed(bytes: B) -> Option<LayoutVerified<B, T>> {
map_zeroed(Self::new_unaligned(bytes))
}
#[inline]
pub fn new_unaligned_from_prefix_zeroed(bytes: B) -> Option<(LayoutVerified<B, T>, B)> {
map_prefix_tuple_zeroed(Self::new_unaligned_from_prefix(bytes))
}
#[inline]
pub fn new_unaligned_from_suffix_zeroed(bytes: B) -> Option<(B, LayoutVerified<B, T>)> {
map_suffix_tuple_zeroed(Self::new_unaligned_from_suffix(bytes))
}
}
fn aligned_to(bytes: &[u8], align: usize) -> bool {
(bytes as *const _ as *const () as usize) % align == 0
}
impl<B, T> LayoutVerified<B, T>
where
B: ByteSliceMut,
{
#[inline]
pub fn bytes_mut(&mut self) -> &mut [u8] {
&mut self.0
}
}
impl<B, T> Deref for LayoutVerified<B, T>
where
B: ByteSlice,
T: FromBytes,
{
type Target = T;
#[inline]
fn deref(&self) -> &T {
unsafe { &mut *(self.0.as_ptr() as *mut T) }
}
}
impl<B, T> DerefMut for LayoutVerified<B, T>
where
B: ByteSliceMut,
T: FromBytes + AsBytes,
{
#[inline]
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *(self.0.as_mut_ptr() as *mut T) }
}
}
impl<T, B> Display for LayoutVerified<B, T>
where
B: ByteSlice,
T: FromBytes + Display,
{
#[inline]
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
let inner: &T = self;
inner.fmt(fmt)
}
}
impl<T, B> Debug for LayoutVerified<B, T>
where
B: ByteSlice,
T: FromBytes + Debug,
{
#[inline]
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
let inner: &T = self;
fmt.debug_tuple("LayoutVerified").field(&inner).finish()
}
}
mod sealed {
use core::cell::{Ref, RefMut};
pub trait Sealed {}
impl<'a> Sealed for &'a [u8] {}
impl<'a> Sealed for &'a mut [u8] {}
impl<'a> Sealed for Ref<'a, [u8]> {}
impl<'a> Sealed for RefMut<'a, [u8]> {}
}
pub unsafe trait ByteSlice: Deref<Target = [u8]> + Sized + self::sealed::Sealed {
fn as_ptr(&self) -> *const u8;
fn split_at(self, mid: usize) -> (Self, Self);
}
pub unsafe trait ByteSliceMut: ByteSlice + DerefMut {
fn as_mut_ptr(&mut self) -> *mut u8;
}
unsafe impl<'a> ByteSlice for &'a [u8] {
fn as_ptr(&self) -> *const u8 {
<[u8]>::as_ptr(self)
}
fn split_at(self, mid: usize) -> (Self, Self) {
<[u8]>::split_at(self, mid)
}
}
unsafe impl<'a> ByteSlice for &'a mut [u8] {
fn as_ptr(&self) -> *const u8 {
<[u8]>::as_ptr(self)
}
fn split_at(self, mid: usize) -> (Self, Self) {
<[u8]>::split_at_mut(self, mid)
}
}
unsafe impl<'a> ByteSlice for Ref<'a, [u8]> {
fn as_ptr(&self) -> *const u8 {
<[u8]>::as_ptr(self)
}
fn split_at(self, mid: usize) -> (Self, Self) {
Ref::map_split(self, |slice| <[u8]>::split_at(slice, mid))
}
}
unsafe impl<'a> ByteSlice for RefMut<'a, [u8]> {
fn as_ptr(&self) -> *const u8 {
<[u8]>::as_ptr(self)
}
fn split_at(self, mid: usize) -> (Self, Self) {
RefMut::map_split(self, |slice| <[u8]>::split_at_mut(slice, mid))
}
}
unsafe impl<'a> ByteSliceMut for &'a mut [u8] {
fn as_mut_ptr(&mut self) -> *mut u8 {
<[u8]>::as_mut_ptr(self)
}
}
unsafe impl<'a> ByteSliceMut for RefMut<'a, [u8]> {
fn as_mut_ptr(&mut self) -> *mut u8 {
<[u8]>::as_mut_ptr(self)
}
}
#[cfg(test)]
mod tests {
use core::ops::Deref;
use core::ptr;
use super::LayoutVerified;
#[derive(Default)]
struct AlignedBuffer<T, B> {
buf: B,
_t: T,
}
impl<T, B: Default> AlignedBuffer<T, B> {
fn clear_buf(&mut self) {
self.buf = B::default();
}
}
fn u64_to_bytes(u: u64) -> [u8; 8] {
unsafe { ptr::read(&u as *const u64 as *const [u8; 8]) }
}
#[test]
fn test_address() {
let buf = [0];
let lv = LayoutVerified::<_, u8>::new(&buf[..]).unwrap();
let buf_ptr = buf.as_ptr();
let deref_ptr = lv.deref() as *const u8;
assert_eq!(buf_ptr, deref_ptr);
}
fn test_new_helper<'a>(mut lv: LayoutVerified<&'a mut [u8], u64>) {
assert_eq!(*lv, 0);
const VAL1: u64 = 0xFF00FF00FF00FF00;
*lv = VAL1;
assert_eq!(lv.bytes(), &u64_to_bytes(VAL1));
const VAL2: u64 = !VAL1; lv.bytes_mut().copy_from_slice(&u64_to_bytes(VAL2)[..]);
assert_eq!(*lv, VAL2);
}
fn test_new_helper_unaligned<'a>(mut lv: LayoutVerified<&'a mut [u8], [u8; 8]>) {
assert_eq!(*lv, [0; 8]);
const VAL1: [u8; 8] = [0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00];
*lv = VAL1;
assert_eq!(lv.bytes(), &VAL1);
const VAL2: [u8; 8] = [0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF]; lv.bytes_mut().copy_from_slice(&VAL2[..]);
assert_eq!(*lv, VAL2);
}
#[test]
fn test_new_aligned_sized() {
let mut buf = AlignedBuffer::<u64, [u8; 8]>::default();
test_new_helper(LayoutVerified::<_, u64>::new(&mut buf.buf[..]).unwrap());
buf.buf = [0xFFu8; 8];
test_new_helper(LayoutVerified::<_, u64>::new_zeroed(&mut buf.buf[..]).unwrap());
{
buf.clear_buf();
let (lv, suffix) = LayoutVerified::<_, u64>::new_from_prefix(&mut buf.buf[..]).unwrap();
assert!(suffix.is_empty());
test_new_helper(lv);
}
{
buf.buf = [0xFFu8; 8];
let (lv, suffix) =
LayoutVerified::<_, u64>::new_from_prefix_zeroed(&mut buf.buf[..]).unwrap();
assert!(suffix.is_empty());
test_new_helper(lv);
}
{
buf.clear_buf();
let (prefix, lv) = LayoutVerified::<_, u64>::new_from_suffix(&mut buf.buf[..]).unwrap();
assert!(prefix.is_empty());
test_new_helper(lv);
}
{
buf.buf = [0xFFu8; 8];
let (prefix, lv) =
LayoutVerified::<_, u64>::new_from_suffix_zeroed(&mut buf.buf[..]).unwrap();
assert!(prefix.is_empty());
test_new_helper(lv);
}
}
#[test]
fn test_new_unaligned_sized() {
let mut buf = [0u8; 8];
test_new_helper_unaligned(
LayoutVerified::<_, [u8; 8]>::new_unaligned(&mut buf[..]).unwrap(),
);
buf = [0xFFu8; 8];
test_new_helper_unaligned(
LayoutVerified::<_, [u8; 8]>::new_unaligned_zeroed(&mut buf[..]).unwrap(),
);
{
buf = [0u8; 8];
let (lv, suffix) =
LayoutVerified::<_, [u8; 8]>::new_unaligned_from_prefix(&mut buf[..]).unwrap();
assert!(suffix.is_empty());
test_new_helper_unaligned(lv);
}
{
buf = [0xFFu8; 8];
let (lv, suffix) = LayoutVerified::<_, [u8; 8]>::new_unaligned_from_prefix_zeroed(
&mut buf[..],
).unwrap();
assert!(suffix.is_empty());
test_new_helper_unaligned(lv);
}
{
buf = [0u8; 8];
let (prefix, lv) =
LayoutVerified::<_, [u8; 8]>::new_unaligned_from_suffix(&mut buf[..]).unwrap();
assert!(prefix.is_empty());
test_new_helper_unaligned(lv);
}
{
buf = [0xFFu8; 8];
let (prefix, lv) = LayoutVerified::<_, [u8; 8]>::new_unaligned_from_suffix_zeroed(
&mut buf[..],
).unwrap();
assert!(prefix.is_empty());
test_new_helper_unaligned(lv);
}
}
#[test]
fn test_new_oversized() {
let mut buf = AlignedBuffer::<u64, [u8; 16]>::default();
{
let (lv, suffix) = LayoutVerified::<_, u64>::new_from_prefix(&mut buf.buf[..]).unwrap();
assert_eq!(suffix.len(), 8);
test_new_helper(lv);
}
{
buf.buf = [0xFFu8; 16];
let (lv, suffix) =
LayoutVerified::<_, u64>::new_from_prefix_zeroed(&mut buf.buf[..]).unwrap();
assert_eq!(suffix, &[0xFFu8; 8]);
test_new_helper(lv);
}
{
buf.clear_buf();
let (prefix, lv) = LayoutVerified::<_, u64>::new_from_suffix(&mut buf.buf[..]).unwrap();
assert_eq!(prefix.len(), 8);
test_new_helper(lv);
}
{
buf.buf = [0xFFu8; 16];
let (prefix, lv) =
LayoutVerified::<_, u64>::new_from_suffix_zeroed(&mut buf.buf[..]).unwrap();
assert_eq!(prefix, &[0xFFu8; 8]);
test_new_helper(lv);
}
}
#[test]
fn test_new_unaligned_oversized() {
let mut buf = [0u8; 16];
{
let (lv, suffix) =
LayoutVerified::<_, [u8; 8]>::new_unaligned_from_prefix(&mut buf[..]).unwrap();
assert_eq!(suffix.len(), 8);
test_new_helper_unaligned(lv);
}
{
buf = [0xFFu8; 16];
let (lv, suffix) = LayoutVerified::<_, [u8; 8]>::new_unaligned_from_prefix_zeroed(
&mut buf[..],
).unwrap();
assert_eq!(suffix, &[0xFF; 8]);
test_new_helper_unaligned(lv);
}
{
buf = [0u8; 16];
let (prefix, lv) =
LayoutVerified::<_, [u8; 8]>::new_unaligned_from_suffix(&mut buf[..]).unwrap();
assert_eq!(prefix.len(), 8);
test_new_helper_unaligned(lv);
}
{
buf = [0xFFu8; 16];
let (prefix, lv) = LayoutVerified::<_, [u8; 8]>::new_unaligned_from_suffix_zeroed(
&mut buf[..],
).unwrap();
assert_eq!(prefix, &[0xFF; 8]);
test_new_helper_unaligned(lv);
}
}
#[test]
fn test_new_fail() {
let mut buf = AlignedBuffer::<u64, [u8; 16]>::default();
assert!(LayoutVerified::<_, u64>::new(&buf.buf[..]).is_none());
assert!(LayoutVerified::<_, u64>::new_zeroed(&mut buf.buf[..]).is_none());
assert!(LayoutVerified::<_, [u8; 8]>::new_unaligned(&buf.buf[..]).is_none());
assert!(LayoutVerified::<_, [u8; 8]>::new_unaligned_zeroed(&mut buf.buf[..]).is_none());
let mut buf = AlignedBuffer::<u64, [u8; 4]>::default();
assert!(LayoutVerified::<_, u64>::new(&buf.buf[..]).is_none());
assert!(LayoutVerified::<_, u64>::new_zeroed(&mut buf.buf[..]).is_none());
assert!(LayoutVerified::<_, [u8; 8]>::new_unaligned(&buf.buf[..]).is_none());
assert!(LayoutVerified::<_, [u8; 8]>::new_unaligned_zeroed(&mut buf.buf[..]).is_none());
assert!(LayoutVerified::<_, u64>::new_from_prefix(&buf.buf[..]).is_none());
assert!(LayoutVerified::<_, u64>::new_from_prefix_zeroed(&mut buf.buf[..]).is_none());
assert!(LayoutVerified::<_, u64>::new_from_suffix(&buf.buf[..]).is_none());
assert!(LayoutVerified::<_, u64>::new_from_suffix_zeroed(&mut buf.buf[..]).is_none());
assert!(LayoutVerified::<_, [u8; 8]>::new_unaligned_from_prefix(&buf.buf[..]).is_none());
assert!(
LayoutVerified::<_, [u8; 8]>::new_unaligned_from_prefix_zeroed(&mut buf.buf[..])
.is_none()
);
assert!(LayoutVerified::<_, [u8; 8]>::new_unaligned_from_suffix(&buf.buf[..]).is_none());
assert!(
LayoutVerified::<_, [u8; 8]>::new_unaligned_from_suffix_zeroed(&mut buf.buf[..])
.is_none()
);
let mut buf = AlignedBuffer::<u64, [u8; 12]>::default();
assert!(LayoutVerified::<_, u64>::new(&buf.buf[4..]).is_none());
assert!(LayoutVerified::<_, u64>::new_zeroed(&mut buf.buf[4..]).is_none());
assert!(LayoutVerified::<_, u64>::new_from_prefix(&buf.buf[4..]).is_none());
assert!(LayoutVerified::<_, u64>::new_from_prefix_zeroed(&mut buf.buf[4..]).is_none());
assert!(LayoutVerified::<_, u64>::new_from_suffix(&buf.buf[..]).is_none());
assert!(LayoutVerified::<_, u64>::new_from_suffix_zeroed(&mut buf.buf[..]).is_none());
}
#[test]
fn test_display_debug() {
let buf = AlignedBuffer::<u64, [u8; 8]>::default();
let lv = LayoutVerified::<_, u64>::new(&buf.buf[..]).unwrap();
assert_eq!(format!("{}", lv), "0");
assert_eq!(format!("{:?}", lv), "LayoutVerified(0)");
}
}