use crate::mem::transmute_unchecked;
use core::cmp::Ordering;
use core::fmt::Debug;
use core::fmt::Formatter;
use core::hash::Hash;
use core::hash::Hasher;
use core::marker::PhantomData;
use core::mem::size_of;
use core::ops::Deref;
use core::ops::DerefMut;
#[repr(transparent)]
pub struct TransmuteContract<IN, OUT> {
data: IN,
_pp: PhantomData<OUT>,
}
impl<IN, OUT> Clone for TransmuteContract<IN, OUT>
where
IN: Clone,
{
#[inline]
fn clone(&self) -> Self {
let new_data = Clone::clone(&self.data);
unsafe { Self::new_unchecked(new_data) }
}
}
impl<IN, OUT> Debug for TransmuteContract<IN, OUT>
where
IN: Debug,
{
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
Debug::fmt(&self.data as &IN, f)
}
}
impl<IN, OUT> PartialEq for TransmuteContract<IN, OUT>
where
IN: PartialEq,
{
#[inline]
fn eq(&self, other: &Self) -> bool {
PartialEq::eq(&self.data, other)
}
#[allow(clippy::partialeq_ne_impl)]
#[inline]
fn ne(&self, other: &Self) -> bool {
PartialEq::ne(&self.data as &IN, other)
}
}
impl<IN, OUT> PartialOrd for TransmuteContract<IN, OUT>
where
IN: PartialOrd,
{
#[inline]
fn partial_cmp(&self, o: &Self) -> Option<Ordering> {
PartialOrd::partial_cmp(&self.data as &IN, o)
}
#[inline]
fn lt(&self, other: &Self) -> bool {
PartialOrd::lt(&self.data as &IN, other)
}
#[inline]
fn le(&self, other: &Self) -> bool {
PartialOrd::le(&self.data as &IN, other)
}
#[inline]
fn gt(&self, other: &Self) -> bool {
PartialOrd::gt(&self.data as &IN, other)
}
#[inline]
fn ge(&self, other: &Self) -> bool {
PartialOrd::ge(&self.data as &IN, other)
}
}
impl<IN, OUT> Eq for TransmuteContract<IN, OUT> where IN: Eq {}
impl<IN, OUT> Ord for TransmuteContract<IN, OUT>
where
IN: Ord,
{
#[inline]
fn cmp(&self, c: &Self) -> core::cmp::Ordering {
Ord::cmp(&self.data as &IN, c)
}
}
impl<IN, OUT> Hash for TransmuteContract<IN, OUT>
where
IN: Hash,
{
#[inline]
fn hash<H>(&self, h: &mut H)
where
H: Hasher,
{
Hash::hash(&self.data as &IN, h)
}
}
impl<IN, OUT> TransmuteContract<IN, OUT> {
const TYPE_SIZE_MATCH_ASSERT: () = [()][
(size_of::<IN>() != size_of::<OUT>()) as usize
];
#[inline]
pub const unsafe fn new_unchecked(data: IN) -> Self {
#[allow(clippy::let_unit_value)]
let _constant_checking_of_input_and_output_type_dimensions = Self::TYPE_SIZE_MATCH_ASSERT;
Self {
data,
_pp: PhantomData,
}
}
#[inline]
pub const fn as_in(&self) -> &IN {
&self.data
}
#[inline]
pub const fn as_mut_in(&mut self) -> &mut IN {
&mut self.data
}
#[inline]
#[track_caller]
pub const fn as_out<'a>(&'a self) -> &'a OUT {
let data: &'a IN = self.as_in();
unsafe {
let new_data_ptr: &'a OUT = transmute_unchecked(data);
new_data_ptr
}
}
#[inline]
#[track_caller]
pub const fn as_mut_out<'a>(&'a mut self) -> &'a mut OUT {
let data: &'a mut IN = self.as_mut_in();
unsafe {
let new_data_ptr: &'a mut OUT = transmute_unchecked(data);
new_data_ptr
}
}
#[inline]
#[track_caller]
pub const fn release_indata(self) -> IN {
let sself: Self = self;
let data: IN = unsafe { transmute_unchecked(sself) };
data
}
#[inline]
#[track_caller]
pub const fn into(self) -> OUT {
let data: IN = self.release_indata();
unsafe {
let result: OUT = transmute_unchecked(data);
result
}
}
}
impl<IN, OUT> Deref for TransmuteContract<IN, OUT> {
type Target = IN;
#[inline]
fn deref(&self) -> &Self::Target {
self.as_in()
}
}
impl<IN, OUT> DerefMut for TransmuteContract<IN, OUT> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut_in()
}
}