rbatis-codegen 4.9.4

The Rust SQL Toolkit and ORM Library. An async, pure Rust SQL crate featuring compile-time Dynamic SQL gen system
Documentation
use crate::ops::{AsProxy, Rem};
use crate::ops_compare::integer_value;
use crate::ops_macros::{impl_numeric_binary_op, impl_same_type_binary_op, impl_value_binary_op};
use rbs::Value;

fn op_rem_u64(value: &Value, other: u64) -> u64 {
    if other == 0 {
        return 0;
    }
    value.u64() % other
}

fn op_rem_i64(value: &Value, other: i64) -> i64 {
    if other == 0 {
        return 0;
    }
    value.i64() % other
}

fn op_rem_f64(value: &Value, other: f64) -> f64 {
    if other == 0.0 {
        0.0
    } else {
        value.f64() % other
    }
}

fn op_rem_u64_value(value: &Value, other: u64) -> u64 {
    let rhs = value.u64();
    if rhs == 0 {
        return 0;
    }
    other % rhs
}

fn op_rem_i64_value(value: &Value, other: i64) -> i64 {
    let rhs = value.i64();
    if rhs == 0 {
        return 0;
    }
    other % rhs
}

fn op_rem_f64_value(value: &Value, other: f64) -> f64 {
    let rhs = value.f64();
    if rhs == 0.0 {
        0.0
    } else {
        other % rhs
    }
}

fn integer_rem(left: i128, rhs: &Value) -> Option<i128> {
    let rhs = integer_value(rhs)?;
    if rhs == 0 {
        Some(0)
    } else {
        Some(left % rhs)
    }
}

fn op_rem_value(left: Value, rhs: Value) -> Value {
    match left {
        Value::I32(value) => {
            if let Some(result) = integer_rem(value as i128, &rhs) {
                return i32::try_from(result)
                    .map(Value::I32)
                    .unwrap_or(Value::I32(0));
            }
            let rhs = rhs.f64();
            if rhs == 0.0 {
                return Value::I32(0);
            }
            Value::I32((value as f64 % rhs) as i32)
        }
        Value::I64(value) => {
            if let Some(result) = integer_rem(value as i128, &rhs) {
                return i64::try_from(result)
                    .map(Value::I64)
                    .unwrap_or(Value::I64(0));
            }
            let rhs = rhs.f64();
            if rhs == 0.0 {
                return Value::I64(0);
            }
            Value::I64((value as f64 % rhs) as i64)
        }
        Value::U32(value) => {
            if let Some(result) = integer_rem(value as i128, &rhs) {
                return u32::try_from(result)
                    .map(Value::U32)
                    .unwrap_or(Value::U32(0));
            }
            let rhs = rhs.f64();
            if rhs == 0.0 {
                return Value::U32(0);
            }
            Value::U32((value as f64 % rhs) as u32)
        }
        Value::U64(value) => {
            if let Some(result) = integer_rem(value as i128, &rhs) {
                return u64::try_from(result)
                    .map(Value::U64)
                    .unwrap_or(Value::U64(0));
            }
            let rhs = rhs.f64();
            if rhs == 0.0 {
                return Value::U64(0);
            }
            Value::U64((value as f64 % rhs) as u64)
        }
        Value::F32(value) => {
            let rhs = rhs.f64() as f32;
            if rhs == 0.0 {
                return Value::F32(0.0);
            }
            Value::F32(value % rhs)
        }
        Value::F64(value) => {
            let rhs = rhs.f64();
            if rhs == 0.0 {
                return Value::F64(0.0);
            }
            Value::F64(value % rhs)
        }
        Value::Ext(_, value) => op_rem_value(*value, rhs),
        _ => Value::Null,
    }
}

impl_value_binary_op!(Rem, op_rem, op_rem_value);
impl_numeric_binary_op!(
    Rem,
    op_rem,
    op_rem_u64,
    op_rem_u64_value,
    [u8, u16, u32, u64],
    u64
);
impl_numeric_binary_op!(
    Rem,
    op_rem,
    op_rem_i64,
    op_rem_i64_value,
    [i8, i16, i32, i64, isize, usize],
    i64
);
impl_numeric_binary_op!(Rem, op_rem, op_rem_f64, op_rem_f64_value, [f32, f64], f64);
impl_same_type_binary_op!(
    Rem,
    op_rem,
    %,
    [
        u8, u16, u32, u64, i8, i16, i32, i64, isize, usize, f32, f64
    ]
);

#[cfg(test)]
mod test {
    use crate::ops::Rem;
    use rbs::Value;

    #[test]
    fn test_rem() {
        let value = Value::I32(13);
        assert_eq!((&value).op_rem(&5i64), 3i64);
        assert_eq!(value.op_rem(5i64), 3i64);
        assert_eq!(Value::I32(13).op_rem(&&Value::I32(5)), Value::I32(3));
    }

    #[test]
    fn test_rem_by_zero() {
        assert_eq!(Value::I32(13).op_rem(0i64), 0i64);
        assert_eq!((&Value::I32(13)).op_rem(&&Value::I32(0)), Value::I32(0));
    }

    #[test]
    fn test_integer_rem_keeps_precision() {
        assert_eq!(
            Value::I64(9_007_199_254_740_993).op_rem(&Value::I64(2)),
            Value::I64(1)
        );
        assert_eq!(Value::I64(-5).op_rem(&Value::U64(2)), Value::I64(-1));
    }
}