Skip to main content

graphrecords_query/capabilities/
transition.rs

1use crate::{
2    AttributeName, Failure, FailureKind, FailureKindValue, IndexValue, Mask, Position, Positional,
3    QueryResult, Scalar, ValueDomain, error::conversion::InvalidTransition,
4};
5use graphrecords_core::graphrecord::{
6    EdgeIndex, GraphRecordAttribute, GraphRecordValue, NodeIndex,
7};
8
9pub trait ValueTransition<T: ValueDomain>: ValueDomain {
10    fn transition<'a>(label: &'static str, value: Self::Value<'a>) -> QueryResult<T::Value<'a>>;
11}
12
13const ATTRIBUTE_NAME_TARGET: &str = "AttributeName";
14const ATTRIBUTE_NAME_INDEX_TARGET: &str = "IndexValue<AttributeName>";
15const BOOL_INDEX_TARGET: &str = "IndexValue<bool>";
16const EDGE_INDEX_TARGET: &str = "IndexValue<EdgeIndex>";
17const GRAPHRECORD_VALUE_INDEX_TARGET: &str = "IndexValue<GraphRecordValue>";
18const MASK_TARGET: &str = "Mask";
19const NODE_INDEX_TARGET: &str = "IndexValue<NodeIndex>";
20const POSITIONAL_INDEX_TARGET: &str = "IndexValue<Positional>";
21const SCALAR_TARGET: &str = "Scalar";
22
23fn graphrecord_value_to_attribute(
24    label: &'static str,
25    value: GraphRecordValue,
26    target: &'static str,
27) -> QueryResult<GraphRecordAttribute> {
28    match value {
29        GraphRecordValue::String(value) => Ok(GraphRecordAttribute::String(value)),
30        GraphRecordValue::Int(value) => Ok(GraphRecordAttribute::Int(value)),
31        value => Err(Failure::new(label, InvalidTransition::new(value, target))),
32    }
33}
34
35fn graphrecord_value_to_bool(
36    label: &'static str,
37    value: GraphRecordValue,
38    target: &'static str,
39) -> QueryResult<bool> {
40    match value {
41        GraphRecordValue::Bool(value) => Ok(value),
42        value => Err(Failure::new(label, InvalidTransition::new(value, target))),
43    }
44}
45
46fn graphrecord_value_to_edge_index(
47    label: &'static str,
48    value: GraphRecordValue,
49) -> QueryResult<EdgeIndex> {
50    match value {
51        GraphRecordValue::Int(value) => EdgeIndex::try_from(value).map_err(|_| {
52            Failure::new(
53                label,
54                InvalidTransition::new(GraphRecordValue::Int(value), EDGE_INDEX_TARGET),
55            )
56        }),
57        value => Err(Failure::new(
58            label,
59            InvalidTransition::new(value, EDGE_INDEX_TARGET),
60        )),
61    }
62}
63
64fn graphrecord_value_to_position(
65    label: &'static str,
66    value: GraphRecordValue,
67) -> QueryResult<Position> {
68    match value {
69        GraphRecordValue::Int(value) => Position::try_from(value).map_err(|_| {
70            Failure::new(
71                label,
72                InvalidTransition::new(GraphRecordValue::Int(value), POSITIONAL_INDEX_TARGET),
73            )
74        }),
75        value => Err(Failure::new(
76            label,
77            InvalidTransition::new(value, POSITIONAL_INDEX_TARGET),
78        )),
79    }
80}
81
82fn attribute_to_graphrecord_value(value: GraphRecordAttribute) -> GraphRecordValue {
83    match value {
84        GraphRecordAttribute::String(value) => GraphRecordValue::String(value),
85        GraphRecordAttribute::Int(value) => GraphRecordValue::Int(value),
86    }
87}
88
89fn attribute_to_edge_index(
90    label: &'static str,
91    value: GraphRecordAttribute,
92) -> QueryResult<EdgeIndex> {
93    match value {
94        GraphRecordAttribute::Int(value) => EdgeIndex::try_from(value).map_err(|_| {
95            Failure::new(
96                label,
97                InvalidTransition::new(GraphRecordAttribute::Int(value), EDGE_INDEX_TARGET),
98            )
99        }),
100        value @ GraphRecordAttribute::String(_) => Err(Failure::new(
101            label,
102            InvalidTransition::new(value, EDGE_INDEX_TARGET),
103        )),
104    }
105}
106
107fn attribute_to_position(
108    label: &'static str,
109    value: GraphRecordAttribute,
110) -> QueryResult<Position> {
111    match value {
112        GraphRecordAttribute::Int(value) => Position::try_from(value).map_err(|_| {
113            Failure::new(
114                label,
115                InvalidTransition::new(GraphRecordAttribute::Int(value), POSITIONAL_INDEX_TARGET),
116            )
117        }),
118        value @ GraphRecordAttribute::String(_) => Err(Failure::new(
119            label,
120            InvalidTransition::new(value, POSITIONAL_INDEX_TARGET),
121        )),
122    }
123}
124
125fn position_to_integer(
126    label: &'static str,
127    value: Position,
128    target: &'static str,
129) -> QueryResult<i64> {
130    i64::try_from(value).map_err(|_| Failure::new(label, InvalidTransition::new(value, target)))
131}
132
133impl ValueTransition<IndexValue<GraphRecordValue>> for Scalar {
134    fn transition<'a>(
135        _label: &'static str,
136        value: Self::Value<'a>,
137    ) -> QueryResult<<IndexValue<GraphRecordValue> as ValueDomain>::Value<'a>> {
138        Ok(value)
139    }
140}
141
142impl ValueTransition<AttributeName> for Scalar {
143    fn transition<'a>(
144        label: &'static str,
145        value: Self::Value<'a>,
146    ) -> QueryResult<<AttributeName as ValueDomain>::Value<'a>> {
147        graphrecord_value_to_attribute(label, value, ATTRIBUTE_NAME_TARGET)
148    }
149}
150
151impl ValueTransition<IndexValue<NodeIndex>> for Scalar {
152    fn transition<'a>(
153        label: &'static str,
154        value: Self::Value<'a>,
155    ) -> QueryResult<<IndexValue<NodeIndex> as ValueDomain>::Value<'a>> {
156        graphrecord_value_to_attribute(label, value, NODE_INDEX_TARGET)
157    }
158}
159
160impl ValueTransition<IndexValue<AttributeName>> for Scalar {
161    fn transition<'a>(
162        label: &'static str,
163        value: Self::Value<'a>,
164    ) -> QueryResult<<IndexValue<AttributeName> as ValueDomain>::Value<'a>> {
165        graphrecord_value_to_attribute(label, value, ATTRIBUTE_NAME_INDEX_TARGET)
166    }
167}
168
169impl ValueTransition<Mask> for Scalar {
170    fn transition<'a>(
171        label: &'static str,
172        value: Self::Value<'a>,
173    ) -> QueryResult<<Mask as ValueDomain>::Value<'a>> {
174        graphrecord_value_to_bool(label, value, MASK_TARGET)
175    }
176}
177
178impl ValueTransition<IndexValue<bool>> for Scalar {
179    fn transition<'a>(
180        label: &'static str,
181        value: Self::Value<'a>,
182    ) -> QueryResult<<IndexValue<bool> as ValueDomain>::Value<'a>> {
183        graphrecord_value_to_bool(label, value, BOOL_INDEX_TARGET)
184    }
185}
186
187impl ValueTransition<IndexValue<EdgeIndex>> for Scalar {
188    fn transition<'a>(
189        label: &'static str,
190        value: Self::Value<'a>,
191    ) -> QueryResult<<IndexValue<EdgeIndex> as ValueDomain>::Value<'a>> {
192        graphrecord_value_to_edge_index(label, value)
193    }
194}
195
196impl ValueTransition<IndexValue<Positional>> for Scalar {
197    fn transition<'a>(
198        label: &'static str,
199        value: Self::Value<'a>,
200    ) -> QueryResult<<IndexValue<Positional> as ValueDomain>::Value<'a>> {
201        graphrecord_value_to_position(label, value)
202    }
203}
204
205impl ValueTransition<Scalar> for IndexValue<GraphRecordValue> {
206    fn transition<'a>(
207        _label: &'static str,
208        value: Self::Value<'a>,
209    ) -> QueryResult<<Scalar as ValueDomain>::Value<'a>> {
210        Ok(value)
211    }
212}
213
214impl ValueTransition<AttributeName> for IndexValue<GraphRecordValue> {
215    fn transition<'a>(
216        label: &'static str,
217        value: Self::Value<'a>,
218    ) -> QueryResult<<AttributeName as ValueDomain>::Value<'a>> {
219        graphrecord_value_to_attribute(label, value, ATTRIBUTE_NAME_TARGET)
220    }
221}
222
223impl ValueTransition<IndexValue<NodeIndex>> for IndexValue<GraphRecordValue> {
224    fn transition<'a>(
225        label: &'static str,
226        value: Self::Value<'a>,
227    ) -> QueryResult<<IndexValue<NodeIndex> as ValueDomain>::Value<'a>> {
228        graphrecord_value_to_attribute(label, value, NODE_INDEX_TARGET)
229    }
230}
231
232impl ValueTransition<IndexValue<AttributeName>> for IndexValue<GraphRecordValue> {
233    fn transition<'a>(
234        label: &'static str,
235        value: Self::Value<'a>,
236    ) -> QueryResult<<IndexValue<AttributeName> as ValueDomain>::Value<'a>> {
237        graphrecord_value_to_attribute(label, value, ATTRIBUTE_NAME_INDEX_TARGET)
238    }
239}
240
241impl ValueTransition<Mask> for IndexValue<GraphRecordValue> {
242    fn transition<'a>(
243        label: &'static str,
244        value: Self::Value<'a>,
245    ) -> QueryResult<<Mask as ValueDomain>::Value<'a>> {
246        graphrecord_value_to_bool(label, value, MASK_TARGET)
247    }
248}
249
250impl ValueTransition<IndexValue<bool>> for IndexValue<GraphRecordValue> {
251    fn transition<'a>(
252        label: &'static str,
253        value: Self::Value<'a>,
254    ) -> QueryResult<<IndexValue<bool> as ValueDomain>::Value<'a>> {
255        graphrecord_value_to_bool(label, value, BOOL_INDEX_TARGET)
256    }
257}
258
259impl ValueTransition<IndexValue<EdgeIndex>> for IndexValue<GraphRecordValue> {
260    fn transition<'a>(
261        label: &'static str,
262        value: Self::Value<'a>,
263    ) -> QueryResult<<IndexValue<EdgeIndex> as ValueDomain>::Value<'a>> {
264        graphrecord_value_to_edge_index(label, value)
265    }
266}
267
268impl ValueTransition<IndexValue<Positional>> for IndexValue<GraphRecordValue> {
269    fn transition<'a>(
270        label: &'static str,
271        value: Self::Value<'a>,
272    ) -> QueryResult<<IndexValue<Positional> as ValueDomain>::Value<'a>> {
273        graphrecord_value_to_position(label, value)
274    }
275}
276
277impl ValueTransition<Scalar> for AttributeName {
278    fn transition<'a>(
279        _label: &'static str,
280        value: Self::Value<'a>,
281    ) -> QueryResult<<Scalar as ValueDomain>::Value<'a>> {
282        Ok(attribute_to_graphrecord_value(value))
283    }
284}
285
286impl ValueTransition<IndexValue<GraphRecordValue>> for AttributeName {
287    fn transition<'a>(
288        _label: &'static str,
289        value: Self::Value<'a>,
290    ) -> QueryResult<<IndexValue<GraphRecordValue> as ValueDomain>::Value<'a>> {
291        Ok(attribute_to_graphrecord_value(value))
292    }
293}
294
295impl ValueTransition<IndexValue<NodeIndex>> for AttributeName {
296    fn transition<'a>(
297        _label: &'static str,
298        value: Self::Value<'a>,
299    ) -> QueryResult<<IndexValue<NodeIndex> as ValueDomain>::Value<'a>> {
300        Ok(value)
301    }
302}
303
304impl ValueTransition<IndexValue<Self>> for AttributeName {
305    fn transition<'a>(
306        _label: &'static str,
307        value: Self::Value<'a>,
308    ) -> QueryResult<<IndexValue<Self> as ValueDomain>::Value<'a>> {
309        Ok(value)
310    }
311}
312
313impl ValueTransition<IndexValue<EdgeIndex>> for AttributeName {
314    fn transition<'a>(
315        label: &'static str,
316        value: Self::Value<'a>,
317    ) -> QueryResult<<IndexValue<EdgeIndex> as ValueDomain>::Value<'a>> {
318        attribute_to_edge_index(label, value)
319    }
320}
321
322impl ValueTransition<IndexValue<Positional>> for AttributeName {
323    fn transition<'a>(
324        label: &'static str,
325        value: Self::Value<'a>,
326    ) -> QueryResult<<IndexValue<Positional> as ValueDomain>::Value<'a>> {
327        attribute_to_position(label, value)
328    }
329}
330
331impl ValueTransition<Scalar> for IndexValue<NodeIndex> {
332    fn transition<'a>(
333        _label: &'static str,
334        value: Self::Value<'a>,
335    ) -> QueryResult<<Scalar as ValueDomain>::Value<'a>> {
336        Ok(attribute_to_graphrecord_value(value))
337    }
338}
339
340impl ValueTransition<IndexValue<GraphRecordValue>> for IndexValue<NodeIndex> {
341    fn transition<'a>(
342        _label: &'static str,
343        value: Self::Value<'a>,
344    ) -> QueryResult<<IndexValue<GraphRecordValue> as ValueDomain>::Value<'a>> {
345        Ok(attribute_to_graphrecord_value(value))
346    }
347}
348
349impl ValueTransition<AttributeName> for IndexValue<NodeIndex> {
350    fn transition<'a>(
351        _label: &'static str,
352        value: Self::Value<'a>,
353    ) -> QueryResult<<AttributeName as ValueDomain>::Value<'a>> {
354        Ok(value)
355    }
356}
357
358impl ValueTransition<IndexValue<AttributeName>> for IndexValue<NodeIndex> {
359    fn transition<'a>(
360        _label: &'static str,
361        value: Self::Value<'a>,
362    ) -> QueryResult<<IndexValue<AttributeName> as ValueDomain>::Value<'a>> {
363        Ok(value)
364    }
365}
366
367impl ValueTransition<IndexValue<EdgeIndex>> for IndexValue<NodeIndex> {
368    fn transition<'a>(
369        label: &'static str,
370        value: Self::Value<'a>,
371    ) -> QueryResult<<IndexValue<EdgeIndex> as ValueDomain>::Value<'a>> {
372        attribute_to_edge_index(label, value)
373    }
374}
375
376impl ValueTransition<IndexValue<Positional>> for IndexValue<NodeIndex> {
377    fn transition<'a>(
378        label: &'static str,
379        value: Self::Value<'a>,
380    ) -> QueryResult<<IndexValue<Positional> as ValueDomain>::Value<'a>> {
381        attribute_to_position(label, value)
382    }
383}
384
385impl ValueTransition<Scalar> for IndexValue<AttributeName> {
386    fn transition<'a>(
387        _label: &'static str,
388        value: Self::Value<'a>,
389    ) -> QueryResult<<Scalar as ValueDomain>::Value<'a>> {
390        Ok(attribute_to_graphrecord_value(value))
391    }
392}
393
394impl ValueTransition<IndexValue<GraphRecordValue>> for IndexValue<AttributeName> {
395    fn transition<'a>(
396        _label: &'static str,
397        value: Self::Value<'a>,
398    ) -> QueryResult<<IndexValue<GraphRecordValue> as ValueDomain>::Value<'a>> {
399        Ok(attribute_to_graphrecord_value(value))
400    }
401}
402
403impl ValueTransition<AttributeName> for IndexValue<AttributeName> {
404    fn transition<'a>(
405        _label: &'static str,
406        value: Self::Value<'a>,
407    ) -> QueryResult<<AttributeName as ValueDomain>::Value<'a>> {
408        Ok(value)
409    }
410}
411
412impl ValueTransition<IndexValue<NodeIndex>> for IndexValue<AttributeName> {
413    fn transition<'a>(
414        _label: &'static str,
415        value: Self::Value<'a>,
416    ) -> QueryResult<<IndexValue<NodeIndex> as ValueDomain>::Value<'a>> {
417        Ok(value)
418    }
419}
420
421impl ValueTransition<IndexValue<EdgeIndex>> for IndexValue<AttributeName> {
422    fn transition<'a>(
423        label: &'static str,
424        value: Self::Value<'a>,
425    ) -> QueryResult<<IndexValue<EdgeIndex> as ValueDomain>::Value<'a>> {
426        attribute_to_edge_index(label, value)
427    }
428}
429
430impl ValueTransition<IndexValue<Positional>> for IndexValue<AttributeName> {
431    fn transition<'a>(
432        label: &'static str,
433        value: Self::Value<'a>,
434    ) -> QueryResult<<IndexValue<Positional> as ValueDomain>::Value<'a>> {
435        attribute_to_position(label, value)
436    }
437}
438
439impl ValueTransition<Scalar> for Mask {
440    fn transition<'a>(
441        _label: &'static str,
442        value: Self::Value<'a>,
443    ) -> QueryResult<<Scalar as ValueDomain>::Value<'a>> {
444        Ok(GraphRecordValue::Bool(value))
445    }
446}
447
448impl ValueTransition<IndexValue<GraphRecordValue>> for Mask {
449    fn transition<'a>(
450        _label: &'static str,
451        value: Self::Value<'a>,
452    ) -> QueryResult<<IndexValue<GraphRecordValue> as ValueDomain>::Value<'a>> {
453        Ok(GraphRecordValue::Bool(value))
454    }
455}
456
457impl ValueTransition<IndexValue<bool>> for Mask {
458    fn transition<'a>(
459        _label: &'static str,
460        value: Self::Value<'a>,
461    ) -> QueryResult<<IndexValue<bool> as ValueDomain>::Value<'a>> {
462        Ok(value)
463    }
464}
465
466impl ValueTransition<Scalar> for IndexValue<bool> {
467    fn transition<'a>(
468        _label: &'static str,
469        value: Self::Value<'a>,
470    ) -> QueryResult<<Scalar as ValueDomain>::Value<'a>> {
471        Ok(GraphRecordValue::Bool(value))
472    }
473}
474
475impl ValueTransition<IndexValue<GraphRecordValue>> for IndexValue<bool> {
476    fn transition<'a>(
477        _label: &'static str,
478        value: Self::Value<'a>,
479    ) -> QueryResult<<IndexValue<GraphRecordValue> as ValueDomain>::Value<'a>> {
480        Ok(GraphRecordValue::Bool(value))
481    }
482}
483
484impl ValueTransition<Mask> for IndexValue<bool> {
485    fn transition<'a>(
486        _label: &'static str,
487        value: Self::Value<'a>,
488    ) -> QueryResult<<Mask as ValueDomain>::Value<'a>> {
489        Ok(value)
490    }
491}
492
493impl ValueTransition<Scalar> for IndexValue<EdgeIndex> {
494    fn transition<'a>(
495        _label: &'static str,
496        value: Self::Value<'a>,
497    ) -> QueryResult<<Scalar as ValueDomain>::Value<'a>> {
498        Ok(GraphRecordValue::Int(i64::from(value)))
499    }
500}
501
502impl ValueTransition<IndexValue<GraphRecordValue>> for IndexValue<EdgeIndex> {
503    fn transition<'a>(
504        _label: &'static str,
505        value: Self::Value<'a>,
506    ) -> QueryResult<<IndexValue<GraphRecordValue> as ValueDomain>::Value<'a>> {
507        Ok(GraphRecordValue::Int(i64::from(value)))
508    }
509}
510
511impl ValueTransition<AttributeName> for IndexValue<EdgeIndex> {
512    fn transition<'a>(
513        _label: &'static str,
514        value: Self::Value<'a>,
515    ) -> QueryResult<<AttributeName as ValueDomain>::Value<'a>> {
516        Ok(GraphRecordAttribute::Int(i64::from(value)))
517    }
518}
519
520impl ValueTransition<IndexValue<NodeIndex>> for IndexValue<EdgeIndex> {
521    fn transition<'a>(
522        _label: &'static str,
523        value: Self::Value<'a>,
524    ) -> QueryResult<<IndexValue<NodeIndex> as ValueDomain>::Value<'a>> {
525        Ok(GraphRecordAttribute::Int(i64::from(value)))
526    }
527}
528
529impl ValueTransition<IndexValue<AttributeName>> for IndexValue<EdgeIndex> {
530    fn transition<'a>(
531        _label: &'static str,
532        value: Self::Value<'a>,
533    ) -> QueryResult<<IndexValue<AttributeName> as ValueDomain>::Value<'a>> {
534        Ok(GraphRecordAttribute::Int(i64::from(value)))
535    }
536}
537
538impl ValueTransition<IndexValue<Positional>> for IndexValue<EdgeIndex> {
539    fn transition<'a>(
540        label: &'static str,
541        value: Self::Value<'a>,
542    ) -> QueryResult<<IndexValue<Positional> as ValueDomain>::Value<'a>> {
543        usize::try_from(value).map_err(|_| {
544            Failure::new(
545                label,
546                InvalidTransition::new(value, POSITIONAL_INDEX_TARGET),
547            )
548        })
549    }
550}
551
552impl ValueTransition<Scalar> for IndexValue<Positional> {
553    fn transition<'a>(
554        label: &'static str,
555        value: Self::Value<'a>,
556    ) -> QueryResult<<Scalar as ValueDomain>::Value<'a>> {
557        position_to_integer(label, value, SCALAR_TARGET).map(GraphRecordValue::Int)
558    }
559}
560
561impl ValueTransition<IndexValue<GraphRecordValue>> for IndexValue<Positional> {
562    fn transition<'a>(
563        label: &'static str,
564        value: Self::Value<'a>,
565    ) -> QueryResult<<IndexValue<GraphRecordValue> as ValueDomain>::Value<'a>> {
566        position_to_integer(label, value, GRAPHRECORD_VALUE_INDEX_TARGET).map(GraphRecordValue::Int)
567    }
568}
569
570impl ValueTransition<AttributeName> for IndexValue<Positional> {
571    fn transition<'a>(
572        label: &'static str,
573        value: Self::Value<'a>,
574    ) -> QueryResult<<AttributeName as ValueDomain>::Value<'a>> {
575        position_to_integer(label, value, ATTRIBUTE_NAME_TARGET).map(GraphRecordAttribute::Int)
576    }
577}
578
579impl ValueTransition<IndexValue<NodeIndex>> for IndexValue<Positional> {
580    fn transition<'a>(
581        label: &'static str,
582        value: Self::Value<'a>,
583    ) -> QueryResult<<IndexValue<NodeIndex> as ValueDomain>::Value<'a>> {
584        position_to_integer(label, value, NODE_INDEX_TARGET).map(GraphRecordAttribute::Int)
585    }
586}
587
588impl ValueTransition<IndexValue<AttributeName>> for IndexValue<Positional> {
589    fn transition<'a>(
590        label: &'static str,
591        value: Self::Value<'a>,
592    ) -> QueryResult<<IndexValue<AttributeName> as ValueDomain>::Value<'a>> {
593        position_to_integer(label, value, ATTRIBUTE_NAME_INDEX_TARGET)
594            .map(GraphRecordAttribute::Int)
595    }
596}
597
598impl ValueTransition<IndexValue<EdgeIndex>> for IndexValue<Positional> {
599    fn transition<'a>(
600        label: &'static str,
601        value: Self::Value<'a>,
602    ) -> QueryResult<<IndexValue<EdgeIndex> as ValueDomain>::Value<'a>> {
603        EdgeIndex::try_from(value)
604            .map_err(|_| Failure::new(label, InvalidTransition::new(value, EDGE_INDEX_TARGET)))
605    }
606}
607
608impl ValueTransition<IndexValue<FailureKind>> for FailureKindValue {
609    fn transition<'a>(
610        _label: &'static str,
611        value: Self::Value<'a>,
612    ) -> QueryResult<<IndexValue<FailureKind> as ValueDomain>::Value<'a>> {
613        Ok(value)
614    }
615}
616
617impl ValueTransition<FailureKindValue> for IndexValue<FailureKind> {
618    fn transition<'a>(
619        _label: &'static str,
620        value: Self::Value<'a>,
621    ) -> QueryResult<<FailureKindValue as ValueDomain>::Value<'a>> {
622        Ok(value)
623    }
624}