use crate::pointer::{CoerceSlice, Pointee, Size};
use crate::traits::ZeroCopy;
pub trait Coerce<U: ?Sized + Pointee>: Pointee {
fn coerce_metadata<O: Size>(metadata: Self::Stored<O>) -> U::Stored<O>;
fn try_coerce_metadata<O: Size>(metadata: Self::Stored<O>) -> Option<U::Stored<O>>;
}
impl<T, U> Coerce<[U]> for [T]
where
T: ZeroCopy,
U: ZeroCopy,
[T]: CoerceSlice<[U]>,
{
#[inline]
fn coerce_metadata<O: Size>(metadata: O) -> O {
<[T]>::resize(metadata)
}
#[inline]
fn try_coerce_metadata<O: Size>(metadata: O) -> Option<O> {
<[T]>::try_resize(metadata)
}
}
impl<T> Coerce<[T]> for str
where
[u8]: CoerceSlice<[T]>,
T: ZeroCopy,
{
#[inline]
fn coerce_metadata<O: Size>(metadata: O) -> O {
<[u8]>::resize(metadata)
}
#[inline]
fn try_coerce_metadata<O: Size>(metadata: O) -> Option<O> {
<[u8]>::try_resize(metadata)
}
}
impl<T> Coerce<str> for [T]
where
[T]: CoerceSlice<[u8]>,
T: ZeroCopy,
{
#[inline]
fn coerce_metadata<O: Size>(metadata: O) -> O {
<[T]>::resize(metadata)
}
#[inline]
fn try_coerce_metadata<O: Size>(metadata: O) -> Option<O> {
<[T]>::try_resize(metadata)
}
}
macro_rules! same_size_inner {
($from:ty, {$($to:ty),*}) => {
$(
#[doc = concat!("Defines the coercion for `", stringify!($from) ,"` to `", stringify!($to), "`.")]
#[doc = concat!("let reference: Ref<", stringify!($from), "> = Ref::zero();")]
#[doc = concat!("let reference2 = reference.coerce::<", stringify!($to), ">();")]
impl Coerce<$to> for $from {
#[inline(always)]
fn coerce_metadata<O: Size>(metadata: ()) -> () {
metadata
}
#[inline(always)]
fn try_coerce_metadata<O: Size>(metadata: ()) -> Option<()> {
Some(metadata)
}
}
)*
}
}
macro_rules! same_size {
([$({$($from:ty),*}),*], [$($to:tt),*]) => {
$(
$(
same_size_inner!($from, $to);
)*
)*
};
}
same_size!([{u8, i8}], [{u8, i8}]);
same_size!([{u16, i16}], [{u16, i16, [u8; 2], [i8; 2]}]);
same_size!([{u32, i32}], [{u32, i32, [u16; 2], [i16; 2], [u8; 4], [i8; 4]}]);
same_size!([{u64, i64}], [{u64, i64, [u32; 2], [i32; 2], [u16; 4], [i16; 4], [u8; 8], [i8; 8]}]);
same_size!([{u128, i128}], [{u128, i128, [u64; 2], [i64; 2], [u32; 4], [i32; 4], [u16; 8], [i16; 8], [u8; 16], [i8; 16]}]);
impl<T, U> Coerce<[U]> for T
where
T: ZeroCopy,
U: ZeroCopy,
[T]: CoerceSlice<[U]>,
{
#[inline]
fn coerce_metadata<O: Size>((): ()) -> O {
<[T]>::resize(O::ONE)
}
#[inline]
fn try_coerce_metadata<O: Size>((): ()) -> Option<O> {
<[T]>::try_resize(O::ONE)
}
}
impl<T, const N: usize, U> Coerce<[U]> for [T; N]
where
T: ZeroCopy,
U: ZeroCopy,
[T]: CoerceSlice<[U]>,
{
#[inline]
fn coerce_metadata<O: Size>((): ()) -> <[T] as Pointee>::Stored<O> {
let factor = O::try_from_usize(N).unwrap_or(O::MAX);
<[T]>::resize(factor)
}
#[inline]
fn try_coerce_metadata<O: Size>((): ()) -> Option<<[T] as Pointee>::Stored<O>> {
let factor = O::try_from_usize(N)?;
<[T]>::try_resize(factor)
}
}
macro_rules! non_zero_inner {
($from:ident, {$($to:ty),*}) => {
$(
#[doc = concat!("Defines the coercion for `", stringify!($from) ,"` to `", stringify!($to), "`.")]
#[doc = concat!("use std::num::", stringify!($from), ";")]
#[doc = concat!("let reference: Ref<", stringify!($from), "> = Ref::zero();")]
#[doc = concat!("let reference2 = reference.coerce::<", stringify!($to), ">();")]
impl Coerce<$to> for core::num::$from {
#[inline(always)]
fn coerce_metadata<O: Size>(metadata: ()) -> () {
metadata
}
#[inline(always)]
fn try_coerce_metadata<O: Size>(metadata: ()) -> Option<()> {
Some(metadata)
}
}
)*
}
}
macro_rules! non_zero {
([$({$($from:ident),*}),*], [$($to:tt),*]) => {
$(
$(
non_zero_inner!($from, $to);
)*
)*
};
}
non_zero!([{NonZeroU8, NonZeroI8}], [{u8, i8}]);
non_zero!([{NonZeroU16, NonZeroI16}], [{u16, i16}]);
non_zero!([{NonZeroU32, NonZeroI32}], [{u32, i32}]);
non_zero!([{NonZeroU64, NonZeroI64}], [{u64, i64}]);
non_zero!([{NonZeroU128, NonZeroI128}], [{u128, i128}]);
impl<T, U> Coerce<U> for core::num::Wrapping<T>
where
T: Coerce<U>,
U: ZeroCopy,
T: ZeroCopy,
{
#[inline(always)]
fn coerce_metadata<O: Size>(metadata: ()) {
metadata
}
#[inline(always)]
fn try_coerce_metadata<O: Size>(metadata: ()) -> Option<()> {
Some(metadata)
}
}