Skip to main content

graphrecords_query/index/
expanded.rs

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}