Skip to main content

rbatis_codegen/
ops_rem.rs

1use crate::ops::{AsProxy, Rem};
2use crate::ops_compare::integer_value;
3use crate::ops_macros::{impl_numeric_binary_op, impl_same_type_binary_op, impl_value_binary_op};
4use rbs::Value;
5
6fn op_rem_u64(value: &Value, other: u64) -> u64 {
7    if other == 0 {
8        return 0;
9    }
10    value.u64() % other
11}
12
13fn op_rem_i64(value: &Value, other: i64) -> i64 {
14    if other == 0 {
15        return 0;
16    }
17    value.i64() % other
18}
19
20fn op_rem_f64(value: &Value, other: f64) -> f64 {
21    if other == 0.0 {
22        0.0
23    } else {
24        value.f64() % other
25    }
26}
27
28fn op_rem_u64_value(value: &Value, other: u64) -> u64 {
29    let rhs = value.u64();
30    if rhs == 0 {
31        return 0;
32    }
33    other % rhs
34}
35
36fn op_rem_i64_value(value: &Value, other: i64) -> i64 {
37    let rhs = value.i64();
38    if rhs == 0 {
39        return 0;
40    }
41    other % rhs
42}
43
44fn op_rem_f64_value(value: &Value, other: f64) -> f64 {
45    let rhs = value.f64();
46    if rhs == 0.0 {
47        0.0
48    } else {
49        other % rhs
50    }
51}
52
53fn integer_rem(left: i128, rhs: &Value) -> Option<i128> {
54    let rhs = integer_value(rhs)?;
55    if rhs == 0 {
56        Some(0)
57    } else {
58        Some(left % rhs)
59    }
60}
61
62fn op_rem_value(left: Value, rhs: Value) -> Value {
63    match left {
64        Value::I32(value) => {
65            if let Some(result) = integer_rem(value as i128, &rhs) {
66                return i32::try_from(result)
67                    .map(Value::I32)
68                    .unwrap_or(Value::I32(0));
69            }
70            let rhs = rhs.f64();
71            if rhs == 0.0 {
72                return Value::I32(0);
73            }
74            Value::I32((value as f64 % rhs) as i32)
75        }
76        Value::I64(value) => {
77            if let Some(result) = integer_rem(value as i128, &rhs) {
78                return i64::try_from(result)
79                    .map(Value::I64)
80                    .unwrap_or(Value::I64(0));
81            }
82            let rhs = rhs.f64();
83            if rhs == 0.0 {
84                return Value::I64(0);
85            }
86            Value::I64((value as f64 % rhs) as i64)
87        }
88        Value::U32(value) => {
89            if let Some(result) = integer_rem(value as i128, &rhs) {
90                return u32::try_from(result)
91                    .map(Value::U32)
92                    .unwrap_or(Value::U32(0));
93            }
94            let rhs = rhs.f64();
95            if rhs == 0.0 {
96                return Value::U32(0);
97            }
98            Value::U32((value as f64 % rhs) as u32)
99        }
100        Value::U64(value) => {
101            if let Some(result) = integer_rem(value as i128, &rhs) {
102                return u64::try_from(result)
103                    .map(Value::U64)
104                    .unwrap_or(Value::U64(0));
105            }
106            let rhs = rhs.f64();
107            if rhs == 0.0 {
108                return Value::U64(0);
109            }
110            Value::U64((value as f64 % rhs) as u64)
111        }
112        Value::F32(value) => {
113            let rhs = rhs.f64() as f32;
114            if rhs == 0.0 {
115                return Value::F32(0.0);
116            }
117            Value::F32(value % rhs)
118        }
119        Value::F64(value) => {
120            let rhs = rhs.f64();
121            if rhs == 0.0 {
122                return Value::F64(0.0);
123            }
124            Value::F64(value % rhs)
125        }
126        Value::Ext(_, value) => op_rem_value(*value, rhs),
127        _ => Value::Null,
128    }
129}
130
131impl_value_binary_op!(Rem, op_rem, op_rem_value);
132impl_numeric_binary_op!(
133    Rem,
134    op_rem,
135    op_rem_u64,
136    op_rem_u64_value,
137    [u8, u16, u32, u64],
138    u64
139);
140impl_numeric_binary_op!(
141    Rem,
142    op_rem,
143    op_rem_i64,
144    op_rem_i64_value,
145    [i8, i16, i32, i64, isize, usize],
146    i64
147);
148impl_numeric_binary_op!(Rem, op_rem, op_rem_f64, op_rem_f64_value, [f32, f64], f64);
149impl_same_type_binary_op!(
150    Rem,
151    op_rem,
152    %,
153    [
154        u8, u16, u32, u64, i8, i16, i32, i64, isize, usize, f32, f64
155    ]
156);
157
158#[cfg(test)]
159mod test {
160    use crate::ops::Rem;
161    use rbs::Value;
162
163    #[test]
164    fn test_rem() {
165        let value = Value::I32(13);
166        assert_eq!((&value).op_rem(&5i64), 3i64);
167        assert_eq!(value.op_rem(5i64), 3i64);
168        assert_eq!(Value::I32(13).op_rem(&&Value::I32(5)), Value::I32(3));
169    }
170
171    #[test]
172    fn test_rem_by_zero() {
173        assert_eq!(Value::I32(13).op_rem(0i64), 0i64);
174        assert_eq!((&Value::I32(13)).op_rem(&&Value::I32(0)), Value::I32(0));
175    }
176
177    #[test]
178    fn test_integer_rem_keeps_precision() {
179        assert_eq!(
180            Value::I64(9_007_199_254_740_993).op_rem(&Value::I64(2)),
181            Value::I64(1)
182        );
183        assert_eq!(Value::I64(-5).op_rem(&Value::U64(2)), Value::I64(-1));
184    }
185}