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