#![no_std]
pub mod prelude {
pub use crate::{Extend as _, Truncate as _};
}
mod sealed {
pub trait Integer {}
macro_rules! impl_integer {
($($t:ty)*) => {$(
impl Integer for $t {}
)*};
}
impl_integer! {
u8 u16 u32 u64 u128 usize
i8 i16 i32 i64 i128 isize
}
pub trait ExtendTargetSealed<T> {
fn extend(self) -> T;
}
pub trait TruncateTargetSealed<T> {
fn truncate(self) -> T;
fn saturating_truncate(self) -> T;
fn checked_truncate(self) -> Option<T>;
}
}
pub trait ExtendTarget<T>: sealed::ExtendTargetSealed<T> {}
pub trait TruncateTarget<T>: sealed::TruncateTargetSealed<T> {}
pub trait Extend: sealed::Integer {
fn extend<T>(self) -> T
where
Self: ExtendTarget<T>;
}
impl<T: sealed::Integer> Extend for T {
fn extend<U>(self) -> U
where
T: ExtendTarget<U>,
{
sealed::ExtendTargetSealed::extend(self)
}
}
pub trait Truncate: sealed::Integer {
fn truncate<T>(self) -> T
where
Self: TruncateTarget<T>;
fn saturating_truncate<T>(self) -> T
where
Self: TruncateTarget<T>;
fn checked_truncate<T>(self) -> Option<T>
where
Self: TruncateTarget<T>;
}
impl<T: sealed::Integer> Truncate for T {
fn truncate<U>(self) -> U
where
T: TruncateTarget<U>,
{
sealed::TruncateTargetSealed::truncate(self)
}
fn saturating_truncate<U>(self) -> U
where
T: TruncateTarget<U>,
{
sealed::TruncateTargetSealed::saturating_truncate(self)
}
fn checked_truncate<U>(self) -> Option<U>
where
T: TruncateTarget<U>,
{
sealed::TruncateTargetSealed::checked_truncate(self)
}
}
macro_rules! impl_extend {
($($from:ty => $($to:ty),+;)*) => {$($(
const _: () = assert!(
core::mem::size_of::<$from>() <= core::mem::size_of::<$to>(),
concat!(
"cannot extend ",
stringify!($from),
" to ",
stringify!($to),
" because ",
stringify!($from),
" is larger than ",
stringify!($to)
)
);
impl sealed::ExtendTargetSealed<$to> for $from {
#[inline]
fn extend(self) -> $to {
self as _
}
}
impl ExtendTarget<$to> for $from {}
)+)*};
}
macro_rules! impl_truncate {
($($($from:ty),+ => $to:ty;)*) => {$($(
const _: () = assert!(
core::mem::size_of::<$from>() >= core::mem::size_of::<$to>(),
concat!(
"cannot truncate ",
stringify!($from),
" to ",
stringify!($to),
" because ",
stringify!($from),
" is smaller than ",
stringify!($to)
)
);
impl sealed::TruncateTargetSealed<$to> for $from {
#[inline]
fn truncate(self) -> $to {
self as _
}
#[inline]
fn saturating_truncate(self) -> $to {
if self > <$to>::MAX as _ {
<$to>::MAX
} else if self < <$to>::MIN as _ {
<$to>::MIN
} else {
self as _
}
}
#[inline]
fn checked_truncate(self) -> Option<$to> {
if self > <$to>::MAX as _ || self < <$to>::MIN as _ {
None
} else {
Some(self as _)
}
}
}
impl TruncateTarget<$to> for $from {}
)+)*};
}
impl_extend! {
u8 => u8, u16, u32, u64, u128, usize;
u16 => u16, u32, u64, u128, usize;
u32 => u32, u64, u128;
u64 => u64, u128;
u128 => u128;
usize => usize;
i8 => i8, i16, i32, i64, i128, isize;
i16 => i16, i32, i64, i128, isize;
i32 => i32, i64, i128;
i64 => i64, i128;
i128 => i128;
isize => isize;
}
impl_truncate! {
u8, u16, u32, u64, u128, usize => u8;
u16, u32, u64, u128, usize => u16;
u32, u64, u128 => u32;
u64, u128 => u64;
u128 => u128;
usize => usize;
i8, i16, i32, i64, i128, isize => i8;
i16, i32, i64, i128, isize => i16;
i32, i64, i128 => i32;
i64, i128 => i64;
i128 => i128;
isize => isize;
}