use num::traits::bounds::UpperBounded;
use num::Signed;
use std::error::Error;
use std::fmt;
use std::ops::Deref;
pub trait CastFrom<T> {
fn cast_from(from: T) -> Self;
}
macro_rules! cast_from {
($from:ty, $to:ty) => {
paste::paste! {
impl crate::cast::CastFrom<$from> for $to {
#[allow(clippy::as_conversions)]
#[allow(unused)]
fn cast_from(from: $from) -> $to {
from as $to
}
}
#[allow(clippy::as_conversions)]
#[allow(unused)]
pub const fn [< $from _to_ $to >](from: $from) -> $to {
from as $to
}
}
};
}
#[cfg(target_pointer_width = "32")]
mod target32 {
cast_from!(u8, usize);
cast_from!(u16, usize);
cast_from!(u8, isize);
cast_from!(i8, isize);
cast_from!(u16, isize);
cast_from!(i16, isize);
cast_from!(usize, u64);
cast_from!(usize, i64);
cast_from!(usize, u128);
cast_from!(usize, i128);
cast_from!(isize, i64);
cast_from!(isize, i128);
cast_from!(usize, u32);
cast_from!(isize, i32);
cast_from!(u32, usize);
cast_from!(i32, isize);
}
#[cfg(target_pointer_width = "64")]
pub mod target64 {
cast_from!(u8, usize);
cast_from!(u16, usize);
cast_from!(u32, usize);
cast_from!(u8, isize);
cast_from!(i8, isize);
cast_from!(u16, isize);
cast_from!(i16, isize);
cast_from!(u32, isize);
cast_from!(i32, isize);
cast_from!(usize, u128);
cast_from!(usize, i128);
cast_from!(isize, i128);
cast_from!(usize, u64);
cast_from!(isize, i64);
cast_from!(u64, usize);
cast_from!(i64, isize);
}
cast_from!(u8, u8);
cast_from!(u8, u16);
cast_from!(u8, i16);
cast_from!(u8, u32);
cast_from!(u8, i32);
cast_from!(u8, u64);
cast_from!(u8, i64);
cast_from!(u8, u128);
cast_from!(u8, i128);
cast_from!(u16, u16);
cast_from!(u16, u32);
cast_from!(u16, i32);
cast_from!(u16, u64);
cast_from!(u16, i64);
cast_from!(u16, u128);
cast_from!(u16, i128);
cast_from!(u32, u32);
cast_from!(u32, u64);
cast_from!(u32, i64);
cast_from!(u32, u128);
cast_from!(u32, i128);
cast_from!(u64, u64);
cast_from!(u64, u128);
cast_from!(u64, i128);
cast_from!(i8, i8);
cast_from!(i8, i16);
cast_from!(i8, i32);
cast_from!(i8, i64);
cast_from!(i8, i128);
cast_from!(i16, i16);
cast_from!(i16, i32);
cast_from!(i16, i64);
cast_from!(i16, i128);
cast_from!(i32, i32);
cast_from!(i32, i64);
cast_from!(i32, i128);
cast_from!(i64, i64);
cast_from!(i64, i128);
pub trait TryCastFrom<T>: Sized {
fn try_cast_from(from: T) -> Option<Self>;
}
macro_rules! try_cast_from {
($from:ty, $to:ty) => {
impl crate::cast::TryCastFrom<$from> for $to {
#[allow(clippy::as_conversions)]
fn try_cast_from(from: $from) -> Option<$to> {
let to = from as $to;
let inverse = to as $from;
if from == inverse {
Some(to)
} else {
None
}
}
}
};
}
try_cast_from!(f64, i64);
try_cast_from!(i64, f64);
try_cast_from!(f64, u64);
try_cast_from!(u64, f64);
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
#[repr(transparent)]
pub struct NonNeg<T>(T)
where
T: Signed + fmt::Display;
impl<T> NonNeg<T>
where
T: Signed + fmt::Display,
{
pub fn min() -> NonNeg<T> {
NonNeg(T::zero())
}
pub fn max() -> NonNeg<T>
where
T: UpperBounded,
{
NonNeg(T::max_value())
}
pub fn try_from(n: T) -> Result<NonNeg<T>, NonNegError> {
match n.is_negative() {
false => Ok(NonNeg(n)),
true => Err(NonNegError),
}
}
}
impl<T> fmt::Display for NonNeg<T>
where
T: Signed + fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
impl<T> Deref for NonNeg<T>
where
T: Signed + fmt::Display,
{
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl From<NonNeg<i64>> for u64 {
fn from(n: NonNeg<i64>) -> u64 {
u64::try_from(*n).expect("non-negative")
}
}
#[cfg(target_pointer_width = "64")]
impl CastFrom<NonNeg<i64>> for usize {
#[allow(clippy::as_conversions)]
fn cast_from(from: NonNeg<i64>) -> usize {
usize::cast_from(u64::from(from))
}
}
#[derive(Debug, Clone)]
pub struct NonNegError;
impl fmt::Display for NonNegError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("cannot construct NonNeg from negative number")
}
}
impl Error for NonNegError {}