use super::*;
pub trait BitPattern: Copy
{
type Bits: BitAnyPattern;
fn from_bits(bits: Self::Bits) -> Option<Self>
{
if Self::is_bit_pattern_valid(&bits)
{
Some(unsafe { *(&bits as *const Self::Bits as *const Self) })
}
else
{
None
}
}
fn is_bit_pattern_valid(bits: &Self::Bits) -> bool;
}
impl<T: BitAnyPattern> BitPattern for T
{
type Bits = T;
#[inline(always)]
fn from_bits(bits: Self::Bits) -> Option<Self> { Some(bits) }
#[inline(always)]
fn is_bit_pattern_valid(_bits: &Self::Bits) -> bool { true }
}
impl BitPattern for char
{
type Bits = u32;
#[inline(always)]
fn from_bits(bits: Self::Bits) -> Option<Self> { core::char::from_u32(bits) }
#[inline(always)]
fn is_bit_pattern_valid(bits: &Self::Bits) -> bool { Self::from_bits(*bits).is_some() }
}
impl BitPattern for bool
{
type Bits = u8;
#[inline(always)]
fn from_bits(bits: Self::Bits) -> Option<Self>
{
match bits
{
0 => Some(false),
1 => Some(true),
_ => None,
}
}
fn is_bit_pattern_valid(bits: &Self::Bits) -> bool
{
match bits
{
0 | 1 => true,
_ => false,
}
}
}
macro_rules! impl_checked_for_nonzero {
($($nonzero:ty: $primitive:ty),* $(,)?) => {
$(
impl BitPattern for $nonzero {
type Bits = $primitive;
#[inline(always)]
fn from_bits(bits: Self::Bits) -> Option<Self> {
<$nonzero>::new(bits)
}
fn is_bit_pattern_valid(bits: &Self::Bits) -> bool {
*bits != 0
}
}
)*
};
}
impl_checked_for_nonzero! {
core::num::NonZeroU8: u8,
core::num::NonZeroI8: i8,
core::num::NonZeroU16: u16,
core::num::NonZeroI16: i16,
core::num::NonZeroU32: u32,
core::num::NonZeroI32: i32,
core::num::NonZeroU64: u64,
core::num::NonZeroI64: i64,
core::num::NonZeroUsize: usize,
core::num::NonZeroIsize: isize,
}
#[inline(always)]
#[track_caller]
pub(crate) fn is_aligned_to(ptr: *const (), align: usize) -> bool
{
((ptr as usize) % align) == 0
}
#[inline(always)]
pub unsafe fn try_from_bytes_unchecked<T>(bytes: &[u8]) -> BitResult<&T>
{
if bytes.len() != size_of::<T>()
{
Err(BitError::SizeMismatch)
}
else if !is_aligned_to(bytes.as_ptr() as *const (), align_of::<T>())
{
Err(BitError::TargetAlignmentGreaterAndInputNotAligned)
}
else
{
Ok(unsafe { &*(bytes.as_ptr() as *const T) })
}
}
#[inline(always)]
pub fn try_from_bytes<T: BitPattern>(bytes: &[u8]) -> BitResult<&T>
{
let pod = unsafe { try_from_bytes_unchecked(bytes) }?;
if <T as BitPattern>::is_bit_pattern_valid(pod)
{
Ok(unsafe { &*(pod as *const <T as BitPattern>::Bits as *const T) })
}
else
{
Err(BitError::InvalidBitPattern)
}
}
#[inline(always)]
#[track_caller]
pub fn from_bytes<T: BitPattern>(bytes: &[u8]) -> &T
{
try_from_bytes(bytes).expect("invalid bits pattern")
}
#[inline(always)]
pub unsafe fn try_from_bytes_mut_unchecked<T>(bytes: &mut [u8]) -> BitResult<&mut T>
{
if bytes.len() != size_of::<T>()
{
Err(BitError::SizeMismatch)
}
else if !is_aligned_to(bytes.as_mut_ptr() as *mut (), align_of::<T>())
{
Err(BitError::TargetAlignmentGreaterAndInputNotAligned)
}
else
{
Ok(unsafe { &mut *(bytes.as_mut_ptr() as *mut T) })
}
}
#[inline(always)]
pub fn try_from_bytes_mut<T: BitPattern>(bytes: &mut [u8]) -> BitResult<&mut T>
{
let pod = unsafe { try_from_bytes_mut_unchecked(bytes) }?;
if <T as BitPattern>::is_bit_pattern_valid(pod)
{
Ok(unsafe { &mut *(pod as *mut <T as BitPattern>::Bits as *mut T) })
}
else
{
Err(BitError::InvalidBitPattern)
}
}
#[inline(always)]
#[track_caller]
pub fn from_bytes_mut<T: BitPattern>(bytes: &mut [u8]) -> &mut T
{
try_from_bytes_mut(bytes).expect("invalid bits pattern")
}
#[inline(always)]
pub unsafe fn try_transmute_slice_unchecked<Src: Copy, Dst: Copy>(src: &[Src])
-> BitResult<&[Dst]>
{
let input_bytes = core::mem::size_of_val::<[Src]>(src);
if align_of::<Dst>() > align_of::<Src>()
&& !is_aligned_to(src.as_ptr() as *const (), align_of::<Dst>())
{
Err(BitError::TargetAlignmentGreaterAndInputNotAligned)
}
else if size_of::<Dst>() == size_of::<Src>()
{
Ok(unsafe { core::slice::from_raw_parts(src.as_ptr() as *const Dst, src.len()) })
}
else if (size_of::<Dst>() != 0 && input_bytes % size_of::<Dst>() == 0)
|| (size_of::<Dst>() == 0 && input_bytes == 0)
{
let new_len = if size_of::<Dst>() != 0
{
input_bytes / size_of::<Dst>()
}
else
{
0
};
Ok(unsafe { core::slice::from_raw_parts(src.as_ptr() as *const Dst, new_len) })
}
else
{
Err(BitError::OutputSliceWouldHaveSlop)
}
}
#[inline(always)]
pub fn try_transmute_slice<Src: BitAllUsed, Dst: BitPattern>(a: &[Src]) -> BitResult<&[Dst]>
{
let pod = unsafe { crate::try_transmute_slice_unchecked(a) }?;
if pod
.iter()
.all(|pod| <Dst as BitPattern>::is_bit_pattern_valid(pod))
{
Ok(unsafe { core::slice::from_raw_parts(pod.as_ptr() as *const Dst, pod.len()) })
}
else
{
Err(BitError::InvalidBitPattern)
}
}
#[inline(always)]
#[track_caller]
pub fn transmute_slice<Src: BitAllUsed, Dst: BitPattern>(a: &[Src]) -> &[Dst]
{
try_transmute_slice(a).expect("invalid bits pattern")
}
#[inline(always)]
#[track_caller]
pub fn transmute_slice_mut<A: BitAllUsed + BitAnyPattern, B: BitAllUsed + BitPattern>(
a: &mut [A],
) -> &mut [B]
{
try_transmute_slice_mut(a).expect("invalid bits pattern")
}
#[inline(always)]
pub fn try_transmute_slice_mut<Src: BitAllUsed + BitAnyPattern, Dst: BitPattern + BitAllUsed>(
a: &mut [Src],
) -> BitResult<&mut [Dst]>
{
let pod = unsafe { crate::try_transmute_slice_mut_unchecked(a) }?;
if pod
.iter()
.all(|pod| <Dst as BitPattern>::is_bit_pattern_valid(pod))
{
Ok(unsafe { core::slice::from_raw_parts_mut(pod.as_mut_ptr() as *mut Dst, pod.len()) })
}
else
{
Err(BitError::InvalidBitPattern)
}
}
#[inline(always)]
pub unsafe fn try_transmute_slice_mut_unchecked<Src: Copy, Dst: Copy>(
src: &mut [Src],
) -> BitResult<&mut [Dst]>
{
let input_bytes = core::mem::size_of_val::<[Src]>(src);
if align_of::<Dst>() > align_of::<Src>()
&& !is_aligned_to(src.as_mut_ptr() as *mut (), align_of::<Dst>())
{
Err(BitError::TargetAlignmentGreaterAndInputNotAligned)
}
else if size_of::<Dst>() == size_of::<Src>()
{
Ok(unsafe { core::slice::from_raw_parts_mut(src.as_mut_ptr() as *mut Dst, src.len()) })
}
else if (size_of::<Dst>() != 0 && input_bytes % size_of::<Dst>() == 0)
|| (size_of::<Dst>() == 0 && input_bytes == 0)
{
let new_len = if size_of::<Dst>() != 0
{
input_bytes / size_of::<Dst>()
}
else
{
0
};
Ok(unsafe { core::slice::from_raw_parts_mut(src.as_mut_ptr() as *mut Dst, new_len) })
}
else
{
Err(BitError::OutputSliceWouldHaveSlop)
}
}
#[inline(always)]
#[track_caller]
pub unsafe fn try_transmute_unchecked<Src: Copy, Dst: Copy>(src: Src) -> BitResult<Dst>
{
if size_of::<Src>() == size_of::<Dst>()
{
unsafe {
Ok(core::mem::transmute_copy(&::core::mem::ManuallyDrop::new(
src,
)))
}
}
else
{
Err(BitError::SizeMismatch)
}
}
#[inline(always)]
#[track_caller]
pub fn try_transmute<Src: BitAllUsed, Dst: BitPattern>(src: Src) -> BitResult<Dst>
{
let pod = unsafe { try_transmute_unchecked(src)? };
match <Dst as BitPattern>::from_bits(pod)
{
Some(val) => Ok(val),
None => Err(BitError::InvalidBitPattern),
}
}
#[inline(always)]
#[track_caller]
pub fn transmute<Src: BitAllUsed, Dst: BitPattern>(src: Src) -> Dst
{
try_transmute(src).expect("invalid transmute")
}