#![deny(rustdoc::broken_intra_doc_links)]
#[doc(hidden)]
#[macro_export]
macro_rules! __impl_validated_arithmetic_op {
(
$StructName:ident, $PolicyType:ident, $trait_name:ident, $method_name:ident, $msg:literal
) => {
impl<K: $crate::core::traits::NumKernel> std::ops::$trait_name<$StructName<K>>
for $StructName<K>
{
type Output = Self;
#[inline(always)]
fn $method_name(self, rhs: Self) -> Self::Output {
Self::try_new_validated(self.value.$method_name(rhs.value)).expect($msg)
}
}
impl<'a, K: $crate::core::traits::NumKernel> std::ops::$trait_name<$StructName<K>>
for &'a $StructName<K>
{
type Output = $StructName<K>;
#[inline(always)]
fn $method_name(self, rhs: $StructName<K>) -> Self::Output {
$StructName::<K>::try_new_validated(self.value.clone().$method_name(rhs.value))
.expect($msg)
}
}
impl<'a, K: $crate::core::traits::NumKernel> std::ops::$trait_name<&'a $StructName<K>>
for $StructName<K>
{
type Output = Self;
#[inline(always)]
fn $method_name(self, rhs: &'a Self) -> Self::Output {
Self::try_new_validated(self.value.$method_name(&rhs.value)).expect($msg)
}
}
impl<'a, K: $crate::core::traits::NumKernel> std::ops::$trait_name<&'a $StructName<K>>
for &'a $StructName<K>
{
type Output = $StructName<K>;
#[inline(always)]
fn $method_name(self, rhs: &'a $StructName<K>) -> Self::Output {
$StructName::<K>::try_new_validated(self.value.clone().$method_name(&rhs.value))
.expect($msg)
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __impl_validated_arithmetic_op_assign {
(
$StructName:ident, $PolicyType:ident, $trait_name:ident, $method_name:ident, $msg:literal
) => {
impl<K: $crate::core::traits::NumKernel> std::ops::$trait_name<$StructName<K>>
for $StructName<K>
{
#[inline(always)]
fn $method_name(&mut self, rhs: Self) {
self.value.$method_name(rhs.value);
let _ = K::$PolicyType::validate_ref(&self.value).expect($msg);
}
}
impl<'a, K: $crate::core::traits::NumKernel> std::ops::$trait_name<&'a $StructName<K>>
for $StructName<K>
{
#[inline(always)]
fn $method_name(&mut self, rhs: &'a Self) {
self.value.$method_name(&rhs.value);
let _ = K::$PolicyType::validate_ref(&self.value).expect($msg);
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __impl_validated_arithmetic_op_and_op_assign {
(
$StructName:ident, $PolicyType:ident, $trait_name:ident, $method_name:ident, $msg:literal
) => {
$crate::__impl_validated_arithmetic_op!(
$StructName,
$PolicyType,
$trait_name,
$method_name,
$msg
);
paste::paste! {
$crate::__impl_validated_arithmetic_op_assign!(
$StructName,
$PolicyType,
[<$trait_name Assign>], [<$method_name _assign>], $msg
);
}
};
}
#[macro_export]
macro_rules! define_validated_struct_type {
(
$StructName:ident,
$PolicyType:ident,
$RawType:ident,
$doc:literal,
$display_string:literal
) => {
#[doc = $doc]
#[repr(transparent)]
#[derive(
derive_more::with_trait::AsRef,
derive_more::with_trait::Debug,
derive_more::with_trait::Display,
derive_more::with_trait::LowerExp,
serde::Serialize,
serde::Deserialize,
)]
#[display($display_string, value)]
#[lower_exp($display_string, value)]
pub struct $StructName<K: $crate::core::traits::NumKernel> {
#[as_ref]
pub(crate) value: K::$RawType,
pub(crate) _phantom: std::marker::PhantomData<K>,
}
};
}
#[macro_export]
macro_rules! impl_validated_core_traits {
($StructName:ident, $RawType:ident) => {
impl<K: $crate::core::traits::NumKernel> try_create::IntoInner for $StructName<K> {
type InnerType = K::$RawType;
#[inline(always)]
fn into_inner(self) -> Self::InnerType {
self.value
}
}
impl<K: $crate::core::traits::NumKernel> Clone for $StructName<K> {
#[inline(always)]
fn clone(&self) -> Self {
Self {
value: self.value.clone(),
_phantom: std::marker::PhantomData,
}
}
}
impl<K: $crate::core::traits::NumKernel> PartialEq for $StructName<K> {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
self.value.eq(&other.value)
}
}
};
}
#[macro_export]
macro_rules! impl_validated_constructors {
($StructName:ident, $PolicyType:ident, $RawType:ident) => {
impl<K: $crate::core::traits::NumKernel> try_create::TryNewValidated for $StructName<K> {
type Policy = K::$PolicyType;
#[inline(always)]
fn try_new_validated(value: Self::InnerType) -> Result<Self, Self::Error> {
let value = Self::Policy::validate(value)?;
Ok(Self {
value,
_phantom: std::marker::PhantomData,
})
}
}
impl<K: $crate::core::traits::NumKernel> try_create::TryNew for $StructName<K> {
type Error = <<K as $crate::core::traits::NumKernel>::$PolicyType as try_create::ValidationPolicy>::Error;
#[inline(always)]
fn try_new(value: Self::InnerType) -> Result<Self, Self::Error> {
Self::try_new_validated(value)
}
}
impl<K: $crate::core::traits::NumKernel> $StructName<K> {
#[deprecated(since = "0.3.0", note = "Use `try_new().unwrap()` instead. Will be removed in 1.0.")]
#[inline(always)]
pub fn new(value: K::$RawType) -> Self {
Self::try_new_validated(value)
.expect("new() validation failed - use try_new() for error handling")
}
#[inline(always)]
pub unsafe fn new_unchecked(value: K::$RawType) -> Self {
#[cfg(debug_assertions)]
{
Self::try_new_validated(value)
.expect("new_unchecked() validation failed in debug mode - contract violated")
}
#[cfg(not(debug_assertions))]
{
Self {
value,
_phantom: std::marker::PhantomData,
}
}
}
}
};
}
#[macro_export]
macro_rules! impl_validated_numeric_traits {
($StructName:ident, $PolicyType:ident, $RawType:ident) => {
impl<K: $crate::core::traits::NumKernel> num::Zero for $StructName<K> {
#[inline(always)]
fn zero() -> Self {
Self {
value: <K::$RawType as $crate::kernels::RawScalarTrait>::raw_zero(
K::$PolicyType::PRECISION,
),
_phantom: std::marker::PhantomData,
}
}
#[inline(always)]
fn is_zero(&self) -> bool {
self.value.is_zero()
}
}
impl<K: $crate::core::traits::NumKernel> num::One for $StructName<K> {
#[inline(always)]
fn one() -> Self {
Self {
value: <K::$RawType as $crate::kernels::RawScalarTrait>::raw_one(
K::$PolicyType::PRECISION,
),
_phantom: std::marker::PhantomData,
}
}
}
impl<K: $crate::core::traits::NumKernel> $crate::FpChecks for $StructName<K> {
#[inline(always)]
fn is_finite(&self) -> bool {
self.value.is_finite()
}
#[inline(always)]
fn is_infinite(&self) -> bool {
self.value.is_infinite()
}
#[inline(always)]
fn is_nan(&self) -> bool {
self.value.is_nan()
}
#[inline(always)]
fn is_normal(&self) -> bool {
self.value.is_normal()
}
}
};
}
#[macro_export]
macro_rules! impl_validated_arithmetic {
($StructName:ident, $PolicyType:ident) => {
$crate::__impl_validated_arithmetic_op_and_op_assign!(
$StructName,
$PolicyType,
Add,
add,
"Addition failed validation"
);
$crate::__impl_validated_arithmetic_op_and_op_assign!(
$StructName,
$PolicyType,
Sub,
sub,
"Subtraction failed validation"
);
$crate::__impl_validated_arithmetic_op_and_op_assign!(
$StructName,
$PolicyType,
Mul,
mul,
"Multiplication failed validation"
);
$crate::__impl_validated_arithmetic_op_and_op_assign!(
$StructName,
$PolicyType,
Div,
div,
"Division failed validation"
);
};
}
#[macro_export]
macro_rules! impl_validated_special_ops {
($StructName:ident, $PolicyType:ident) => {
impl<K: $crate::core::traits::NumKernel> std::ops::Neg for $StructName<K> {
type Output = Self;
#[inline(always)]
fn neg(self) -> Self::Output {
Self {
value: -self.value,
_phantom: std::marker::PhantomData,
}
}
}
impl<K: $crate::core::traits::NumKernel> $crate::functions::NegAssign for $StructName<K> {
#[inline(always)]
fn neg_assign(&mut self) {
self.value.neg_assign();
}
}
impl<K: $crate::core::traits::NumKernel> $crate::MulAddRef for $StructName<K> {
#[inline(always)]
fn mul_add_ref(self, b: &Self, c: &Self) -> Self {
Self::try_new_validated(self.value.unchecked_mul_add(&b.value, &c.value))
.expect("mul_add_ref failed validation")
}
}
};
}
#[macro_export]
macro_rules! impl_validated_sum {
($StructName:ident, $PolicyType:ident) => {
impl<K: $crate::core::traits::NumKernel> $crate::algorithms::neumaier_sum::NeumaierAddable
for $StructName<K>
{
fn neumaier_compensated_sum(value: Self, sum: &mut Self, compensation: &mut Self) {
$crate::algorithms::neumaier_sum::NeumaierAddable::neumaier_compensated_sum(
value.value,
&mut sum.value,
&mut compensation.value,
);
let _ = K::$PolicyType::validate_ref(&sum.value)
.expect("Neumaier compensated sum failed validation for sum");
let _ = K::$PolicyType::validate_ref(&compensation.value)
.expect("Neumaier compensated sum failed validation for compensation");
}
}
impl<K: $crate::core::traits::NumKernel> std::iter::Sum for $StructName<K> {
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = Self>,
{
$crate::algorithms::neumaier_sum::NeumaierSum::new_sequential(iter).sum()
}
}
};
}
#[macro_export]
macro_rules! define_validated_struct_modular {
(
$StructName:ident,
$PolicyType:ident,
$RawType:ident,
$doc:literal,
$display_string:literal
) => {
$crate::define_validated_struct_type!(
$StructName,
$PolicyType,
$RawType,
$doc,
$display_string
);
$crate::impl_validated_core_traits!($StructName, $RawType);
$crate::impl_validated_constructors!($StructName, $PolicyType, $RawType);
$crate::impl_validated_numeric_traits!($StructName, $PolicyType, $RawType);
$crate::impl_validated_arithmetic!($StructName, $PolicyType);
$crate::impl_validated_special_ops!($StructName, $PolicyType);
$crate::impl_validated_sum!($StructName, $PolicyType);
};
}
#[allow(unused_imports)]
pub use {
define_validated_struct_modular, define_validated_struct_type, impl_validated_arithmetic,
impl_validated_constructors, impl_validated_core_traits, impl_validated_numeric_traits,
impl_validated_special_ops, impl_validated_sum,
};
#[macro_export]
macro_rules! real {
($value:expr) => {{
use $crate::RealScalar;
$crate::backends::native64::validated::RealNative64StrictFinite::from_f64($value)
}};
}
#[macro_export]
macro_rules! complex {
($re:expr, $im:expr) => {{
use $crate::functions::ComplexScalarConstructors;
$crate::backends::native64::validated::ComplexNative64StrictFinite::new_complex(
$crate::real!($re),
$crate::real!($im),
)
}};
}
#[cfg(test)]
mod tests {
use crate::functions::ComplexScalarGetParts;
#[test]
fn test_real_macro_basic() {
let x = real!(3.);
assert!((x.as_ref() - 3.).abs() < 1e-10);
}
#[test]
fn test_real_macro_constants() {
use std::f64::consts::PI;
let pi = real!(PI);
assert!((pi.as_ref() - PI).abs() < 1e-15);
}
#[test]
fn test_real_macro_negative() {
let x = real!(-42.5);
assert_eq!(*x.as_ref(), -42.5);
}
#[test]
fn test_complex_macro_basic() {
let z = complex!(1.0, 2.0);
assert_eq!(*z.real_part().as_ref(), 1.0);
assert_eq!(*z.imag_part().as_ref(), 2.0);
}
#[test]
fn test_complex_macro_zero_imaginary() {
let z = complex!(5.0, 0.0);
assert_eq!(*z.real_part().as_ref(), 5.0);
assert_eq!(*z.imag_part().as_ref(), 0.0);
}
#[test]
fn test_complex_macro_negative() {
let z = complex!(-3.0, -4.0);
assert_eq!(*z.real_part().as_ref(), -3.0);
assert_eq!(*z.imag_part().as_ref(), -4.0);
}
#[test]
#[should_panic(expected = "RealScalar::from_f64() failed")]
fn test_real_macro_nan() {
let _x = real!(f64::NAN);
}
#[test]
#[should_panic(expected = "RealScalar::from_f64() failed")]
fn test_real_macro_inf() {
let _x = real!(f64::INFINITY);
}
#[test]
#[should_panic(expected = "RealScalar::from_f64() failed")]
fn test_complex_macro_nan_real() {
let _z = complex!(f64::NAN, 1.0);
}
#[test]
#[should_panic(expected = "RealScalar::from_f64() failed")]
fn test_complex_macro_inf_imaginary() {
let _z = complex!(1.0, f64::INFINITY);
}
}