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