|
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 } |