primitive_from/
lib.rs

1
2/// A generic interface for casting between machine scalars with the
3/// `as` operator, which admits narrowing and precision loss.
4/// Implementers of this trait PrimitiveFrom should behave like a primitive
5/// numeric type (e.g. a newtype around another primitive), and the
6/// intended conversion must never fail.
7///
8/// # Examples
9///
10/// ```
11/// # use primitive_from::PrimitiveFrom;
12/// let three: i32 = PrimitiveFrom::from(3.14159265f32);
13/// assert_eq!(three, 3);
14/// ```
15/// 
16/// # Safety
17/// 
18/// Currently, some uses of the `as` operator are not entirely safe.
19/// In particular, it is undefined behavior if:
20/// 
21/// - A truncated floating point value cannot fit in the target integer
22///   type ([#10184](https://github.com/rust-lang/rust/issues/10184));
23/// 
24/// ```ignore
25/// # use primitive_from::PrimitiveFrom;
26/// let x: u8 = PrimitiveFrom::from(1.04E+17); // UB
27/// ```
28/// 
29/// - Or a floating point value does not fit in another floating
30///   point type ([#15536](https://github.com/rust-lang/rust/issues/15536)).
31///
32/// ```ignore
33/// # use primitive_from::PrimitiveFrom;
34/// let x: f32 = PrimitiveFrom::from(1e300f64); // UB
35/// ```
36/// 
37pub trait PrimitiveFrom<T>
38{
39    fn from(_:T) -> Self;
40}
41
42macro_rules! impl_primitive_from {
43    ($U: ty => $( $T: ty ),* ) => {
44        $(
45        impl PrimitiveFrom<$U> for $T {
46            #[inline] fn from(a:$U) -> $T { a as $T }
47        }
48        )*
49    };
50}
51
52impl_primitive_from!(u8 => char, u8, i8, u16, i16, u32, i32, u64, isize, usize, i64, f32, f64);
53impl_primitive_from!(i8 => u8, i8, u16, i16, u32, i32, u64, isize, usize, i64, f32, f64);
54impl_primitive_from!(u16 => u8, i8, u16, i16, u32, i32, u64, isize, usize, i64, f32, f64);
55impl_primitive_from!(i16 => u8, i8, u16, i16, u32, i32, u64, isize, usize, i64, f32, f64);
56impl_primitive_from!(u32 => u8, i8, u16, i16, u32, i32, u64, isize, usize, i64, f32, f64);
57impl_primitive_from!(i32 => u8, i8, u16, i16, u32, i32, u64, isize, usize, i64, f32, f64);
58impl_primitive_from!(u64 => u8, i8, u16, i16, u32, i32, u64, isize, usize, i64, f32, f64);
59impl_primitive_from!(i64 => u8, i8, u16, i16, u32, i32, u64, isize, usize, i64, f32, f64);
60impl_primitive_from!(usize => u8, i8, u16, i16, u32, i32, u64, isize, usize, i64, f32, f64);
61impl_primitive_from!(isize => u8, i8, u16, i16, u32, i32, u64, isize, usize, i64, f32, f64);
62impl_primitive_from!(f32 => u8, i8, u16, i16, u32, i32, u64, isize, usize, i64, f32, f64);
63impl_primitive_from!(f64 => u8, i8, u16, i16, u32, i32, u64, isize, usize, i64, f32, f64);
64impl_primitive_from!(char => char, u8, i8, u16, i16, u32, i32, u64, isize, usize, i64);
65impl_primitive_from!(bool => u8, i8, u16, i16, u32, i32, u64, isize, usize, i64);
66
67
68#[test]
69fn as_primitive() {
70    let x: f32 = PrimitiveFrom::from(1.625f64);
71    assert_eq!(x, 1.625f32);
72
73    let x: f32 = PrimitiveFrom::from(3.14159265358979323846f64);
74    assert_eq!(x, 3.1415927f32);
75
76    let x: u8 = PrimitiveFrom::from(768i16);
77    assert_eq!(x, 0);
78}