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