use super::{QUIET_NAN, SIGN_MASK};
use crate::nan::NEG_QUIET_NAN;
use std::borrow::Borrow;
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct SingleNaNF64(f64);
impl SingleNaNF64 {
#[must_use]
pub fn new(val: f64) -> SingleNaNF64 {
match (val.is_nan(), val.is_sign_positive()) {
(true, true) => SingleNaNF64(f64::from_bits(QUIET_NAN)),
(true, false) => SingleNaNF64(f64::from_bits(NEG_QUIET_NAN)),
(false, _) => SingleNaNF64(val),
}
}
#[must_use]
pub fn from_mut(val: &mut f64) -> Option<&mut SingleNaNF64> {
if val.is_nan() && (val.to_bits() & SIGN_MASK) != QUIET_NAN {
None
} else {
let ptr = (val as *mut f64).cast::<SingleNaNF64>();
Some(unsafe { &mut *ptr })
}
}
#[inline]
pub fn write(&mut self, val: f64) {
*self = SingleNaNF64::new(val);
}
#[inline]
#[must_use]
pub fn get(self) -> f64 {
self.0
}
}
impl AsRef<f64> for SingleNaNF64 {
fn as_ref(&self) -> &f64 {
&self.0
}
}
impl Borrow<f64> for SingleNaNF64 {
fn borrow(&self) -> &f64 {
&self.0
}
}
impl Add for SingleNaNF64 {
type Output = SingleNaNF64;
fn add(self, rhs: Self) -> Self::Output {
SingleNaNF64::new(self.0 + rhs.0)
}
}
impl Add<f64> for SingleNaNF64 {
type Output = SingleNaNF64;
fn add(self, rhs: f64) -> Self::Output {
SingleNaNF64::new(self.0 + rhs)
}
}
impl Sub for SingleNaNF64 {
type Output = SingleNaNF64;
fn sub(self, rhs: Self) -> Self::Output {
SingleNaNF64::new(self.0 - rhs.0)
}
}
impl Sub<f64> for SingleNaNF64 {
type Output = SingleNaNF64;
fn sub(self, rhs: f64) -> Self::Output {
SingleNaNF64::new(self.0 - rhs)
}
}
impl Mul for SingleNaNF64 {
type Output = SingleNaNF64;
fn mul(self, rhs: Self) -> Self::Output {
SingleNaNF64::new(self.0 * rhs.0)
}
}
impl Mul<f64> for SingleNaNF64 {
type Output = SingleNaNF64;
fn mul(self, rhs: f64) -> Self::Output {
SingleNaNF64::new(self.0 * rhs)
}
}
impl Div for SingleNaNF64 {
type Output = SingleNaNF64;
fn div(self, rhs: Self) -> Self::Output {
SingleNaNF64::new(self.0 / rhs.0)
}
}
impl Div<f64> for SingleNaNF64 {
type Output = SingleNaNF64;
fn div(self, rhs: f64) -> Self::Output {
SingleNaNF64::new(self.0 / rhs)
}
}
impl AddAssign<f64> for SingleNaNF64 {
fn add_assign(&mut self, rhs: f64) {
self.write(self.0 + rhs)
}
}
impl SubAssign<f64> for SingleNaNF64 {
fn sub_assign(&mut self, rhs: f64) {
self.write(self.0 - rhs)
}
}
impl MulAssign<f64> for SingleNaNF64 {
fn mul_assign(&mut self, rhs: f64) {
self.write(self.0 * rhs)
}
}
impl DivAssign<f64> for SingleNaNF64 {
fn div_assign(&mut self, rhs: f64) {
self.write(self.0 / rhs)
}
}
#[cfg(test)]
mod tests {
use crate::nan::SingleNaNF64;
#[test]
fn test_add_assign() {
let mut a = SingleNaNF64::new(0.0);
a += 1.0;
assert_eq!(a.get(), 1.0);
}
}