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);