Skip to content

Commit

Permalink
Merge pull request #296 from philipc/issue-294
Browse files Browse the repository at this point in the history
pod: add from_bytes_mut and slice_from_bytes_mut
  • Loading branch information
philipc authored May 4, 2021
2 parents 78e6222 + 86412b7 commit 5841d60
Showing 1 changed file with 49 additions and 4 deletions.
53 changes: 49 additions & 4 deletions src/pod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,37 +27,82 @@ pub unsafe trait Pod: Copy + 'static {}
/// Returns the type and the tail of the slice.
#[inline]
pub fn from_bytes<T: Pod>(data: &[u8]) -> Result<(&T, &[u8])> {
let size = mem::size_of::<T>();
let tail = data.get(size..).ok_or(())?;
let ptr = data.as_ptr();
if (ptr as usize) % mem::align_of::<T>() != 0 {
return Err(());
}
let size = mem::size_of::<T>();
let tail = data.get(size..).ok_or(())?;
// Safety:
// The alignment and size are checked by this function.
// The Pod trait ensures the type is valid to cast from bytes.
let val = unsafe { &*ptr.cast() };
Ok((val, tail))
}

/// Cast a mutable byte slice to a `Pod` type.
///
/// Returns the type and the tail of the slice.
#[inline]
pub fn from_bytes_mut<T: Pod>(data: &mut [u8]) -> Result<(&mut T, &mut [u8])> {
let size = mem::size_of::<T>();
if size > data.len() {
return Err(());
}
let (data, tail) = data.split_at_mut(size);
let ptr = data.as_mut_ptr();
if (ptr as usize) % mem::align_of::<T>() != 0 {
return Err(());
}
// Safety:
// The alignment and size are checked by this function.
// The Pod trait ensures the type is valid to cast from bytes.
let val = unsafe { &mut *ptr.cast() };
Ok((val, tail))
}

/// Cast a byte slice to a slice of a `Pod` type.
///
/// Returns the type slice and the tail of the byte slice.
#[inline]
pub fn slice_from_bytes<T: Pod>(data: &[u8], count: usize) -> Result<(&[T], &[u8])> {
let size = count.checked_mul(mem::size_of::<T>()).ok_or(())?;
let tail = data.get(size..).ok_or(())?;
let ptr = data.as_ptr();
if (ptr as usize) % mem::align_of::<T>() != 0 {
return Err(());
}
let size = count.checked_mul(mem::size_of::<T>()).ok_or(())?;
let tail = data.get(size..).ok_or(())?;
// Safety:
// The alignment and size are checked by this function.
// The Pod trait ensures the type is valid to cast from bytes.
let slice = unsafe { slice::from_raw_parts(ptr.cast(), count) };
Ok((slice, tail))
}

/// Cast a mutable byte slice to a slice of a `Pod` type.
///
/// Returns the type slice and the tail of the byte slice.
#[inline]
pub fn slice_from_bytes_mut<T: Pod>(
data: &mut [u8],
count: usize,
) -> Result<(&mut [T], &mut [u8])> {
let size = count.checked_mul(mem::size_of::<T>()).ok_or(())?;
if size > data.len() {
return Err(());
}
let (data, tail) = data.split_at_mut(size);
let ptr = data.as_mut_ptr();
if (ptr as usize) % mem::align_of::<T>() != 0 {
return Err(());
}
// Safety:
// The alignment and size are checked by this function.
// The Pod trait ensures the type is valid to cast from bytes.
let slice = unsafe { slice::from_raw_parts_mut(ptr.cast(), count) };
Ok((slice, tail))
}

/// Cast a `Pod` type to a byte slice.
#[inline]
pub fn bytes_of<T: Pod>(val: &T) -> &[u8] {
Expand Down

0 comments on commit 5841d60

Please sign in to comment.