Skip to main content

rbatis_codegen/
ops_div.rs

1use crate::ops::{AsProxy, Div};
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_div_u64(value: &Value, other: u64) -> u64 {
7    if other == 0 {
8        return 0;
9    }
10    value.u64() / other
11}
12
13fn op_div_i64(value: &Value, other: i64) -> i64 {
14    if other == 0 {
15        return 0;
16    }
17    value.i64() / other
18}
19
20fn op_div_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_div_i64_value(value: &Value, other: i64) -> i64 {
29    let rhs = value.i64();
30    if rhs == 0 {
31        return 0;
32    }
33    other / rhs
34}
35
36fn op_div_u64_value(value: &Value, other: u64) -> u64 {
37    let rhs = value.u64();
38    if rhs == 0 {
39        return 0;
40    }
41    other / rhs
42}
43
44fn op_div_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_div(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_div_value(left: Value, rhs: Value) -> Value {
63    match left {
64        Value::I32(value) => {
65            if let Some(result) = integer_div(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_div(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_div(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_div(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) => Value::F32(value / rhs.f64() as f32),
113        Value::F64(value) => Value::F64(value / rhs.f64()),
114        Value::Ext(_, value) => op_div_value(*value, rhs),
115        _ => Value::Null,
116    }
117}
118
119impl_value_binary_op!(Div, op_div, op_div_value);
120impl_numeric_binary_op!(
121    Div,
122    op_div,
123    op_div_u64,
124    op_div_u64_value,
125    [u8, u16, u32, u64],
126    u64
127);
128impl_numeric_binary_op!(
129    Div,
130    op_div,
131    op_div_i64,
132    op_div_i64_value,
133    [i8, i16, i32, i64, isize, usize],
134    i64
135);
136impl_numeric_binary_op!(Div, op_div, op_div_f64, op_div_f64_value, [f32, f64], f64);
137impl_same_type_binary_op!(
138    Div,
139    op_div,
140    /,
141    [
142        u8, u16, u32, u64, i8, i16, i32, i64, isize, usize, f32, f64
143    ]
144);
145
146#[cfg(test)]
147mod test {
148    use crate::ops::Div;
149    use rbs::Value;
150
151    #[test]
152    fn test_div() {
153        let value = Value::I32(12);
154        assert_eq!((&value).op_div(&4i64), 3i64);
155        assert_eq!(value.op_div(4i64), 3i64);
156        assert_eq!(Value::I32(12).op_div(&&Value::I32(4)), Value::I32(3));
157    }
158
159    #[test]
160    fn test_div_by_zero() {
161        assert_eq!(Value::I32(12).op_div(0i64), 0i64);
162        assert_eq!((&Value::I32(12)).op_div(&&Value::I32(0)), Value::I32(0));
163    }
164
165    #[test]
166    fn test_integer_div_keeps_precision() {
167        let large = Value::I64(9_007_199_254_740_993);
168        assert_eq!(
169            large.op_div(&Value::I64(1)),
170            Value::I64(9_007_199_254_740_993)
171        );
172        assert_eq!(Value::I64(10).op_div(&Value::U64(3)), Value::I64(3));
173    }
174}