use crate::{Angle, Radians, radians};
use std::{
cmp::Ordering,
fmt::{Display, Formatter},
hash::{Hash, Hasher},
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};
#[derive(Clone, Copy, Debug, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
pub struct Real(pub(crate) f64);
impl Real {
pub const ZERO: Self = Self(0f64);
#[inline]
pub const fn new(v: f64) -> Self {
Self(v).with_check()
}
#[inline]
pub const fn check(&self) {
assert!(!self.0.is_nan(), "value is nan");
assert!(self.0.is_finite(), "value is inf");
}
#[inline]
pub const fn with_check(self) -> Self {
self.check();
self
}
#[inline]
pub fn ln(self) -> Self {
Self(self.0.ln())
}
#[inline]
pub const fn abs(self) -> Self {
Self(self.0.abs())
}
#[inline]
pub fn powf(self, v: f64) -> Self {
Self(self.0.powf(v))
}
#[inline]
pub fn sqrt(self) -> Self {
Self(self.0.sqrt())
}
#[inline]
pub fn asin(self) -> Angle<Radians> {
radians!(self.into_inner().asin())
}
#[inline]
pub fn acos(self) -> Angle<Radians> {
radians!(self.into_inner().acos())
}
#[inline]
pub fn atan2(self, other: Real) -> Angle<Radians> {
radians!(self.0.atan2(other.0))
}
#[inline]
pub const fn floor(self) -> Self {
Self(self.0.floor())
}
#[inline]
pub const fn trunc(self) -> Self {
Self(self.0.trunc())
}
#[inline]
pub const fn ceil(self) -> Self {
Self(self.0.ceil())
}
#[inline]
pub const fn untrunc(self) -> Self {
Self(self.0.trunc() + 1.)
}
#[inline]
pub const fn round(self) -> Self {
Self(self.0.round())
}
#[inline]
pub const fn signum(self) -> Real {
Self(self.0.signum())
}
#[inline]
pub const fn into_inner(self) -> f64 {
self.0
}
}
impl Display for Real {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl Hash for Real {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write(&self.0.to_le_bytes())
}
}
impl PartialEq for Real {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl Eq for Real {}
impl PartialOrd for Real {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Real {
fn cmp(&self, other: &Self) -> Ordering {
if self.0 < other.0 {
Ordering::Less
} else if self.0 > other.0 {
Ordering::Greater
} else {
Ordering::Equal
}
}
}
impl Neg for Real {
type Output = Self;
fn neg(self) -> Self::Output {
Self(-self.0)
}
}
impl Add for Real {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0)
}
}
impl AddAssign for Real {
fn add_assign(&mut self, rhs: Self) {
self.0 += rhs.0;
}
}
impl Sub for Real {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self(self.0 - rhs.0)
}
}
impl SubAssign for Real {
fn sub_assign(&mut self, rhs: Self) {
self.0 -= rhs.0;
}
}
impl Mul for Real {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self(self.0 * rhs.0)
}
}
impl MulAssign for Real {
fn mul_assign(&mut self, rhs: Self) {
self.0 *= rhs.0;
}
}
impl Div for Real {
type Output = Self;
fn div(self, rhs: Self) -> Self::Output {
Self(self.0 / rhs.0).with_check()
}
}
impl DivAssign for Real {
fn div_assign(&mut self, rhs: Self) {
self.0 /= rhs.0;
self.check();
}
}