1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
use std::fmt::Debug;

pub struct CastFailure<T, U: Debug> {
    value: U,
    _marker: std::marker::PhantomData<T>,
}

impl<T, U: Debug> Debug for CastFailure<T, U> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("CastFailure")
            .field("value", &self.value)
            .finish()
    }
}

impl<T, U: Debug> From<U> for CastFailure<T, U> {
    fn from(value: U) -> Self {
        Self {
            value,
            _marker: std::marker::PhantomData,
        }
    }
}

impl<T, U: Debug> std::fmt::Display for CastFailure<T, U> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "cast failed: value {:?} of type `{}` could not be represented by type `{}`",
            self.value,
            std::any::type_name::<U>(),
            std::any::type_name::<T>(),
        )
    }
}

impl<T, U: Debug> std::error::Error for CastFailure<T, U> {}

impl<T, U: Debug> CastFailure<T, U> {
    #[cold]
    fn panic(self) -> ! {
        panic!("{}", self);
    }
}

pub fn try_cast<T: num_traits::NumCast, U: Copy + Debug + num_traits::ToPrimitive>(
    n: U,
) -> Result<T, CastFailure<T, U>> {
    T::from(n).ok_or_else(move || n.into())
}

pub fn cast<T: num_traits::NumCast, U: Copy + Debug + num_traits::ToPrimitive>(n: U) -> T {
    try_cast(n).unwrap_or_else(move |err| err.panic())
}