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}