use crate::prelude::{Rint, Scalar};
use crate::scalar::macros::*;
use crate::*;
use std::cmp::Ordering::*;
use std::convert::TryFrom;
use std::ops::{Add, Div, Mul, Neg, Sub};
use std::ops::{AddAssign, DivAssign, MulAssign, SubAssign};
#[repr(transparent)]
pub struct Rfloat(f64);
impl Scalar<f64> for Rfloat {
fn inner(&self) -> f64 {
self.0
}
fn new(val: f64) -> Self {
Rfloat(val)
}
}
impl Rfloat {
pub fn is_nan(&self) -> bool {
self.0.is_nan()
}
pub fn is_sign_positive(&self) -> bool {
self.0.is_sign_positive()
}
pub fn is_sign_negative(&self) -> bool {
self.0.is_sign_negative()
}
pub fn is_infinite(&self) -> bool {
self.0.is_infinite()
}
pub fn is_subnormal(&self) -> bool {
self.0.is_subnormal()
}
pub fn abs(&self) -> Rfloat {
self.0.abs().into()
}
pub fn sqrt(&self) -> Rfloat {
self.0.sqrt().into()
}
pub fn min(&self, other: Self) -> Self {
match self.partial_cmp(&other) {
Some(Less | Equal) => *self,
Some(Greater) => other,
_ => Self::na(),
}
}
pub fn max(&self, other: Self) -> Self {
match self.partial_cmp(&other) {
Some(Less) => other,
Some(Greater | Equal) => *self,
_ => Self::na(),
}
}
}
gen_trait_impl!(Rfloat, f64, |x: &Rfloat| x.inner().is_na(), f64::na());
gen_from_primitive!(Rfloat, f64);
impl From<Rfloat> for Option<f64> {
fn from(v: Rfloat) -> Self {
if v.is_na() {
None
} else {
Some(v.0)
}
}
}
gen_sum_iter!(Rfloat);
gen_partial_ord!(Rfloat, f64);
gen_binop!(
Rfloat,
f64,
Add,
|lhs: f64, rhs: f64| Some(lhs + rhs),
"Add two Rfloat values or an option of f64."
);
gen_binop!(
Rfloat,
f64,
Sub,
|lhs: f64, rhs: f64| Some(lhs - rhs),
"Subtract two Rfloat values or an option of f64."
);
gen_binop!(
Rfloat,
f64,
Mul,
|lhs: f64, rhs: f64| Some(lhs * rhs),
"Multiply two Rfloat values or an option of f64."
);
gen_binop!(
Rfloat,
f64,
Div,
|lhs: f64, rhs: f64| Some(lhs / rhs),
"Divide two Rfloat values or an option of f64."
);
gen_binopassign!(
Rfloat,
f64,
AddAssign,
|lhs: f64, rhs: f64| Some(lhs + rhs),
"Add two Rfloat values or an option of f64, modifying the left-hand side in place. Overflows to NA."
);
gen_binopassign!(
Rfloat,
f64,
SubAssign,
|lhs: f64, rhs: f64| Some(lhs - rhs),
"Subtract two Rfloat values or an option of f64, modifying the left-hand side in place. Overflows to NA."
);
gen_binopassign!(
Rfloat,
f64,
MulAssign,
|lhs: f64, rhs: f64| Some(lhs * rhs),
"Multiply two Rfloat values or an option of f64, modifying the left-hand side in place. Overflows to NA."
);
gen_binopassign!(
Rfloat,
f64,
DivAssign,
|lhs: f64, rhs: f64| Some(lhs / rhs),
"Divide two Rfloat values or an option of f64, modifying the left-hand side in place. Overflows to NA."
);
gen_unop!(Rfloat, Neg, |lhs: f64| Some(-lhs), "Negate a Rfloat value.");
impl From<i32> for Rfloat {
fn from(value: i32) -> Self {
Rfloat::from(value as f64)
}
}
impl From<Rint> for Rfloat {
fn from(value: Rint) -> Self {
if value.is_na() {
Rfloat::na()
} else {
Rfloat::from(value.inner())
}
}
}
impl TryFrom<&Robj> for Rfloat {
type Error = Error;
fn try_from(robj: &Robj) -> Result<Self> {
let f64_val: Result<f64> = robj.try_into();
match f64_val {
Ok(val) => Ok(Rfloat::from(val)),
Err(Error::MustNotBeNA(_)) => Ok(Rfloat::na()),
Err(e) => Err(e),
}
}
}
impl std::fmt::Debug for Rfloat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.is_na() {
write!(f, "NA_REAL")
} else {
self.inner().fmt(f)
}
}
}