| |
1 /*! |
| |
2 Helper traits to work with references or owned values of types and their subsets. |
| |
3 */ |
| |
4 |
| |
5 #[derive(Clone, Copy)] |
| |
6 pub enum EitherDecomp<A, B> { |
| |
7 Owned(A), |
| |
8 Borrowed(B), |
| |
9 } |
| |
10 |
| |
11 /// A very basic implementation of [`Cow`] without a [`Clone`] trait dependency. |
| |
12 pub type MyCow<'b, X> = EitherDecomp<X, &'b X>; |
| |
13 |
| |
14 impl<'b, X> std::ops::Deref for MyCow<'b, X> { |
| |
15 type Target = X; |
| |
16 |
| |
17 #[inline] |
| |
18 fn deref(&self) -> &Self::Target { |
| |
19 match self { |
| |
20 EitherDecomp::Owned(x) => &x, |
| |
21 EitherDecomp::Borrowed(x) => x, |
| |
22 } |
| |
23 } |
| |
24 } |
| |
25 |
| |
26 impl<'b, X> MyCow<'b, X> { |
| |
27 #[inline] |
| |
28 pub fn into_owned(self) -> X where X : Clone { |
| |
29 match self { |
| |
30 EitherDecomp::Owned(x) => x, |
| |
31 EitherDecomp::Borrowed(x) => x.clone(), |
| |
32 } |
| |
33 } |
| |
34 } |
| |
35 |
| |
36 /// Trait for abitrary mathematical spaces. |
| |
37 pub trait Space : Instance<Self, Self::Decomp> { |
| |
38 /// Default decomposition for the space |
| |
39 type Decomp : Decomposition<Self>; |
| |
40 } |
| |
41 |
| |
42 #[macro_export] |
| |
43 macro_rules! impl_basic_space { |
| |
44 ($($type:ty)*) => { $( |
| |
45 impl $crate::instance::Space for $type { |
| |
46 type Decomp = $crate::instance::BasicDecomposition; |
| |
47 } |
| |
48 )* }; |
| |
49 ($type:ty where $($where:tt)*) => { |
| |
50 impl<$($where)*> $crate::instance::Space for $type { |
| |
51 type Decomp = $crate::instance::BasicDecomposition; |
| |
52 } |
| |
53 }; |
| |
54 } |
| |
55 |
| |
56 impl_basic_space!(u8 u16 u32 u64 u128 usize |
| |
57 i8 i16 i32 i64 i128 isize |
| |
58 f32 f64); |
| |
59 |
| |
60 /// Marker type for decompositions to be used with [`Instance`]. |
| |
61 pub trait Decomposition<X : Space> : Sized { |
| |
62 /// Possibly owned form of the decomposition |
| |
63 type Decomposition<'b> : Instance<X, Self> where X : 'b; |
| |
64 /// Unlikely owned form of the decomposition. |
| |
65 /// Type for a lightweight intermediate conversion that does not own the original variable. |
| |
66 /// Usually this is just a reference, but may also be a lightweight structure that |
| |
67 /// contains references; see the implementation for [`crate::direct_product::Pair`]. |
| |
68 type Reference<'b> : Instance<X, Self> + Copy where X : 'b; |
| |
69 |
| |
70 /// Left the lightweight reference type into a full decomposition type. |
| |
71 fn lift<'b>(r : Self::Reference<'b>) -> Self::Decomposition<'b>; |
| |
72 } |
| |
73 |
| |
74 /// Most common [`Decomposition`] (into `Either<X, &'b X>`) that allows working with owned |
| |
75 /// values and all sorts of references. |
| |
76 #[derive(Copy, Clone, Debug)] |
| |
77 pub struct BasicDecomposition; |
| |
78 |
| |
79 impl<X : Space + Clone> Decomposition<X> for BasicDecomposition { |
| |
80 type Decomposition<'b> = MyCow<'b, X> where X : 'b; |
| |
81 type Reference<'b> = &'b X where X : 'b; |
| |
82 |
| |
83 #[inline] |
| |
84 fn lift<'b>(r : Self::Reference<'b>) -> Self::Decomposition<'b> { |
| |
85 MyCow::Borrowed(r) |
| |
86 } |
| |
87 } |
| |
88 |
| |
89 /// Helper trait for functions to work with either owned values or references to either the |
| |
90 /// “principal type” `X` or types some present a subset of `X`. In the latter sense, this |
| |
91 /// generalises [`std::borrow::ToOwned`], [`std::borrow::Borrow`], and [`std::borrow::Cow`]. |
| |
92 /// This type also includes iteratation facilities when `X` is a [`Collection`], to avoid |
| |
93 /// the possibly costly conversion of such subset types into `X`. |
| |
94 pub trait Instance<X : Space, D = <X as Space>::Decomp> : Sized where D : Decomposition<X> { |
| |
95 /// Decomposes self according to `decomposer`. |
| |
96 fn decompose<'b>(self) -> D::Decomposition<'b> |
| |
97 where Self : 'b, X : 'b; |
| |
98 |
| |
99 /// Returns a lightweight instance of `self`. |
| |
100 fn ref_instance(&self) -> D::Reference<'_>; |
| |
101 |
| |
102 /// Returns an owned instance of `X`, cloning or converting non-true instances when necessary. |
| |
103 fn own(self) -> X; |
| |
104 |
| |
105 // ************** automatically implemented methods below from here ************** |
| |
106 |
| |
107 /// Returns an owned instance or reference to `X`, converting non-true instances when necessary. |
| |
108 /// |
| |
109 /// Default implementation uses [`Self::own`]. Consumes the input. |
| |
110 fn cow<'b>(self) -> MyCow<'b, X> where Self : 'b { |
| |
111 MyCow::Owned(self.own()) |
| |
112 } |
| |
113 |
| |
114 #[inline] |
| |
115 /// Evaluates `f` on a reference to self. |
| |
116 /// |
| |
117 /// Default implementation uses [`Self::cow`]. Consumes the input. |
| |
118 fn eval<'b, R>(self, f : impl FnOnce(&X) -> R) -> R |
| |
119 where X : 'b, Self : 'b |
| |
120 { |
| |
121 f(&*self.cow()) |
| |
122 } |
| |
123 |
| |
124 #[inline] |
| |
125 /// Evaluates `f` or `g` depending on whether a reference or owned value is available. |
| |
126 /// |
| |
127 /// Default implementation uses [`Self::cow`]. Consumes the input. |
| |
128 fn either<'b, R>( |
| |
129 self, |
| |
130 f : impl FnOnce(X) -> R, |
| |
131 g : impl FnOnce(&X) -> R |
| |
132 ) -> R |
| |
133 where Self : 'b |
| |
134 { |
| |
135 match self.cow() { |
| |
136 EitherDecomp::Owned(x) => f(x), |
| |
137 EitherDecomp::Borrowed(x) => g(x), |
| |
138 } |
| |
139 } |
| |
140 } |
| |
141 |
| |
142 |
| |
143 impl<X : Space + Clone> Instance<X, BasicDecomposition> for X { |
| |
144 #[inline] |
| |
145 fn decompose<'b>(self) -> <BasicDecomposition as Decomposition<X>>::Decomposition<'b> |
| |
146 where Self : 'b, X : 'b |
| |
147 { |
| |
148 MyCow::Owned(self) |
| |
149 } |
| |
150 |
| |
151 #[inline] |
| |
152 fn own(self) -> X { |
| |
153 self |
| |
154 } |
| |
155 |
| |
156 #[inline] |
| |
157 fn cow<'b>(self) -> MyCow<'b, X> where Self : 'b { |
| |
158 MyCow::Owned(self) |
| |
159 } |
| |
160 |
| |
161 #[inline] |
| |
162 fn ref_instance(&self) -> <BasicDecomposition as Decomposition<X>>::Reference<'_> { |
| |
163 self |
| |
164 } |
| |
165 } |
| |
166 |
| |
167 impl<'a, X : Space + Clone> Instance<X, BasicDecomposition> for &'a X { |
| |
168 #[inline] |
| |
169 fn decompose<'b>(self) -> <BasicDecomposition as Decomposition<X>>::Decomposition<'b> |
| |
170 where Self : 'b, X : 'b |
| |
171 { |
| |
172 MyCow::Borrowed(self) |
| |
173 } |
| |
174 |
| |
175 #[inline] |
| |
176 fn own(self) -> X { |
| |
177 self.clone() |
| |
178 } |
| |
179 |
| |
180 #[inline] |
| |
181 fn cow<'b>(self) -> MyCow<'b, X> where Self : 'b { |
| |
182 MyCow::Borrowed(self) |
| |
183 } |
| |
184 |
| |
185 #[inline] |
| |
186 fn ref_instance(&self) -> <BasicDecomposition as Decomposition<X>>::Reference<'_> { |
| |
187 *self |
| |
188 } |
| |
189 } |
| |
190 |
| |
191 impl<'a, X : Space + Clone> Instance<X, BasicDecomposition> for &'a mut X { |
| |
192 #[inline] |
| |
193 fn decompose<'b>(self) -> <BasicDecomposition as Decomposition<X>>::Decomposition<'b> |
| |
194 where Self : 'b, X : 'b |
| |
195 { |
| |
196 EitherDecomp::Borrowed(self) |
| |
197 } |
| |
198 |
| |
199 #[inline] |
| |
200 fn own(self) -> X { |
| |
201 self.clone() |
| |
202 } |
| |
203 |
| |
204 #[inline] |
| |
205 fn cow<'b>(self) -> MyCow<'b, X> where Self : 'b, X : Clone { |
| |
206 EitherDecomp::Borrowed(self) |
| |
207 } |
| |
208 |
| |
209 #[inline] |
| |
210 fn ref_instance(&self) -> <BasicDecomposition as Decomposition<X>>::Reference<'_> { |
| |
211 *self |
| |
212 } |
| |
213 } |
| |
214 |
| |
215 impl<'a, X : Space + Clone> Instance<X, BasicDecomposition> for MyCow<'a, X> { |
| |
216 |
| |
217 #[inline] |
| |
218 fn decompose<'b>(self) -> <BasicDecomposition as Decomposition<X>>::Decomposition<'b> |
| |
219 where Self : 'b, X : 'b |
| |
220 { |
| |
221 self |
| |
222 } |
| |
223 |
| |
224 #[inline] |
| |
225 fn own(self) -> X { |
| |
226 match self { |
| |
227 MyCow::Borrowed(a) => a.own(), |
| |
228 MyCow::Owned(b) => b.own() |
| |
229 } |
| |
230 } |
| |
231 |
| |
232 #[inline] |
| |
233 fn cow<'b>(self) -> MyCow<'b, X> where Self : 'b { |
| |
234 match self { |
| |
235 MyCow::Borrowed(a) => a.cow(), |
| |
236 MyCow::Owned(b) => b.cow() |
| |
237 } |
| |
238 } |
| |
239 |
| |
240 #[inline] |
| |
241 fn ref_instance(&self) -> <BasicDecomposition as Decomposition<X>>::Reference<'_> { |
| |
242 match self { |
| |
243 MyCow::Borrowed(a) => a, |
| |
244 MyCow::Owned(b) => &b, |
| |
245 } |
| |
246 } |
| |
247 } |
| |
248 |
| |
249 /// Marker type for mutable decompositions to be used with [`InstanceMut`]. |
| |
250 pub trait DecompositionMut<X : Space> : Sized { |
| |
251 type ReferenceMut<'b> : InstanceMut<X, Self> where X : 'b; |
| |
252 } |
| |
253 |
| |
254 |
| |
255 /// Helper trait for functions to work with mutable references. |
| |
256 pub trait InstanceMut<X : Space , D = <X as Space>::Decomp> : Sized where D : DecompositionMut<X> { |
| |
257 /// Returns a mutable decomposition of self. |
| |
258 fn ref_instance_mut(&mut self) -> D::ReferenceMut<'_>; |
| |
259 } |
| |
260 |
| |
261 impl<X : Space> DecompositionMut<X> for BasicDecomposition { |
| |
262 type ReferenceMut<'b> = &'b mut X where X : 'b; |
| |
263 } |
| |
264 |
| |
265 /// This impl may seem pointless, but allows throwaway mutable scratch variables |
| |
266 impl<'a, X : Space> InstanceMut<X, BasicDecomposition> for X { |
| |
267 #[inline] |
| |
268 fn ref_instance_mut(&mut self) |
| |
269 -> <BasicDecomposition as DecompositionMut<X>>::ReferenceMut<'_> |
| |
270 { |
| |
271 self |
| |
272 } |
| |
273 } |
| |
274 |
| |
275 impl<'a, X : Space> InstanceMut<X, BasicDecomposition> for &'a mut X { |
| |
276 #[inline] |
| |
277 fn ref_instance_mut(&mut self) |
| |
278 -> <BasicDecomposition as DecompositionMut<X>>::ReferenceMut<'_> |
| |
279 { |
| |
280 self |
| |
281 } |
| |
282 } |