Skip to main content

graphrecords_query/capabilities/arithmetic/
modulo.rs

1use 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}