Skip to main content

easy_cast/
impl_basic.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License in the LICENSE-APACHE file or at:
4//     https://www.apache.org/licenses/LICENSE-2.0
5
6//! Basic impls for Conv
7
8use super::*;
9
10/// Implement [`Conv`] infallibly over a [`From`] implementation
11///
12/// # Example
13///
14/// ```
15/// struct MyInt(i32);
16///
17/// impl From<MyInt> for i32 {
18///     fn from(x: MyInt) -> i32 {
19///         x.0
20///     }
21/// }
22///
23/// impl From<MyInt> for i64 {
24///     fn from(x: MyInt) -> i64 {
25///         x.0.into()
26///     }
27/// }
28///
29/// easy_cast::impl_via_from!(MyInt: i32, i64);
30/// ```
31#[macro_export]
32macro_rules! impl_via_from {
33    ($x:ty: $y:ty) => {
34        impl $crate::traits::Conv<$x> for $y {
35            #[inline]
36            fn conv(x: $x) -> $y {
37                <$y>::from(x)
38            }
39            #[inline]
40            fn try_conv(x: $x) -> $crate::Result<Self> {
41                Ok(<$y>::from(x))
42            }
43        }
44    };
45    ($x:ty: $y:ty, $($yy:ty),+) => {
46        $crate::impl_via_from!($x: $y);
47        $crate::impl_via_from!($x: $($yy),+);
48    };
49}
50
51impl_via_from!(i8: f32, f64, i16, i32, i64, i128);
52impl_via_from!(i16: f32, f64, i32, i64, i128);
53impl_via_from!(i32: f64, i64, i128);
54impl_via_from!(i64: i128);
55impl_via_from!(u8: f32, f64, i16, i32, i64, i128);
56impl_via_from!(u8: u16, u32, u64, u128);
57impl_via_from!(u16: f32, f64, i32, i64, i128, u32, u64, u128);
58impl_via_from!(u32: f64, i64, i128, u64, u128);
59impl_via_from!(u64: i128, u128);
60
61// TODO(unsize): remove T: Copy + Default bound
62// TODO(specialization): implement ConvApprox for arrays and tuples
63impl<S, T: Conv<S> + Copy + Default, const N: usize> Conv<[S; N]> for [T; N] {
64    #[inline]
65    fn try_conv(ss: [S; N]) -> Result<Self> {
66        let mut tt = [T::default(); N];
67        for (s, t) in IntoIterator::into_iter(ss).zip(tt.iter_mut()) {
68            *t = T::try_conv(s)?;
69        }
70        Ok(tt)
71    }
72    #[inline]
73    fn conv(ss: [S; N]) -> Self {
74        let mut tt = [T::default(); N];
75        for (s, t) in IntoIterator::into_iter(ss).zip(tt.iter_mut()) {
76            *t = T::conv(s);
77        }
78        tt
79    }
80}
81
82#[cfg(any(feature = "std", feature = "libm"))]
83impl<S, T: ConvFloat<S> + Copy + Default, const N: usize> ConvFloat<[S; N]> for [T; N] {
84    #[inline]
85    fn try_conv_trunc(ss: [S; N]) -> Result<Self> {
86        let mut tt = [T::default(); N];
87        for (s, t) in IntoIterator::into_iter(ss).zip(tt.iter_mut()) {
88            *t = T::try_conv_trunc(s)?;
89        }
90        Ok(tt)
91    }
92    #[inline]
93    fn try_conv_nearest(ss: [S; N]) -> Result<Self> {
94        let mut tt = [T::default(); N];
95        for (s, t) in IntoIterator::into_iter(ss).zip(tt.iter_mut()) {
96            *t = T::try_conv_nearest(s)?;
97        }
98        Ok(tt)
99    }
100    #[inline]
101    fn try_conv_floor(ss: [S; N]) -> Result<Self> {
102        let mut tt = [T::default(); N];
103        for (s, t) in IntoIterator::into_iter(ss).zip(tt.iter_mut()) {
104            *t = T::try_conv_floor(s)?;
105        }
106        Ok(tt)
107    }
108    #[inline]
109    fn try_conv_ceil(ss: [S; N]) -> Result<Self> {
110        let mut tt = [T::default(); N];
111        for (s, t) in IntoIterator::into_iter(ss).zip(tt.iter_mut()) {
112            *t = T::try_conv_ceil(s)?;
113        }
114        Ok(tt)
115    }
116
117    #[inline]
118    fn conv_trunc(ss: [S; N]) -> Self {
119        let mut tt = [T::default(); N];
120        for (s, t) in IntoIterator::into_iter(ss).zip(tt.iter_mut()) {
121            *t = T::conv_trunc(s);
122        }
123        tt
124    }
125    #[inline]
126    fn conv_nearest(ss: [S; N]) -> Self {
127        let mut tt = [T::default(); N];
128        for (s, t) in IntoIterator::into_iter(ss).zip(tt.iter_mut()) {
129            *t = T::conv_nearest(s);
130        }
131        tt
132    }
133    #[inline]
134    fn conv_floor(ss: [S; N]) -> Self {
135        let mut tt = [T::default(); N];
136        for (s, t) in IntoIterator::into_iter(ss).zip(tt.iter_mut()) {
137            *t = T::conv_floor(s);
138        }
139        tt
140    }
141    #[inline]
142    fn conv_ceil(ss: [S; N]) -> Self {
143        let mut tt = [T::default(); N];
144        for (s, t) in IntoIterator::into_iter(ss).zip(tt.iter_mut()) {
145            *t = T::conv_ceil(s);
146        }
147        tt
148    }
149}
150
151impl Conv<()> for () {
152    #[inline]
153    fn try_conv(_: ()) -> Result<Self> {
154        Ok(())
155    }
156    #[inline]
157    fn conv(_: ()) -> Self {}
158}
159impl<S0, T0: Conv<S0>> Conv<(S0,)> for (T0,) {
160    #[inline]
161    fn try_conv(ss: (S0,)) -> Result<Self> {
162        Ok((ss.0.try_cast()?,))
163    }
164    #[inline]
165    fn conv(ss: (S0,)) -> Self {
166        (ss.0.cast(),)
167    }
168}
169impl<S0, S1, T0: Conv<S0>, T1: Conv<S1>> Conv<(S0, S1)> for (T0, T1) {
170    #[inline]
171    fn try_conv(ss: (S0, S1)) -> Result<Self> {
172        Ok((ss.0.try_cast()?, ss.1.try_cast()?))
173    }
174    #[inline]
175    fn conv(ss: (S0, S1)) -> Self {
176        (ss.0.cast(), ss.1.cast())
177    }
178}
179impl<S0, S1, S2, T0: Conv<S0>, T1: Conv<S1>, T2: Conv<S2>> Conv<(S0, S1, S2)> for (T0, T1, T2) {
180    #[inline]
181    fn try_conv(ss: (S0, S1, S2)) -> Result<Self> {
182        Ok((ss.0.try_cast()?, ss.1.try_cast()?, ss.2.try_cast()?))
183    }
184    #[inline]
185    fn conv(ss: (S0, S1, S2)) -> Self {
186        (ss.0.cast(), ss.1.cast(), ss.2.cast())
187    }
188}
189impl<S0, S1, S2, S3, T0: Conv<S0>, T1: Conv<S1>, T2: Conv<S2>, T3: Conv<S3>> Conv<(S0, S1, S2, S3)>
190    for (T0, T1, T2, T3)
191{
192    #[inline]
193    fn try_conv(ss: (S0, S1, S2, S3)) -> Result<Self> {
194        Ok((
195            ss.0.try_cast()?,
196            ss.1.try_cast()?,
197            ss.2.try_cast()?,
198            ss.3.try_cast()?,
199        ))
200    }
201    #[inline]
202    fn conv(ss: (S0, S1, S2, S3)) -> Self {
203        (ss.0.cast(), ss.1.cast(), ss.2.cast(), ss.3.cast())
204    }
205}
206impl<S0, S1, S2, S3, S4, T0: Conv<S0>, T1: Conv<S1>, T2: Conv<S2>, T3: Conv<S3>, T4: Conv<S4>>
207    Conv<(S0, S1, S2, S3, S4)> for (T0, T1, T2, T3, T4)
208{
209    #[inline]
210    fn try_conv(ss: (S0, S1, S2, S3, S4)) -> Result<Self> {
211        Ok((
212            ss.0.try_cast()?,
213            ss.1.try_cast()?,
214            ss.2.try_cast()?,
215            ss.3.try_cast()?,
216            ss.4.try_cast()?,
217        ))
218    }
219    #[inline]
220    fn conv(ss: (S0, S1, S2, S3, S4)) -> Self {
221        (
222            ss.0.cast(),
223            ss.1.cast(),
224            ss.2.cast(),
225            ss.3.cast(),
226            ss.4.cast(),
227        )
228    }
229}
230impl<S0, S1, S2, S3, S4, S5, T0, T1, T2, T3, T4, T5> Conv<(S0, S1, S2, S3, S4, S5)>
231    for (T0, T1, T2, T3, T4, T5)
232where
233    T0: Conv<S0>,
234    T1: Conv<S1>,
235    T2: Conv<S2>,
236    T3: Conv<S3>,
237    T4: Conv<S4>,
238    T5: Conv<S5>,
239{
240    #[inline]
241    fn try_conv(ss: (S0, S1, S2, S3, S4, S5)) -> Result<Self> {
242        Ok((
243            ss.0.try_cast()?,
244            ss.1.try_cast()?,
245            ss.2.try_cast()?,
246            ss.3.try_cast()?,
247            ss.4.try_cast()?,
248            ss.5.try_cast()?,
249        ))
250    }
251    #[inline]
252    fn conv(ss: (S0, S1, S2, S3, S4, S5)) -> Self {
253        (
254            ss.0.cast(),
255            ss.1.cast(),
256            ss.2.cast(),
257            ss.3.cast(),
258            ss.4.cast(),
259            ss.5.cast(),
260        )
261    }
262}
263
264#[cfg(any(feature = "std", feature = "libm"))]
265impl<S0, S1, T0: ConvFloat<S0>, T1: ConvFloat<S1>> ConvFloat<(S0, S1)> for (T0, T1) {
266    #[inline]
267    fn try_conv_trunc(ss: (S0, S1)) -> Result<Self> {
268        Ok((T0::try_conv_trunc(ss.0)?, T1::try_conv_trunc(ss.1)?))
269    }
270    #[inline]
271    fn try_conv_nearest(ss: (S0, S1)) -> Result<Self> {
272        Ok((T0::try_conv_nearest(ss.0)?, T1::try_conv_nearest(ss.1)?))
273    }
274    #[inline]
275    fn try_conv_floor(ss: (S0, S1)) -> Result<Self> {
276        Ok((T0::try_conv_floor(ss.0)?, T1::try_conv_floor(ss.1)?))
277    }
278    #[inline]
279    fn try_conv_ceil(ss: (S0, S1)) -> Result<Self> {
280        Ok((T0::try_conv_ceil(ss.0)?, T1::try_conv_ceil(ss.1)?))
281    }
282
283    #[inline]
284    fn conv_trunc(ss: (S0, S1)) -> Self {
285        (T0::conv_trunc(ss.0), T1::conv_trunc(ss.1))
286    }
287    #[inline]
288    fn conv_nearest(ss: (S0, S1)) -> Self {
289        (T0::conv_nearest(ss.0), T1::conv_nearest(ss.1))
290    }
291    #[inline]
292    fn conv_floor(ss: (S0, S1)) -> Self {
293        (T0::conv_floor(ss.0), T1::conv_floor(ss.1))
294    }
295    #[inline]
296    fn conv_ceil(ss: (S0, S1)) -> Self {
297        (T0::conv_ceil(ss.0), T1::conv_ceil(ss.1))
298    }
299}
300
301/// Implement a trivial [`Conv`] infallibly
302///
303/// A trivial conversion is one which maps a type to itself.
304///
305/// # Example
306///
307/// ```
308/// struct MyInt(i32);
309///
310/// easy_cast::impl_via_trivial!(MyInt);
311/// ```
312#[macro_export]
313macro_rules! impl_via_trivial {
314    ($x:ty) => {
315        impl $crate::Conv<$x> for $x {
316            #[inline]
317            fn conv(x: $x) -> Self {
318                x
319            }
320            #[inline]
321            fn try_conv(x: $x) -> $crate::Result<Self> {
322                Ok(x)
323            }
324        }
325    };
326    ($x:ty $(, $xx:tt)* $(,)?) => {
327        $crate::impl_via_trivial!($x);
328        $crate::impl_via_trivial!($($xx),*);
329    };
330}
331
332#[rustfmt::skip]
333impl_via_trivial!(
334    u8, u16, u32, u64, u128, usize,
335    i8, i16, i32, i64, i128, isize,
336    f32, f64,
337);