use crate::scalar::macros::*;
use crate::*;
use std::convert::TryFrom;
use std::ops::{Add, Div, Mul, Neg, Not, Sub};
use std::ops::{AddAssign, DivAssign, MulAssign, SubAssign};
pub struct Rint(pub i32);
impl Rint {
gen_impl!(Rint, i32);
}
gen_trait_impl!(Rint, i32, |x: &Rint| x.0 == i32::MIN, i32::MIN);
gen_from_primitive!(Rint, i32);
gen_from_scalar!(Rint, i32);
gen_sum_iter!(Rint);
gen_binop!(
Rint,
i32,
Add,
|lhs: i32, rhs| lhs.checked_add(rhs),
"Add two Rint values or an option of i32, overflows to NA."
);
gen_binop!(
Rint,
i32,
Sub,
|lhs: i32, rhs| lhs.checked_sub(rhs),
"Subtract two Rint values or an option of i32, overflows to NA."
);
gen_binop!(
Rint,
i32,
Mul,
|lhs: i32, rhs| lhs.checked_mul(rhs),
"Multiply two Rint values or an option of i32, overflows to NA."
);
gen_binop!(
Rint,
i32,
Div,
|lhs: i32, rhs| lhs.checked_div(rhs),
"Divide two Rint values or an option of i32, overflows to NA."
);
gen_binopassign!(
Rint,
i32,
AddAssign,
|lhs: i32, rhs| lhs.checked_add(rhs),
"Add two Rint values or an option of i32, modifying the left-hand side in place. Overflows to NA."
);
gen_binopassign!(
Rint,
i32,
SubAssign,
|lhs: i32, rhs| lhs.checked_sub(rhs),
"Subtract two Rint values or an option of i32, modifying the left-hand side in place. Overflows to NA."
);
gen_binopassign!(
Rint,
i32,
MulAssign,
|lhs: i32, rhs| lhs.checked_mul(rhs),
"Multiply two Rint values or an option of i32, modifying the left-hand side in place. Overflows to NA."
);
gen_binopassign!(
Rint,
i32,
DivAssign,
|lhs: i32, rhs| lhs.checked_div(rhs),
"Divide two Rint values or an option of i32, modifying the left-hand side in place. Overflows to NA."
);
gen_unop!(
Rint,
Neg,
|lhs: i32| Some(-lhs),
"Negate a Rint value, overflows to NA."
);
gen_unop!(
Rint,
Not,
|lhs: i32| Some(!lhs),
"Logical not a Rint value, overflows to NA."
);
impl TryFrom<&Robj> for Rint {
type Error = Error;
fn try_from(robj: &Robj) -> Result<Self> {
match robj.len() {
0 => return Err(Error::ExpectedNonZeroLength(robj.clone())),
1 => {}
_ => return Err(Error::ExpectedScalar(robj.clone())),
};
if robj.is_na() {
return Ok(Rint::na());
}
if let Some(v) = robj.as_integer() {
if let Ok(v) = Self::try_from(v) {
return Ok(v);
} else {
return Err(Error::OutOfLimits(robj.clone()));
}
}
if let Some(v) = robj.as_real() {
let result = v as i32;
if (result as f64 - v).abs() < f64::EPSILON {
return Ok(Rint::from(result));
} else {
return Err(Error::ExpectedWholeNumber(robj.clone()));
}
}
Err(Error::ExpectedNumeric(robj.clone()))
}
}
impl std::fmt::Debug for Rint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.is_na() {
write!(f, "NA_INTEGER")
} else {
self.inner().fmt(f)
}
}
}