1use crate::{Failure, IndexDomain, QueryResult, ValueDomain};
2use std::{
3 cmp::Ordering,
4 fmt::{self, Debug, Display, Formatter},
5 hash::{Hash, Hasher},
6 marker::PhantomData,
7};
8
9#[derive(Clone)]
10pub struct ExpandedIndex<P: IndexDomain, C: IndexDomain>(PhantomData<(P, C)>);
11
12#[derive(Clone, PartialEq, Eq, Hash, Debug)]
13enum ExpandedIndexRepresentation<P, C> {
14 Source(P),
15 Child { parent: P, child: C },
16}
17
18impl<P: PartialOrd, C: PartialOrd> PartialOrd for ExpandedIndexRepresentation<P, C> {
19 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
20 let parent_ordering = match (self, other) {
21 (
22 Self::Source(first)
23 | Self::Child {
24 parent: first,
25 child: _,
26 },
27 Self::Source(second)
28 | Self::Child {
29 parent: second,
30 child: _,
31 },
32 ) => first.partial_cmp(second)?,
33 };
34
35 if parent_ordering != Ordering::Equal {
36 return Some(parent_ordering);
37 }
38
39 match (self, other) {
40 (Self::Source(_), Self::Source(_)) => Some(Ordering::Equal),
41 (Self::Source(_), Self::Child { .. }) => Some(Ordering::Less),
42 (Self::Child { .. }, Self::Source(_)) => Some(Ordering::Greater),
43 (
44 Self::Child {
45 parent: _,
46 child: first,
47 },
48 Self::Child {
49 parent: _,
50 child: second,
51 },
52 ) => first.partial_cmp(second),
53 }
54 }
55}
56
57impl<P: Ord, C: Ord> Ord for ExpandedIndexRepresentation<P, C> {
58 fn cmp(&self, other: &Self) -> Ordering {
59 let parent_ordering = match (self, other) {
60 (
61 Self::Source(first)
62 | Self::Child {
63 parent: first,
64 child: _,
65 },
66 Self::Source(second)
67 | Self::Child {
68 parent: second,
69 child: _,
70 },
71 ) => first.cmp(second),
72 };
73
74 if parent_ordering != Ordering::Equal {
75 return parent_ordering;
76 }
77
78 match (self, other) {
79 (Self::Source(_), Self::Source(_)) => Ordering::Equal,
80 (Self::Source(_), Self::Child { .. }) => Ordering::Less,
81 (Self::Child { .. }, Self::Source(_)) => Ordering::Greater,
82 (
83 Self::Child {
84 parent: _,
85 child: first,
86 },
87 Self::Child {
88 parent: _,
89 child: second,
90 },
91 ) => first.cmp(second),
92 }
93 }
94}
95
96pub struct ExpandedIndexOwned<P: IndexDomain, C: IndexDomain> {
97 representation: ExpandedIndexRepresentation<P::Owned, C::Owned>,
98}
99
100impl<P: IndexDomain, C: IndexDomain> ExpandedIndexOwned<P, C> {
101 #[must_use]
102 pub const fn parent_index(&self) -> &P::Owned {
103 match &self.representation {
104 ExpandedIndexRepresentation::Source(parent)
105 | ExpandedIndexRepresentation::Child { parent, child: _ } => parent,
106 }
107 }
108
109 #[must_use]
110 pub const fn child_index(&self) -> Option<&C::Owned> {
111 match &self.representation {
112 ExpandedIndexRepresentation::Source(_) => None,
113 ExpandedIndexRepresentation::Child { parent: _, child } => Some(child),
114 }
115 }
116
117 #[must_use]
118 pub fn into_parts(self) -> (P::Owned, Option<C::Owned>) {
119 match self.representation {
120 ExpandedIndexRepresentation::Source(parent) => (parent, None),
121 ExpandedIndexRepresentation::Child { parent, child } => (parent, Some(child)),
122 }
123 }
124
125 #[must_use]
126 pub const fn is_source(&self) -> bool {
127 matches!(&self.representation, ExpandedIndexRepresentation::Source(_))
128 }
129
130 pub(crate) const fn source(parent: P::Owned) -> Self {
131 Self {
132 representation: ExpandedIndexRepresentation::Source(parent),
133 }
134 }
135
136 pub(crate) const fn child(parent: P::Owned, child: C::Owned) -> Self {
137 Self {
138 representation: ExpandedIndexRepresentation::Child { parent, child },
139 }
140 }
141}
142
143impl<P: IndexDomain, C: IndexDomain> Clone for ExpandedIndexOwned<P, C> {
144 fn clone(&self) -> Self {
145 Self {
146 representation: self.representation.clone(),
147 }
148 }
149}
150
151impl<P: IndexDomain, C: IndexDomain> PartialEq for ExpandedIndexOwned<P, C> {
152 fn eq(&self, other: &Self) -> bool {
153 self.representation == other.representation
154 }
155}
156
157impl<P: IndexDomain, C: IndexDomain> Eq for ExpandedIndexOwned<P, C> {}
158
159impl<P, C> PartialOrd for ExpandedIndexOwned<P, C>
160where
161 P: IndexDomain,
162 C: IndexDomain,
163 P::Owned: PartialOrd,
164 C::Owned: PartialOrd,
165{
166 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
167 self.representation.partial_cmp(&other.representation)
168 }
169}
170
171impl<P, C> Ord for ExpandedIndexOwned<P, C>
172where
173 P: IndexDomain,
174 C: IndexDomain,
175 P::Owned: Ord,
176 C::Owned: Ord,
177{
178 fn cmp(&self, other: &Self) -> Ordering {
179 self.representation.cmp(&other.representation)
180 }
181}
182
183impl<P: IndexDomain, C: IndexDomain> Hash for ExpandedIndexOwned<P, C> {
184 fn hash<H: Hasher>(&self, state: &mut H) {
185 self.representation.hash(state);
186 }
187}
188
189impl<P: IndexDomain, C: IndexDomain> Debug for ExpandedIndexOwned<P, C> {
190 fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
191 self.representation.fmt(formatter)
192 }
193}
194
195impl<P: IndexDomain, C: IndexDomain> Display for ExpandedIndexOwned<P, C> {
196 fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
197 match &self.representation {
198 ExpandedIndexRepresentation::Source(parent) => write!(formatter, "source({parent})"),
199 ExpandedIndexRepresentation::Child { parent, child } => {
200 write!(formatter, "child({parent}, {child})")
201 }
202 }
203 }
204}
205
206pub struct ExpandedIndexReference<'a, P: IndexDomain, C: IndexDomain> {
207 representation: ExpandedIndexRepresentation<P::Index<'a>, C::Index<'a>>,
208}
209
210impl<'a, P: IndexDomain, C: IndexDomain> ExpandedIndexReference<'a, P, C> {
211 #[must_use]
212 pub const fn parent_index(&self) -> &P::Index<'a> {
213 match &self.representation {
214 ExpandedIndexRepresentation::Source(parent)
215 | ExpandedIndexRepresentation::Child { parent, child: _ } => parent,
216 }
217 }
218
219 #[must_use]
220 pub const fn child_index(&self) -> Option<&C::Index<'a>> {
221 match &self.representation {
222 ExpandedIndexRepresentation::Source(_) => None,
223 ExpandedIndexRepresentation::Child { parent: _, child } => Some(child),
224 }
225 }
226
227 #[must_use]
228 pub const fn is_source(&self) -> bool {
229 matches!(&self.representation, ExpandedIndexRepresentation::Source(_))
230 }
231
232 pub(crate) const fn source(parent: P::Index<'a>) -> Self {
233 Self {
234 representation: ExpandedIndexRepresentation::Source(parent),
235 }
236 }
237
238 pub(crate) const fn child(parent: P::Index<'a>, child: C::Index<'a>) -> Self {
239 Self {
240 representation: ExpandedIndexRepresentation::Child { parent, child },
241 }
242 }
243}
244
245impl<P: IndexDomain, C: IndexDomain> Clone for ExpandedIndexReference<'_, P, C> {
246 fn clone(&self) -> Self {
247 Self {
248 representation: self.representation.clone(),
249 }
250 }
251}
252
253impl<P: IndexDomain, C: IndexDomain> PartialEq for ExpandedIndexReference<'_, P, C> {
254 fn eq(&self, other: &Self) -> bool {
255 self.representation == other.representation
256 }
257}
258
259impl<P: IndexDomain, C: IndexDomain> Eq for ExpandedIndexReference<'_, P, C> {}
260
261impl<'a, P, C> PartialOrd for ExpandedIndexReference<'a, P, C>
262where
263 P: IndexDomain,
264 C: IndexDomain,
265 P::Index<'a>: PartialOrd,
266 C::Index<'a>: PartialOrd,
267{
268 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
269 self.representation.partial_cmp(&other.representation)
270 }
271}
272
273impl<'a, P, C> Ord for ExpandedIndexReference<'a, P, C>
274where
275 P: IndexDomain,
276 C: IndexDomain,
277 P::Index<'a>: Ord,
278 C::Index<'a>: Ord,
279{
280 fn cmp(&self, other: &Self) -> Ordering {
281 self.representation.cmp(&other.representation)
282 }
283}
284
285impl<P: IndexDomain, C: IndexDomain> Hash for ExpandedIndexReference<'_, P, C> {
286 fn hash<H: Hasher>(&self, state: &mut H) {
287 self.representation.hash(state);
288 }
289}
290
291impl<P: IndexDomain, C: IndexDomain> Debug for ExpandedIndexReference<'_, P, C> {
292 fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
293 match &self.representation {
294 ExpandedIndexRepresentation::Source(parent) => formatter
295 .debug_tuple("Source")
296 .field(&P::to_owned(parent))
297 .finish(),
298 ExpandedIndexRepresentation::Child { parent, child } => formatter
299 .debug_struct("Child")
300 .field("parent", &P::to_owned(parent))
301 .field("child", &C::to_owned(child))
302 .finish(),
303 }
304 }
305}
306
307impl<P: IndexDomain, C: IndexDomain> IndexDomain for ExpandedIndex<P, C> {
308 type Index<'a>
309 = ExpandedIndexReference<'a, P, C>
310 where
311 Self: 'a;
312 type Owned = ExpandedIndexOwned<P, C>;
313
314 fn to_owned(index: &Self::Index<'_>) -> Self::Owned {
315 match &index.representation {
316 ExpandedIndexRepresentation::Source(parent) => {
317 ExpandedIndexOwned::source(P::to_owned(parent))
318 }
319 ExpandedIndexRepresentation::Child { parent, child } => {
320 ExpandedIndexOwned::child(P::to_owned(parent), C::to_owned(child))
321 }
322 }
323 }
324
325 fn from_owned(owned: &Self::Owned) -> Self::Index<'_> {
326 match &owned.representation {
327 ExpandedIndexRepresentation::Source(parent) => {
328 ExpandedIndexReference::source(P::from_owned(parent))
329 }
330 ExpandedIndexRepresentation::Child { parent, child } => {
331 ExpandedIndexReference::child(P::from_owned(parent), C::from_owned(child))
332 }
333 }
334 }
335}
336
337pub struct ExpandedChild<'a, C: IndexDomain, V: ValueDomain> {
338 index: C::Index<'a>,
339 outcome: QueryResult<V::Value<'a>>,
340}
341
342impl<'a, C: IndexDomain, V: ValueDomain> ExpandedChild<'a, C, V> {
343 #[must_use]
344 pub const fn success(index: C::Index<'a>, value: V::Value<'a>) -> Self {
345 Self {
346 index,
347 outcome: Ok(value),
348 }
349 }
350
351 #[must_use]
352 pub const fn failure(index: C::Index<'a>, failure: Box<Failure>) -> Self {
353 Self {
354 index,
355 outcome: Err(failure),
356 }
357 }
358
359 #[must_use]
360 pub const fn from_outcome(index: C::Index<'a>, outcome: QueryResult<V::Value<'a>>) -> Self {
361 Self { index, outcome }
362 }
363
364 pub(crate) fn into_parts(self) -> (C::Index<'a>, QueryResult<V::Value<'a>>) {
365 (self.index, self.outcome)
366 }
367}