graphrecords_query/capabilities/arithmetic/
modulo.rs1use crate::{
2 AttributeName, Failure, IndexValue, Positional, QueryResult, Scalar, ValueDomain,
3 error::arithmetic::ModuloByZero,
4};
5use graphrecords_core::graphrecord::{
6 EdgeIndex, GraphRecordAttribute, GraphRecordValue, NodeIndex, datatypes::Mod,
7};
8
9pub trait ValueModulo: ValueDomain {
10 fn modulo<'a>(
11 label: &'static str,
12 value: Self::Value<'a>,
13 argument: Self::Value<'a>,
14 ) -> QueryResult<Self::Value<'a>>;
15}
16
17const fn is_attribute_modulo_by_zero(
18 value: &GraphRecordAttribute,
19 modulus: &GraphRecordAttribute,
20) -> bool {
21 matches!(
22 (value, modulus),
23 (GraphRecordAttribute::Int(_), GraphRecordAttribute::Int(0))
24 )
25}
26
27fn is_graphrecord_value_modulo_by_zero(
28 value: &GraphRecordValue,
29 modulus: &GraphRecordValue,
30) -> bool {
31 match (value, modulus) {
32 (GraphRecordValue::Int(_) | GraphRecordValue::Float(_), GraphRecordValue::Int(0)) => true,
33 (
34 GraphRecordValue::Int(_) | GraphRecordValue::Float(_),
35 GraphRecordValue::Float(modulus),
36 ) => *modulus == 0.0,
37 _ => false,
38 }
39}
40
41impl ValueModulo for Scalar {
42 fn modulo<'a>(
43 label: &'static str,
44 value: Self::Value<'a>,
45 argument: Self::Value<'a>,
46 ) -> QueryResult<Self::Value<'a>> {
47 if is_graphrecord_value_modulo_by_zero(&value, &argument) {
48 return Err(Failure::new(label, ModuloByZero));
49 }
50
51 value
52 .r#mod(argument)
53 .map_err(|error| Failure::new(label, error))
54 }
55}
56
57impl ValueModulo for AttributeName {
58 fn modulo<'a>(
59 label: &'static str,
60 value: Self::Value<'a>,
61 argument: Self::Value<'a>,
62 ) -> QueryResult<Self::Value<'a>> {
63 if is_attribute_modulo_by_zero(&value, &argument) {
64 return Err(Failure::new(label, ModuloByZero));
65 }
66
67 value
68 .r#mod(argument)
69 .map_err(|error| Failure::new(label, error))
70 }
71}
72
73impl ValueModulo for IndexValue<Positional> {
74 fn modulo<'a>(
75 label: &'static str,
76 value: Self::Value<'a>,
77 argument: Self::Value<'a>,
78 ) -> QueryResult<Self::Value<'a>> {
79 if argument == 0 {
80 return Err(Failure::new(label, ModuloByZero));
81 }
82
83 Ok(value % argument)
84 }
85}
86
87impl ValueModulo for IndexValue<NodeIndex> {
88 fn modulo<'a>(
89 label: &'static str,
90 value: Self::Value<'a>,
91 argument: Self::Value<'a>,
92 ) -> QueryResult<Self::Value<'a>> {
93 if is_attribute_modulo_by_zero(&value, &argument) {
94 return Err(Failure::new(label, ModuloByZero));
95 }
96
97 value
98 .r#mod(argument)
99 .map_err(|error| Failure::new(label, error))
100 }
101}
102
103impl ValueModulo for IndexValue<AttributeName> {
104 fn modulo<'a>(
105 label: &'static str,
106 value: Self::Value<'a>,
107 argument: Self::Value<'a>,
108 ) -> QueryResult<Self::Value<'a>> {
109 if is_attribute_modulo_by_zero(&value, &argument) {
110 return Err(Failure::new(label, ModuloByZero));
111 }
112
113 value
114 .r#mod(argument)
115 .map_err(|error| Failure::new(label, error))
116 }
117}
118
119impl ValueModulo for IndexValue<EdgeIndex> {
120 fn modulo<'a>(
121 label: &'static str,
122 value: Self::Value<'a>,
123 argument: Self::Value<'a>,
124 ) -> QueryResult<Self::Value<'a>> {
125 if argument == 0 {
126 return Err(Failure::new(label, ModuloByZero));
127 }
128
129 Ok(value % argument)
130 }
131}
132
133impl ValueModulo for IndexValue<GraphRecordValue> {
134 fn modulo<'a>(
135 label: &'static str,
136 value: Self::Value<'a>,
137 argument: Self::Value<'a>,
138 ) -> QueryResult<Self::Value<'a>> {
139 if is_graphrecord_value_modulo_by_zero(&value, &argument) {
140 return Err(Failure::new(label, ModuloByZero));
141 }
142
143 value
144 .r#mod(argument)
145 .map_err(|error| Failure::new(label, error))
146 }
147}