#![no_std]
pub trait CastFrom<T>: Sized {
fn cast_from(value: T) -> Self;
}
pub trait CastInto<T>: Sized {
fn cast_into(self) -> T;
}
impl<T, U> CastInto<U> for T
where
U: CastFrom<T>,
{
fn cast_into(self) -> U {
CastFrom::cast_from(self)
}
}
macro_rules! nz {
(u8) => {
core::num::NonZeroU8
};
(i8) => {
core::num::NonZeroI8
};
(u16) => {
core::num::NonZeroU16
};
(i16) => {
core::num::NonZeroI16
};
(u32) => {
core::num::NonZeroU32
};
(i32) => {
core::num::NonZeroI32
};
(u64) => {
core::num::NonZeroU64
};
(i64) => {
core::num::NonZeroI64
};
(u128) => {
core::num::NonZeroU128
};
(i128) => {
core::num::NonZeroI128
};
(usize) => {
core::num::NonZeroUsize
};
(isize) => {
core::num::NonZeroIsize
};
}
macro_rules! cast_from {
($from:tt, $to:tt) => {
const _: () = {
let unsigned_from = <$from>::MIN == 0;
let unsigned_to = <$to>::MIN == 0;
if unsigned_from != unsigned_to {
panic!("signedness differ");
}
#[allow(clippy::cast_possible_truncation)]
if <$from>::MAX as $to as $from != <$from>::MAX {
panic!("from::MAX doesn't fit in to");
}
#[allow(clippy::cast_possible_truncation)]
if <$from>::MIN as $to as $from != <$from>::MIN {
panic!("from::MIN doesn't fit in to");
}
};
impl super::CastFrom<$from> for $to {
#[allow(clippy::cast_possible_truncation)]
fn cast_from(from: $from) -> $to {
from as $to
}
}
impl super::CastFrom<nz!($from)> for nz!($to) {
fn cast_from(from: nz!($from)) -> nz!($to) {
unsafe { <nz!($to)>::new_unchecked(super::CastFrom::cast_from(from.get())) }
}
}
};
}
#[cfg(target_pointer_width = "16")]
mod target16 {
cast_from!(u8, usize);
cast_from!(i8, isize);
cast_from!(u16, usize);
cast_from!(i16, isize);
cast_from!(usize, u16);
cast_from!(isize, i16);
cast_from!(usize, u32);
cast_from!(isize, i32);
cast_from!(usize, u64);
cast_from!(isize, i64);
cast_from!(usize, u128);
cast_from!(isize, i128);
}
#[cfg(target_pointer_width = "32")]
mod target32 {
cast_from!(u8, usize);
cast_from!(i8, isize);
cast_from!(u16, usize);
cast_from!(i16, isize);
cast_from!(u32, usize);
cast_from!(i32, isize);
cast_from!(usize, u32);
cast_from!(isize, i32);
cast_from!(usize, u64);
cast_from!(isize, i64);
cast_from!(usize, u128);
cast_from!(isize, i128);
}
#[cfg(target_pointer_width = "64")]
mod target64 {
cast_from!(u8, usize);
cast_from!(i8, isize);
cast_from!(u16, usize);
cast_from!(i16, isize);
cast_from!(u32, usize);
cast_from!(i32, isize);
cast_from!(u64, usize);
cast_from!(i64, isize);
cast_from!(usize, u64);
cast_from!(isize, i64);
cast_from!(usize, u128);
cast_from!(isize, i128);
}