#![no_std]
#![warn(missing_docs)]
#[cfg(target_arch = "x86")]
use core::arch::x86;
#[cfg(target_arch = "x86_64")]
use core::arch::x86_64;
use core::{marker::*, mem::*, num::*, ptr::*};
#[doc(hidden)]
pub use ::core as __core;
macro_rules! impl_unsafe_marker_for_array {
( $marker:ident , $( $n:expr ),* ) => {
$(unsafe impl<T> $marker for [T; $n] where T: $marker {})*
}
}
#[cfg(feature = "extern_crate_std")]
extern crate std;
#[cfg(feature = "extern_crate_alloc")]
extern crate alloc;
#[cfg(feature = "extern_crate_alloc")]
pub mod allocation;
#[cfg(feature = "extern_crate_alloc")]
pub use allocation::*;
mod zeroable;
pub use zeroable::*;
mod pod;
pub use pod::*;
mod contiguous;
pub use contiguous::*;
mod offset_of;
pub use offset_of::*;
mod transparent;
pub use transparent::*;
#[cold]
#[inline(never)]
fn something_went_wrong(src: &str, err: PodCastError) -> ! {
panic!("{src}>{err:?}", src = src, err = err)
}
#[inline]
pub fn bytes_of<T: Pod>(t: &T) -> &[u8] {
match try_cast_slice::<T, u8>(core::slice::from_ref(t)) {
Ok(s) => s,
Err(_) => unreachable!(),
}
}
#[inline]
pub fn bytes_of_mut<T: Pod>(t: &mut T) -> &mut [u8] {
match try_cast_slice_mut::<T, u8>(core::slice::from_mut(t)) {
Ok(s) => s,
Err(_) => unreachable!(),
}
}
#[inline]
pub fn from_bytes<T: Pod>(s: &[u8]) -> &T {
match try_from_bytes(s) {
Ok(t) => t,
Err(e) => something_went_wrong("from_bytes", e),
}
}
#[inline]
pub fn from_bytes_mut<T: Pod>(s: &mut [u8]) -> &mut T {
match try_from_bytes_mut(s) {
Ok(t) => t,
Err(e) => something_went_wrong("from_bytes_mut", e),
}
}
#[inline]
pub fn try_from_bytes<T: Pod>(s: &[u8]) -> Result<&T, PodCastError> {
if s.len() != size_of::<T>() {
Err(PodCastError::SizeMismatch)
} else if (s.as_ptr() as usize) % align_of::<T>() != 0 {
Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)
} else {
Ok(unsafe { &*(s.as_ptr() as *const T) })
}
}
#[inline]
pub fn try_from_bytes_mut<T: Pod>(
s: &mut [u8],
) -> Result<&mut T, PodCastError> {
if s.len() != size_of::<T>() {
Err(PodCastError::SizeMismatch)
} else if (s.as_ptr() as usize) % align_of::<T>() != 0 {
Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)
} else {
Ok(unsafe { &mut *(s.as_mut_ptr() as *mut T) })
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PodCastError {
TargetAlignmentGreaterAndInputNotAligned,
OutputSliceWouldHaveSlop,
SizeMismatch,
AlignmentMismatch,
}
impl core::fmt::Display for PodCastError {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{:?}", self)
}
}
#[cfg(feature = "extern_crate_std")]
impl std::error::Error for PodCastError {}
#[inline]
pub fn cast<A: Pod, B: Pod>(a: A) -> B {
if size_of::<A>() == size_of::<B>() {
match try_cast(a) {
Ok(b) => b,
Err(_) => unreachable!(),
}
} else {
match try_cast(a) {
Ok(b) => b,
Err(e) => something_went_wrong("cast", e),
}
}
}
#[inline]
pub fn cast_mut<A: Pod, B: Pod>(a: &mut A) -> &mut B {
if size_of::<A>() == size_of::<B>() && align_of::<A>() >= align_of::<B>() {
match try_cast_mut(a) {
Ok(b) => b,
Err(_) => unreachable!(),
}
} else {
match try_cast_mut(a) {
Ok(b) => b,
Err(e) => something_went_wrong("cast_mut", e),
}
}
}
#[inline]
pub fn cast_ref<A: Pod, B: Pod>(a: &A) -> &B {
if size_of::<A>() == size_of::<B>() && align_of::<A>() >= align_of::<B>() {
match try_cast_ref(a) {
Ok(b) => b,
Err(_) => unreachable!(),
}
} else {
match try_cast_ref(a) {
Ok(b) => b,
Err(e) => something_went_wrong("cast_ref", e),
}
}
}
#[inline]
pub fn cast_slice<A: Pod, B: Pod>(a: &[A]) -> &[B] {
match try_cast_slice(a) {
Ok(b) => b,
Err(e) => something_went_wrong("cast_slice", e),
}
}
#[inline]
pub fn cast_slice_mut<A: Pod, B: Pod>(a: &mut [A]) -> &mut [B] {
match try_cast_slice_mut(a) {
Ok(b) => b,
Err(e) => something_went_wrong("cast_slice_mut", e),
}
}
#[inline]
pub fn pod_align_to<T: Pod, U: Pod>(vals: &[T]) -> (&[T], &[U], &[T]) {
unsafe { vals.align_to::<U>() }
}
#[inline]
pub fn pod_align_to_mut<T: Pod, U: Pod>(
vals: &mut [T],
) -> (&mut [T], &mut [U], &mut [T]) {
unsafe { vals.align_to_mut::<U>() }
}
#[inline]
pub fn try_cast<A: Pod, B: Pod>(a: A) -> Result<B, PodCastError> {
if size_of::<A>() == size_of::<B>() {
let mut b = B::zeroed();
let ap = &a as *const A as *const u8;
let bp = &mut b as *mut B as *mut u8;
unsafe { ap.copy_to_nonoverlapping(bp, size_of::<A>()) };
Ok(b)
} else {
Err(PodCastError::SizeMismatch)
}
}
#[inline]
pub fn try_cast_ref<A: Pod, B: Pod>(a: &A) -> Result<&B, PodCastError> {
if align_of::<B>() > align_of::<A>()
&& (a as *const A as usize) % align_of::<B>() != 0
{
Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)
} else if size_of::<B>() == size_of::<A>() {
Ok(unsafe { &*(a as *const A as *const B) })
} else {
Err(PodCastError::SizeMismatch)
}
}
#[inline]
pub fn try_cast_mut<A: Pod, B: Pod>(a: &mut A) -> Result<&mut B, PodCastError> {
if align_of::<B>() > align_of::<A>()
&& (a as *mut A as usize) % align_of::<B>() != 0
{
Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)
} else if size_of::<B>() == size_of::<A>() {
Ok(unsafe { &mut *(a as *mut A as *mut B) })
} else {
Err(PodCastError::SizeMismatch)
}
}
#[inline]
pub fn try_cast_slice<A: Pod, B: Pod>(a: &[A]) -> Result<&[B], PodCastError> {
if align_of::<B>() > align_of::<A>()
&& (a.as_ptr() as usize) % align_of::<B>() != 0
{
Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)
} else if size_of::<B>() == size_of::<A>() {
Ok(unsafe { core::slice::from_raw_parts(a.as_ptr() as *const B, a.len()) })
} else if size_of::<A>() == 0 || size_of::<B>() == 0 {
Err(PodCastError::SizeMismatch)
} else if core::mem::size_of_val(a) % size_of::<B>() == 0 {
let new_len = core::mem::size_of_val(a) / size_of::<B>();
Ok(unsafe { core::slice::from_raw_parts(a.as_ptr() as *const B, new_len) })
} else {
Err(PodCastError::OutputSliceWouldHaveSlop)
}
}
#[inline]
pub fn try_cast_slice_mut<A: Pod, B: Pod>(
a: &mut [A],
) -> Result<&mut [B], PodCastError> {
if align_of::<B>() > align_of::<A>()
&& (a.as_mut_ptr() as usize) % align_of::<B>() != 0
{
Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)
} else if size_of::<B>() == size_of::<A>() {
Ok(unsafe {
core::slice::from_raw_parts_mut(a.as_mut_ptr() as *mut B, a.len())
})
} else if size_of::<A>() == 0 || size_of::<B>() == 0 {
Err(PodCastError::SizeMismatch)
} else if core::mem::size_of_val(a) % size_of::<B>() == 0 {
let new_len = core::mem::size_of_val(a) / size_of::<B>();
Ok(unsafe {
core::slice::from_raw_parts_mut(a.as_mut_ptr() as *mut B, new_len)
})
} else {
Err(PodCastError::OutputSliceWouldHaveSlop)
}
}