simba/scalar/
subset.rs

1#[cfg(feature = "decimal")]
2use decimal::d128;
3use num::Zero;
4use num_complex::Complex;
5
6/// Nested sets and conversions between them (using an injective mapping).
7///
8/// Useful to work with substructures. In generic code, it is preferable to use `SupersetOf`
9/// as trait bound whenever possible instead of `SubsetOf` (because `SupersetOf` is automatically
10/// implemented whenever `SubsetOf` is).
11///
12/// The notion of "nested sets" is very broad and applies to what the types are _supposed to
13/// represent_, independently from their actual implementation details and limitations. For
14/// example:
15/// * f32 and f64 are both supposed to represent reals and are thus considered equal (even if in
16///   practice f64 has more elements).
17/// * u32 and i8 are respectively supposed to represent natural and relative numbers. Thus, u32 is
18///   a subset of i8.
19/// * A quaternion and a 3x3 orthogonal matrix with unit determinant are both sets of rotations.
20///   They can thus be considered equal.
21///
22/// In other words, implementation details due to machine limitations are ignored (otherwise we
23/// could not even, e.g., convert a u64 to an i64). If considering those limitations are
24/// important, other crates allowing you to query the limitations of given types should be used.
25pub trait SubsetOf<T>: Sized {
26    /// The inclusion map: converts `self` to the equivalent element of its superset.
27    fn to_superset(&self) -> T;
28
29    /// The inverse inclusion map: attempts to construct `self` from the equivalent element of its
30    /// superset.
31    ///
32    /// Must return `None` if `element` has no equivalent in `Self`.
33    fn from_superset(element: &T) -> Option<Self> {
34        if Self::is_in_subset(element) {
35            Some(Self::from_superset_unchecked(element))
36        } else {
37            None
38        }
39    }
40
41    /// Use with care! Same as `self.to_superset` but without any property checks. Always succeeds.
42    fn from_superset_unchecked(element: &T) -> Self;
43
44    /// Checks if `element` is actually part of the subset `Self` (and can be converted to it).
45    fn is_in_subset(element: &T) -> bool;
46}
47
48/// Nested sets and conversions between them.
49///
50/// Useful to work with substructures. It is preferable to implement the `SubsetOf` trait instead
51/// of `SupersetOf` whenever possible (because `SupersetOf` is automatically implemented whenever
52/// `SubsetOf` is).
53///
54/// The notion of "nested sets" is very broad and applies to what the types are _supposed to
55/// represent_, independently from their actual implementation details and limitations. For
56/// example:
57/// * f32 and f64 are both supposed to represent reals and are thus considered equal (even if in
58///   practice f64 has more elements).
59/// * u32 and i8 are respectively supposed to represent natural and relative numbers. Thus, i8 is
60///   a superset of u32.
61/// * A quaternion and a 3x3 orthogonal matrix with unit determinant are both sets of rotations.
62///   They can thus be considered equal.
63///
64/// In other words, implementation details due to machine limitations are ignored (otherwise we
65/// could not even, e.g., convert a u64 to an i64). If considering those limitations are
66/// important, other crates allowing you to query the limitations of given types should be used.
67pub trait SupersetOf<T>: Sized {
68    /// The inverse inclusion map: attempts to construct `self` from the equivalent element of its
69    /// superset.
70    ///
71    /// Must return `None` if `element` has no equivalent in `Self`.
72    fn to_subset(&self) -> Option<T> {
73        if self.is_in_subset() {
74            Some(self.to_subset_unchecked())
75        } else {
76            None
77        }
78    }
79
80    /// Checks if `self` is actually part of its subset `T` (and can be converted to it).
81    fn is_in_subset(&self) -> bool;
82
83    /// Use with care! Same as `self.to_subset` but without any property checks. Always succeeds.
84    fn to_subset_unchecked(&self) -> T;
85
86    /// The inclusion map: converts `self` to the equivalent element of its superset.
87    fn from_subset(element: &T) -> Self;
88}
89
90impl<SS: SubsetOf<SP>, SP> SupersetOf<SS> for SP {
91    #[inline]
92    fn to_subset(&self) -> Option<SS> {
93        SS::from_superset(self)
94    }
95
96    #[inline]
97    fn is_in_subset(&self) -> bool {
98        SS::is_in_subset(self)
99    }
100
101    #[inline]
102    fn to_subset_unchecked(&self) -> SS {
103        SS::from_superset_unchecked(self)
104    }
105
106    #[inline]
107    fn from_subset(element: &SS) -> Self {
108        element.to_superset()
109    }
110}
111
112macro_rules! impl_subset (
113    ($($subset: ty as $( $superset: ty),+ );* $(;)*) => {
114        $($(
115        impl SubsetOf<$superset> for $subset {
116            #[inline]
117            fn to_superset(&self) -> $superset {
118                *self as $superset
119            }
120
121            #[inline]
122            fn from_superset_unchecked(element: &$superset) -> $subset {
123                *element as $subset
124            }
125
126            #[inline]
127            fn is_in_subset(_: &$superset) -> bool {
128                true
129            }
130        }
131        )+)*
132    }
133);
134
135impl_subset!(
136    u8    as u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64;
137    u16   as u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64;
138    u32   as u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64;
139    u64   as u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64;
140    u128  as u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64;
141    usize as u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64;
142
143    i8    as i8, i16, i32, i64, i128, isize, f32, f64;
144    i16   as i8, i16, i32, i64, i128, isize, f32, f64;
145    i32   as i8, i16, i32, i64, i128, isize, f32, f64;
146    i64   as i8, i16, i32, i64, i128, isize, f32, f64;
147    i128  as i8, i16, i32, i64, i128, isize, f32, f64;
148    isize as i8, i16, i32, i64, i128, isize, f32, f64;
149
150    f32 as f32, f64;
151    f64 as f32, f64;
152);
153//#[cfg(feature = "decimal")]
154//impl_subset!(
155//    u8 as d128;
156//    u16 as d128;
157//    u32 as d128;
158//    u64 as d128;
159//    usize as d128;
160//
161//    i8 as d128;
162//    i16 as d128;
163//    i32 as d128;
164//    i64 as d128;
165//    isize as d128;
166//
167//    f32 as d128;
168//    f64 as d128;
169//    d128 as d128;
170//);
171
172impl<N1, N2: SupersetOf<N1>> SubsetOf<Complex<N2>> for Complex<N1> {
173    #[inline]
174    fn to_superset(&self) -> Complex<N2> {
175        Complex {
176            re: N2::from_subset(&self.re),
177            im: N2::from_subset(&self.im),
178        }
179    }
180
181    #[inline]
182    fn from_superset_unchecked(element: &Complex<N2>) -> Complex<N1> {
183        Complex {
184            re: element.re.to_subset_unchecked(),
185            im: element.im.to_subset_unchecked(),
186        }
187    }
188
189    #[inline]
190    fn is_in_subset(c: &Complex<N2>) -> bool {
191        c.re.is_in_subset() && c.im.is_in_subset()
192    }
193}
194
195macro_rules! impl_scalar_subset_of_complex (
196    ($($t: ident),*) => {$(
197        impl<N2: Zero + SupersetOf<$t>> SubsetOf<Complex<N2>> for $t {
198            #[inline]
199            fn to_superset(&self) -> Complex<N2> {
200                Complex {
201                    re: N2::from_subset(self),
202                    im: N2::zero()
203                }
204            }
205
206            #[inline]
207            fn from_superset_unchecked(element: &Complex<N2>) -> $t {
208                element.re.to_subset_unchecked()
209            }
210
211            #[inline]
212            fn is_in_subset(c: &Complex<N2>) -> bool {
213                c.re.is_in_subset() && c.im.is_zero()
214            }
215        }
216    )*}
217);
218
219impl_scalar_subset_of_complex!(
220    u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64
221);
222#[cfg(feature = "decimal")]
223impl_scalar_subset_of_complex!(d128);