#![allow(clippy::float_cmp)]
#[macro_export]
macro_rules! assert_relative_eq {
($left:expr, $right:expr) => {{
let epsilon = 1e-7;
assert_relative_eq!($left, $right, epsilon);
}};
($left:expr, $right:expr, $epsilon:expr) => {{
let left_val: f64 = $left.into();
let right_val: f64 = $right.into();
assert!(
(left_val == right_val) || (left_val - right_val).abs() <= $epsilon,
"assertion failed: `(left ~= right)` \
(left: `{:?}`, right: `{:?}`, (left - right): `{:?}` > epsilon: `{:?}`)",
left_val,
right_val,
left_val - right_val,
$epsilon
);
}};
}
#[macro_export]
macro_rules! assert_is_nan {
($left:expr) => {{
let left_val = $left;
assert!(
left_val.is_nan(),
"assertion failed: `(value is NaN)` \
(value: `{:?}`)",
left_val,
);
}};
}
#[macro_export]
macro_rules! assert_is_positive_zero {
($left:expr) => {{
let val = $left;
assert!(
val == 0.0 && val.is_sign_positive(),
"assertion failed: `(value is positive zero)` \
(value: `{:?}`)",
val,
);
}};
}
#[macro_export]
macro_rules! assert_is_negative_zero {
($left:expr) => {{
let val = $left;
assert!(
val == 0.0 && val.is_sign_negative(),
"assertion failed: `(value is negative zero)` \
(value: `{:?}`)",
val,
);
}};
}
#[macro_export]
macro_rules! assert_float_eq {
($left:expr, $right:expr) => {{
if (!$left.is_nan() || !$right.is_nan()) {
assert_eq!($left, $right);
assert_eq!($left.is_sign_positive(), $right.is_sign_positive());
}
}};
}
#[macro_export]
macro_rules! as_const {
($type:ident, $float:ident, $x:expr) => {{
const TMP: $float = $x;
#[allow(clippy::float_cmp_const)]
const RESULT: $crate::$type<$float> = if TMP != TMP {
panic!("NaN is not valid")
} else if TMP == $float::INFINITY && !$crate::$type::accept_infinity() {
panic!("Infinity is not valid")
} else if TMP == $float::NEG_INFINITY && !$crate::$type::accept_infinity() {
panic!("Infinity is not valid")
} else if TMP == 0.0 && !$crate::$type::accept_zero() {
panic!("Zero is not valid")
} else if TMP < 0.0 && !$crate::$type::accept_negative() {
panic!("Negative value is not valid")
} else if TMP > 0.0 && !$crate::$type::accept_positive() {
panic!("Negative zero is not valid")
} else {
unsafe { $crate::$type::<$float>::internal_only_new_unchecked(TMP) }
};
RESULT
}};
($type:ident, $x:expr) => {{
$crate::as_const!($type, f64, $x)
}};
($x:expr) => {{
$crate::as_const!(f64, $x)
}};
}
#[macro_export]
macro_rules! generate_const {
($name:ident, $type:ident, $float:ident, $x:expr, $doc:expr) => {
#[doc = $doc]
pub const $name: $crate::$type<$float> = $crate::as_const!($type, $float, $x);
};
($name:ident, $type:ident, f32, $x:expr) => {
pub const $name: $crate::$type<f32> = $crate::as_const!($type, f32, $x);
};
($name:ident, $type:ident, f64, $x:expr) => {
pub const $name: $crate::$type<f64> = $crate::as_const!($type, f64, $x);
};
($name:ident, $type:ident, $x:expr, $doc:expr) => {
#[doc = $doc]
pub const $name: $crate::$type = $crate::as_const!($type, f64, $x);
};
($name:ident, $type:ident, $x:expr) => {
pub const $name: $crate::$type = $crate::as_const!($type, f64, $x);
};
}
macro_rules! new_unchecked {
($value:ident, $name:ident) => {{
if cfg!(any(
debug_assertions,
feature = "ensure_no_undefined_behavior"
)) {
if Self::new($value).is_err() {
panic!(concat!("This value is not a valid ", stringify!($name)));
}
} else if cfg!(feature = "compiler_hints") {
if Self::new($value).is_err() {
unsafe { core::hint::unreachable_unchecked() }
}
}
Self($value)
}};
}
pub(crate) use new_unchecked;