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