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