Skip to main content

num_valid/
macros.rs

1#![deny(rustdoc::broken_intra_doc_links)]
2
3//! Modular macro system for validated struct generation and convenience macros for creating validated numeric literals.
4//!
5//! This module provides a **refactored, modular version** of the monolithic
6//! `define_validated_struct!` macro. It breaks down the single 900+ line macro
7//! into smaller, composable macros for better maintainability and compile-time
8//! performance.
9//!
10//! This module also provides ergonomic macros for constructing validated numeric types
11//! from literals, similar to Rust's built-in `vec!`, `format!`, and other standard macros.
12//!
13//! # Examples
14//!
15//! ```
16//! use num_valid::{real, complex};
17//!
18//! // Create validated real numbers
19//! let pi = real!(3.14159);
20//! let e = real!(2.71828);
21//!
22//! // Create validated complex numbers
23//! let z1 = complex!(1.0, 2.0);  // 1 + 2i
24//! let z2 = complex!(-3.5, 4.2); // -3.5 + 4.2i
25//! ```
26//!
27//! The exported macros in this module are implementation infrastructure for
28//! `RealValidated` and `ComplexValidated`. They are not supported as an extension API
29//! for downstream crates.
30
31// These macros are exported at the crate root for use by this crate's modules.
32
33// --- MACRO HELPER 1: For the binary operations like: Add, Sub, Mul, Div ---
34// Generates the 4 implementations (T op T, &T op T, T op &T, &T op &T)
35// Uses paste! to construct the full path to std::ops traits
36#[doc(hidden)]
37#[macro_export]
38macro_rules! __impl_validated_arithmetic_op {
39    (
40        $StructName:ident, $PolicyType:ident, $trait_name:ident, $method_name:ident, $msg:literal
41    ) => {
42        // T op T
43        impl<K: $crate::core::traits::NumKernel> std::ops::$trait_name<$StructName<K>>
44            for $StructName<K>
45        {
46            type Output = Self;
47            #[inline(always)]
48            fn $method_name(self, rhs: Self) -> Self::Output {
49                Self::try_new_with_policy(self.value.$method_name(rhs.value)).expect($msg)
50            }
51        }
52        // &T op T
53        impl<'a, K: $crate::core::traits::NumKernel> std::ops::$trait_name<$StructName<K>>
54            for &'a $StructName<K>
55        {
56            type Output = $StructName<K>;
57            #[inline(always)]
58            fn $method_name(self, rhs: $StructName<K>) -> Self::Output {
59                $StructName::<K>::try_new_with_policy(self.value.clone().$method_name(rhs.value))
60                    .expect($msg)
61            }
62        }
63        // T op &T
64        impl<'a, K: $crate::core::traits::NumKernel> std::ops::$trait_name<&'a $StructName<K>>
65            for $StructName<K>
66        {
67            type Output = Self;
68            #[inline(always)]
69            fn $method_name(self, rhs: &'a Self) -> Self::Output {
70                Self::try_new_with_policy(self.value.$method_name(&rhs.value)).expect($msg)
71            }
72        }
73        // &T op &T
74        impl<'a, K: $crate::core::traits::NumKernel> std::ops::$trait_name<&'a $StructName<K>>
75            for &'a $StructName<K>
76        {
77            type Output = $StructName<K>;
78            #[inline(always)]
79            fn $method_name(self, rhs: &'a $StructName<K>) -> Self::Output {
80                $StructName::<K>::try_new_with_policy(self.value.clone().$method_name(&rhs.value))
81                    .expect($msg)
82            }
83        }
84    };
85}
86
87// --- MACRO HELPER 2: For the assignment operations like: AddAssign, SubAssign, etc. ---
88// Generates the 2 implementations (T op= T, T op= &T)
89// $trait_name must be a bare ident like AddAssign, SubAssign
90#[doc(hidden)]
91#[macro_export]
92macro_rules! __impl_validated_arithmetic_op_assign {
93    (
94        $StructName:ident, $PolicyType:ident, $trait_name:ident, $method_name:ident, $msg:literal
95    ) => {
96        // T op= T
97        impl<K: $crate::core::traits::NumKernel> std::ops::$trait_name<$StructName<K>>
98            for $StructName<K>
99        {
100            #[inline(always)]
101            fn $method_name(&mut self, rhs: Self) {
102                self.value.$method_name(rhs.value);
103                let _ = K::$PolicyType::validate_ref(&self.value).expect($msg);
104            }
105        }
106        // T op= &T
107        impl<'a, K: $crate::core::traits::NumKernel> std::ops::$trait_name<&'a $StructName<K>>
108            for $StructName<K>
109        {
110            #[inline(always)]
111            fn $method_name(&mut self, rhs: &'a Self) {
112                self.value.$method_name(&rhs.value);
113                let _ = K::$PolicyType::validate_ref(&self.value).expect($msg);
114            }
115        }
116    };
117}
118
119// --- MACRO HELPER 3: For both op and assignment op ---
120// $trait_name must be a bare ident like Add, Sub, Mul, Div
121// The macro will construct the full paths std::ops::Add and std::ops::AddAssign internally
122#[doc(hidden)]
123#[macro_export]
124macro_rules! __impl_validated_arithmetic_op_and_op_assign {
125    (
126        $StructName:ident, $PolicyType:ident, $trait_name:ident, $method_name:ident, $msg:literal
127    ) => {
128        // First, implement the binary operation
129        $crate::__impl_validated_arithmetic_op!(
130            $StructName,
131            $PolicyType,
132            $trait_name,
133            $method_name,
134            $msg
135        );
136        // Then, implement the assignment operation
137        paste::paste! {
138            $crate::__impl_validated_arithmetic_op_assign!(
139                $StructName,
140                $PolicyType,
141                [<$trait_name Assign>], // attach the string "Assign" at the end of the $trait_name
142                [<$method_name _assign>], // attach the string "_assign" at the end of the $method_name
143                $msg
144            );
145        }
146    };
147}
148// The following macros are NEW and provide modular alternatives to the monolithic macro
149
150/// Defines the validated struct with documentation and serialization support.
151///
152/// Creates a `#[repr(transparent)]` newtype wrapper around the raw type with:
153/// - Automatic `AsRef`, `Debug`, `Display`, `LowerExp` derives
154/// - Serde `Serialize` and `Deserialize` support
155/// - Phantom data for kernel type
156///
157/// ## Example
158///
159/// ```ignore
160/// define_validated_struct_type!(
161///     RealValidated,
162///     RealPolicy,
163///     RawReal,
164///     "A validated real number wrapper",
165///     "{value}"
166/// );
167/// ```
168///
169/// ## Parameters
170///
171/// - `$StructName`: Name of the struct (e.g., `RealValidated`)
172/// - `$PolicyType`: Policy field in `NumKernel` (e.g., `RealPolicy`)
173/// - `$RawType`: Raw value type (e.g., `RawReal`)
174/// - `$doc`: Documentation string
175/// - `$display_string`: Format string for Display/LowerExp (e.g., `"{value}"`)
176#[doc(hidden)]
177#[macro_export]
178macro_rules! define_validated_struct_type {
179    (
180        $StructName:ident,
181        $PolicyType:ident,
182        $RawType:ident,
183        $doc:literal,
184        $display_string:literal
185    ) => {
186        #[doc = $doc]
187        #[repr(transparent)]
188        #[derive(
189            derive_more::with_trait::AsRef,
190            derive_more::with_trait::Debug,
191            derive_more::with_trait::Display,
192            derive_more::with_trait::LowerExp,
193            serde::Serialize,
194            serde::Deserialize,
195        )]
196        #[display($display_string, value)]
197        #[lower_exp($display_string, value)]
198        pub struct $StructName<K: $crate::core::traits::NumKernel> {
199            #[as_ref]
200            pub(crate) value: K::$RawType,
201            pub(crate) _phantom: std::marker::PhantomData<K>,
202        }
203    };
204}
205
206/// Implements core utility traits: `IntoInner`, `Clone`, `PartialEq`.
207///
208/// ## Example
209///
210/// ```ignore
211/// impl_validated_core_traits!(MyType, RawReal);
212/// ```
213#[doc(hidden)]
214#[macro_export]
215macro_rules! impl_validated_core_traits {
216    ($StructName:ident, $RawType:ident) => {
217        impl<K: $crate::core::traits::NumKernel> try_create::IntoInner for $StructName<K> {
218            type InnerType = K::$RawType;
219
220            #[inline(always)]
221            fn into_inner(self) -> Self::InnerType {
222                self.value
223            }
224        }
225
226        impl<K: $crate::core::traits::NumKernel> Clone for $StructName<K> {
227            #[inline(always)]
228            fn clone(&self) -> Self {
229                Self {
230                    value: self.value.clone(),
231                    _phantom: std::marker::PhantomData,
232                }
233            }
234        }
235
236        impl<K: $crate::core::traits::NumKernel> PartialEq for $StructName<K> {
237            #[inline(always)]
238            fn eq(&self, other: &Self) -> bool {
239                self.value.eq(&other.value)
240            }
241        }
242    };
243}
244
245/// Implements the public `TryNew` trait and validated construction helpers.
246///
247/// - `try_new_with_policy()`: Internal constructor that always validates
248/// - `TryNew`: Public fallible construction API (from `try_create` crate)
249/// - `new()`: **DEPRECATED** - Always validates and panics on failure. Use `try_new()` instead.
250/// - `new_unchecked()`: **UNSAFE** - Validates only in debug builds, zero-cost in release.
251///
252/// ## Example
253///
254/// ```ignore
255/// impl_validated_constructors!(MyType, RealPolicy, RawReal);
256/// ```
257#[doc(hidden)]
258#[macro_export]
259macro_rules! impl_validated_constructors {
260    ($StructName:ident, $PolicyType:ident, $RawType:ident) => {
261        impl<K: $crate::core::traits::NumKernel> $StructName<K> {
262            #[inline(always)]
263            pub(crate) fn try_new_with_policy(
264                value: K::$RawType,
265            ) -> Result<
266                Self,
267                <<K as $crate::core::traits::NumKernel>::$PolicyType as try_create::ValidationPolicy>::Error,
268            > {
269                let value = K::$PolicyType::validate(value)?;
270                Ok(Self {
271                    value,
272                    _phantom: std::marker::PhantomData,
273                })
274            }
275        }
276
277        impl<K: $crate::core::traits::NumKernel> try_create::TryNew for $StructName<K> {
278            type Error = <<K as $crate::core::traits::NumKernel>::$PolicyType as try_create::ValidationPolicy>::Error;
279
280            #[inline(always)]
281            fn try_new(value: Self::InnerType) -> Result<Self, Self::Error> {
282                Self::try_new_with_policy(value)
283            }
284        }
285
286        impl<K: $crate::core::traits::NumKernel> $StructName<K> {
287            /// Creates a new instance, panicking if validation fails.
288            ///
289            /// **⚠️ DEPRECATED**: This method will be removed in version 1.0.
290            /// Use [`try_new()`](Self::try_new) for error handling or [`new_unchecked()`](Self::new_unchecked) for performance-critical code.
291            ///
292            /// # Panics
293            ///
294            /// Panics if the value fails validation (e.g., NaN, infinity, subnormal).
295            ///
296            /// # Migration Guide
297            ///
298            /// ```ignore
299            /// // Old (deprecated):
300            /// // let x = MyType::new(3.14);
301            ///
302            /// // New (recommended):
303            /// let x = MyType::try_new(3.14).unwrap();
304            ///
305            /// // Or for error handling:
306            /// let x = MyType::try_new(3.14)?;
307            /// ```
308            #[deprecated(since = "0.4.0", note = "Use `try_new().unwrap()` instead. Will be removed in a future release.")]
309            #[inline(always)]
310            pub fn new(value: K::$RawType) -> Self {
311                Self::try_new_with_policy(value)
312                    .expect("new() validation failed - use try_new() for error handling")
313            }
314
315            /// Creates a new instance without validation in release builds.
316            ///
317            /// # Safety
318            ///
319            /// The caller must guarantee that `value` satisfies the validation policy's requirements.
320            /// Violating this contract may lead to:
321            /// - NaN propagation in calculations
322            /// - Incorrect results in mathematical operations
323            /// - Hash collisions if used as HashMap keys (when policy guarantees finite values)
324            /// - Violation of type-level invariants
325            ///
326            /// In **debug builds**, this function validates the input and panics if invalid,
327            /// helping catch contract violations during development.
328            ///
329            /// In **release builds**, no validation is performed for maximum performance.
330            ///
331            /// # Recommended Usage
332            ///
333            /// Only use this function when:
334            /// 1. Performance is critical and validation overhead is unacceptable
335            /// 2. You have already validated the value through other means
336            /// 3. The value comes from a trusted source (e.g., compile-time constants)
337            ///
338            /// # Examples
339            ///
340            /// ```ignore
341            /// // SAFE: Compile-time constant known to be valid
342            /// let pi = unsafe { MyType::new_unchecked(3.141592653589793) };
343            ///
344            /// // UNSAFE: Runtime value - should use try_new() instead!
345            /// // let x = unsafe { MyType::new_unchecked(user_input) }; // DON'T DO THIS
346            /// ```
347            ///
348            /// # Alternative
349            ///
350            /// For most use cases, prefer [`try_new()`](Self::try_new) which always validates.
351            #[inline(always)]
352            pub unsafe fn new_unchecked(value: K::$RawType) -> Self {
353                #[cfg(debug_assertions)]
354                {
355                    Self::try_new_with_policy(value)
356                        .expect("new_unchecked() validation failed in debug mode - contract violated")
357                }
358                #[cfg(not(debug_assertions))]
359                {
360                    Self {
361                        value,
362                        _phantom: std::marker::PhantomData,
363                    }
364                }
365            }
366        }
367    };
368}
369
370/// Implements numeric traits: `Zero`, `One`, `FpChecks`.
371///
372/// ## Example
373///
374/// ```ignore
375/// impl_validated_numeric_traits!(MyType, RealPolicy, RawReal);
376/// ```
377#[doc(hidden)]
378#[macro_export]
379macro_rules! impl_validated_numeric_traits {
380    ($StructName:ident, $PolicyType:ident, $RawType:ident) => {
381        impl<K: $crate::core::traits::NumKernel> num::Zero for $StructName<K> {
382            #[inline(always)]
383            fn zero() -> Self {
384                Self {
385                    value: <K::$RawType as $crate::kernels::RawScalarTrait>::raw_zero(
386                        K::$PolicyType::PRECISION,
387                    ),
388                    _phantom: std::marker::PhantomData,
389                }
390            }
391
392            #[inline(always)]
393            fn is_zero(&self) -> bool {
394                self.value.is_zero()
395            }
396        }
397
398        impl<K: $crate::core::traits::NumKernel> num::One for $StructName<K> {
399            #[inline(always)]
400            fn one() -> Self {
401                Self {
402                    value: <K::$RawType as $crate::kernels::RawScalarTrait>::raw_one(
403                        K::$PolicyType::PRECISION,
404                    ),
405                    _phantom: std::marker::PhantomData,
406                }
407            }
408        }
409
410        impl<K: $crate::core::traits::NumKernel> $crate::FpChecks for $StructName<K> {
411            #[inline(always)]
412            fn is_finite(&self) -> bool {
413                self.value.is_finite()
414            }
415
416            #[inline(always)]
417            fn is_infinite(&self) -> bool {
418                self.value.is_infinite()
419            }
420
421            #[inline(always)]
422            fn is_nan(&self) -> bool {
423                self.value.is_nan()
424            }
425
426            #[inline(always)]
427            fn is_normal(&self) -> bool {
428                self.value.is_normal()
429            }
430        }
431    };
432}
433
434/// Implements arithmetic traits: `Add`, `Sub`, `Mul`, `Div` and their `*Assign` variants.
435///
436/// Generates all 6 implementations per operation (4 binary + 2 assignment).
437///
438/// ## Example
439///
440/// ```ignore
441/// impl_validated_arithmetic!(MyType, RealPolicy);
442/// ```
443#[doc(hidden)]
444#[macro_export]
445macro_rules! impl_validated_arithmetic {
446    ($StructName:ident, $PolicyType:ident) => {
447        $crate::__impl_validated_arithmetic_op_and_op_assign!(
448            $StructName,
449            $PolicyType,
450            Add,
451            add,
452            "Addition failed validation"
453        );
454
455        $crate::__impl_validated_arithmetic_op_and_op_assign!(
456            $StructName,
457            $PolicyType,
458            Sub,
459            sub,
460            "Subtraction failed validation"
461        );
462
463        $crate::__impl_validated_arithmetic_op_and_op_assign!(
464            $StructName,
465            $PolicyType,
466            Mul,
467            mul,
468            "Multiplication failed validation"
469        );
470
471        $crate::__impl_validated_arithmetic_op_and_op_assign!(
472            $StructName,
473            $PolicyType,
474            Div,
475            div,
476            "Division failed validation"
477        );
478    };
479}
480
481/// Implements special operations: `Neg`, `NegAssign`, `MulAddRef`.
482///
483/// ## Example
484///
485/// ```ignore
486/// impl_validated_special_ops!(MyType, RealPolicy);
487/// ```
488#[doc(hidden)]
489#[macro_export]
490macro_rules! impl_validated_special_ops {
491    ($StructName:ident, $PolicyType:ident) => {
492        impl<K: $crate::core::traits::NumKernel> std::ops::Neg for $StructName<K> {
493            type Output = Self;
494            #[inline(always)]
495            fn neg(self) -> Self::Output {
496                Self {
497                    value: -self.value,
498                    _phantom: std::marker::PhantomData,
499                }
500            }
501        }
502
503        impl<K: $crate::core::traits::NumKernel> $crate::functions::NegAssign for $StructName<K> {
504            #[inline(always)]
505            fn neg_assign(&mut self) {
506                self.value.neg_assign();
507            }
508        }
509
510        impl<K: $crate::core::traits::NumKernel> $crate::MulAddRef for $StructName<K> {
511            #[inline(always)]
512            fn mul_add_ref(self, b: &Self, c: &Self) -> Self {
513                Self::try_new_with_policy(self.value.unchecked_mul_add(&b.value, &c.value))
514                    .expect("mul_add_ref failed validation")
515            }
516        }
517    };
518}
519
520/// Implements `Sum` trait with Neumaier compensated summation algorithm.
521///
522/// Provides accurate summation for iterators by reducing floating-point errors.
523///
524/// ## Example
525///
526/// ```ignore
527/// impl_validated_sum!(MyType, RealPolicy);
528/// ```
529#[doc(hidden)]
530#[macro_export]
531macro_rules! impl_validated_sum {
532    ($StructName:ident, $PolicyType:ident) => {
533        impl<K: $crate::core::traits::NumKernel> $crate::algorithms::accumulators::NeumaierAddable
534            for $StructName<K>
535        {
536            fn neumaier_compensated_sum(value: Self, sum: &mut Self, compensation: &mut Self) {
537                $crate::algorithms::accumulators::NeumaierAddable::neumaier_compensated_sum(
538                    value.value,
539                    &mut sum.value,
540                    &mut compensation.value,
541                );
542                let _ = K::$PolicyType::validate_ref(&sum.value)
543                    .expect("Neumaier compensated sum failed validation for sum");
544                let _ = K::$PolicyType::validate_ref(&compensation.value)
545                    .expect("Neumaier compensated sum failed validation for compensation");
546            }
547        }
548
549        impl<K: $crate::core::traits::NumKernel> std::iter::Sum for $StructName<K> {
550            fn sum<I>(iter: I) -> Self
551            where
552                I: Iterator<Item = Self>,
553            {
554                <$crate::algorithms::accumulators::NeumaierSum<I::Item> as $crate::algorithms::accumulators::Accumulator>::result(
555                 <$crate::algorithms::accumulators::NeumaierSum<I::Item> as $crate::algorithms::accumulators::Accumulator>::new_sequential(iter))
556            }
557        }
558    };
559}
560
561#[doc(hidden)]
562#[macro_export]
563macro_rules! define_validated_struct_modular {
564    (
565        $StructName:ident,
566        $PolicyType:ident,
567        $RawType:ident,
568        $doc:literal,
569        $display_string:literal
570    ) => {
571        // 1. Struct definition
572        $crate::define_validated_struct_type!(
573            $StructName,
574            $PolicyType,
575            $RawType,
576            $doc,
577            $display_string
578        );
579
580        // 2. Core traits
581        $crate::impl_validated_core_traits!($StructName, $RawType);
582
583        // 3. Constructors
584        $crate::impl_validated_constructors!($StructName, $PolicyType, $RawType);
585
586        // 4. Numeric traits
587        $crate::impl_validated_numeric_traits!($StructName, $PolicyType, $RawType);
588
589        // 5. Arithmetic operations
590        $crate::impl_validated_arithmetic!($StructName, $PolicyType);
591
592        // 6. Special operations
593        $crate::impl_validated_special_ops!($StructName, $PolicyType);
594
595        // 7. Sum trait
596        $crate::impl_validated_sum!($StructName, $PolicyType);
597    };
598}
599
600// Re-export macro names for internal use within the crate.
601#[allow(unused_imports)]
602pub use {
603    define_validated_struct_modular, define_validated_struct_type, impl_validated_arithmetic,
604    impl_validated_constructors, impl_validated_core_traits, impl_validated_numeric_traits,
605    impl_validated_special_ops, impl_validated_sum,
606};
607
608/// Creates a validated real number from an f64 literal.
609///
610/// This macro provides a concise syntax for creating [`RealNative64StrictFinite`](crate::RealNative64StrictFinite)
611/// values from floating-point literals. It uses the panicking [`from_f64`](crate::RealScalar::from_f64)
612/// constructor, which is appropriate for compile-time constants and test code where
613/// validity is guaranteed.
614///
615/// # Panics
616///
617/// Panics if the provided value is not finite (NaN, infinity) or is subnormal.
618/// For fallible conversion, use [`RealScalar::try_from_f64`](crate::RealScalar::try_from_f64) directly.
619///
620/// # Examples
621///
622/// ```
623/// use num_valid::*;
624/// use std::f64::consts::PI;
625///
626/// let x = real!(3.14159);
627/// let y = real!(PI);
628/// let z = real!(-42.0);
629///
630/// assert!((x.as_raw_scalar_ref() - 3.14159).abs() < 1e-10);
631/// ```
632///
633/// Using with mathematical constants:
634///
635/// ```
636/// use num_valid::*;
637/// use std::f64::consts::{PI, E, TAU};
638///
639/// let pi = real!(PI);
640/// let e = real!(E);
641/// let tau = real!(TAU);
642///
643/// let circle_area = real!(PI) * real!(25.0); // π * r² with r=5
644/// ```
645#[macro_export]
646macro_rules! real {
647    ($value:expr) => {{
648        use $crate::RealScalar;
649        $crate::backends::native::validated::RealNative64StrictFinite::from_f64($value)
650    }};
651}
652
653/// Creates a validated single-precision real number from an f32 literal.
654///
655/// This macro is the [`f32`] counterpart of [`real!`]: it provides a concise syntax
656/// for creating [`RealNative32StrictFinite`](crate::RealNative32StrictFinite) values
657/// from single-precision floating-point literals. It uses the panicking
658/// [`from_f32`](crate::RealScalar::from_f32) constructor, appropriate for compile-time
659/// constants and test code where validity is guaranteed.
660///
661/// # Panics
662///
663/// Panics if the provided value is not finite (NaN, infinity) or is subnormal.
664/// For fallible conversion, use [`RealScalar::try_from_f32`](crate::RealScalar::try_from_f32) directly.
665///
666/// # Examples
667///
668/// ```
669/// use num_valid::*;
670/// use std::f32::consts::PI;
671///
672/// let x = real32!(3.14159);
673/// let y = real32!(PI);
674/// let z = real32!(-42.0);
675///
676/// assert!((x.as_raw_scalar_ref() - 3.14159).abs() < 1e-5);
677/// ```
678#[macro_export]
679macro_rules! real32 {
680    ($value:expr) => {{
681        use $crate::RealScalar;
682        $crate::backends::native::validated::RealNative32StrictFinite::from_f32($value)
683    }};
684}
685
686/// Creates a validated complex number from two f64 literals (real and imaginary parts).
687///
688/// This macro provides a concise syntax for creating [`ComplexNative64StrictFinite`](crate::ComplexNative64StrictFinite)
689/// values. It accepts two arguments: the real part and the imaginary part.
690///
691/// # Panics
692///
693/// Panics if either the real or imaginary part is not finite (NaN, infinity) or is subnormal.
694/// For fallible conversion, use [`ComplexNative64StrictFinite::try_new_complex`](crate::functions::ComplexScalarConstructors::try_new_complex) directly.
695///
696/// # Examples
697///
698/// ```
699/// use num_valid::complex;
700///
701/// let z1 = complex!(1.0, 2.0);   // 1 + 2i
702/// let z2 = complex!(-3.0, 4.0);  // -3 + 4i
703/// let z3 = complex!(0.0, -1.0);  // -i
704///
705/// // Euler's identity: e^(iπ) + 1 = 0
706/// use std::f64::consts::PI;
707/// use num_valid::{*, functions::{Exp, Abs}};
708///
709/// let i_pi = complex!(0.0, PI);
710/// let e_to_i_pi = i_pi.exp();
711/// let result = e_to_i_pi + complex!(1.0, 0.0);
712///
713/// assert!(result.abs().as_raw_scalar_ref() < &1e-10); // Very close to zero
714/// ```
715///
716/// Creating unit vectors in the complex plane:
717///
718/// ```
719/// use num_valid::complex;
720///
721/// let unit_real = complex!(1.0, 0.0);      // Real axis
722/// let unit_imag = complex!(0.0, 1.0);      // Imaginary axis
723/// let unit_45deg = complex!(0.707, 0.707); // 45° angle
724/// ```
725#[macro_export]
726macro_rules! complex {
727    ($re:expr, $im:expr) => {{
728        use $crate::functions::ComplexScalarConstructors;
729        $crate::backends::native::validated::ComplexNative64StrictFinite::new_complex(
730            $crate::real!($re),
731            $crate::real!($im),
732        )
733    }};
734}
735
736/// Creates a validated single-precision complex number from two f32 literals (real and imaginary parts).
737///
738/// This macro is the [`f32`] counterpart of [`complex!`]: it provides a concise syntax for
739/// creating [`ComplexNative32StrictFinite`](crate::ComplexNative32StrictFinite) values from
740/// two single-precision floating-point literals.
741///
742/// # Panics
743///
744/// Panics if either the real or imaginary part is not finite (NaN, infinity) or is subnormal.
745/// For fallible conversion, use [`ComplexNative32StrictFinite::try_new_complex`](crate::functions::ComplexScalarConstructors::try_new_complex) directly.
746///
747/// # Examples
748///
749/// ```
750/// use num_valid::complex32;
751///
752/// let z1 = complex32!(1.0, 2.0);   // 1 + 2i
753/// let z2 = complex32!(-3.0, 4.0);  // -3 + 4i
754/// ```
755#[macro_export]
756macro_rules! complex32 {
757    ($re:expr, $im:expr) => {{
758        use $crate::functions::ComplexScalarConstructors;
759        $crate::backends::native::validated::ComplexNative32StrictFinite::new_complex(
760            $crate::real32!($re),
761            $crate::real32!($im),
762        )
763    }};
764}
765
766#[cfg(test)]
767mod tests {
768    use crate::{functions::ComplexScalarGetParts, *};
769
770    #[test]
771    fn test_real_macro_basic() {
772        let x = real!(3.);
773        assert!((x.as_raw_scalar_ref() - 3.).abs() < 1e-10);
774    }
775
776    #[test]
777    fn test_real_macro_constants() {
778        use std::f64::consts::PI;
779        let pi = real!(PI);
780        assert!((pi.as_raw_scalar_ref() - PI).abs() < 1e-15);
781    }
782
783    #[test]
784    fn test_real_macro_negative() {
785        let x = real!(-42.5);
786        assert_eq!(*x.as_raw_scalar_ref(), -42.5);
787    }
788
789    #[test]
790    fn test_real32_macro_basic() {
791        let x = real32!(3.0_f32);
792        assert!((x.as_raw_scalar_ref() - 3.0).abs() < 1e-5);
793    }
794
795    #[test]
796    fn test_real32_macro_constants() {
797        use std::f32::consts::PI;
798        let pi = real32!(PI);
799        assert!((pi.as_raw_scalar_ref() - PI).abs() < 1e-6);
800    }
801
802    #[test]
803    fn test_real32_macro_negative() {
804        let x = real32!(-42.5_f32);
805        assert_eq!(*x.as_raw_scalar_ref(), -42.5);
806    }
807
808    #[test]
809    fn test_complex_macro_basic() {
810        let z = complex!(1.0, 2.0);
811        assert_eq!(*z.real_part().as_raw_scalar_ref(), 1.0);
812        assert_eq!(*z.imag_part().as_raw_scalar_ref(), 2.0);
813    }
814
815    #[test]
816    fn test_complex_macro_zero_imaginary() {
817        let z = complex!(5.0, 0.0);
818        assert_eq!(*z.real_part().as_raw_scalar_ref(), 5.0);
819        assert_eq!(*z.imag_part().as_raw_scalar_ref(), 0.0);
820    }
821
822    #[test]
823    fn test_complex_macro_negative() {
824        let z = complex!(-3.0, -4.0);
825        assert_eq!(*z.real_part().as_raw_scalar_ref(), -3.0);
826        assert_eq!(*z.imag_part().as_raw_scalar_ref(), -4.0);
827    }
828
829    #[test]
830    fn test_complex32_macro_basic() {
831        let z = complex32!(1.0_f32, 2.0_f32);
832        assert_eq!(*z.real_part().as_raw_scalar_ref(), 1.0);
833        assert_eq!(*z.imag_part().as_raw_scalar_ref(), 2.0);
834    }
835
836    #[test]
837    fn test_complex32_macro_zero_imaginary() {
838        let z = complex32!(5.0_f32, 0.0_f32);
839        assert_eq!(*z.real_part().as_raw_scalar_ref(), 5.0);
840        assert_eq!(*z.imag_part().as_raw_scalar_ref(), 0.0);
841    }
842
843    #[test]
844    fn test_complex32_macro_negative() {
845        let z = complex32!(-3.0_f32, -4.0_f32);
846        assert_eq!(*z.real_part().as_raw_scalar_ref(), -3.0);
847        assert_eq!(*z.imag_part().as_raw_scalar_ref(), -4.0);
848    }
849
850    #[test]
851    #[should_panic(
852        expected = "RealScalar::try_from_f64() failed: invalid conversion from f64 value"
853    )]
854    fn test_real_macro_nan() {
855        let _x = real!(f64::NAN);
856    }
857
858    #[test]
859    #[should_panic(
860        expected = "RealScalar::try_from_f64() failed: invalid conversion from f64 value"
861    )]
862    fn test_real_macro_inf() {
863        let _x = real!(f64::INFINITY);
864    }
865
866    #[test]
867    #[should_panic(
868        expected = "RealScalar::try_from_f32() failed: invalid conversion from f32 value"
869    )]
870    fn test_real32_macro_nan() {
871        let _x = real32!(f32::NAN);
872    }
873
874    #[test]
875    #[should_panic(
876        expected = "RealScalar::try_from_f32() failed: invalid conversion from f32 value"
877    )]
878    fn test_real32_macro_inf() {
879        let _x = real32!(f32::INFINITY);
880    }
881
882    #[test]
883    #[should_panic(
884        expected = "RealScalar::try_from_f64() failed: invalid conversion from f64 value"
885    )]
886    fn test_complex_macro_nan_real() {
887        let _z = complex!(f64::NAN, 1.0);
888    }
889
890    #[test]
891    #[should_panic(
892        expected = "RealScalar::try_from_f64() failed: invalid conversion from f64 value"
893    )]
894    fn test_complex_macro_inf_imaginary() {
895        let _z = complex!(1.0, f64::INFINITY);
896    }
897
898    #[test]
899    #[should_panic(
900        expected = "RealScalar::try_from_f32() failed: invalid conversion from f32 value"
901    )]
902    fn test_complex32_macro_nan_real() {
903        let _z = complex32!(f32::NAN, 1.0_f32);
904    }
905
906    #[test]
907    #[should_panic(
908        expected = "RealScalar::try_from_f32() failed: invalid conversion from f32 value"
909    )]
910    fn test_complex32_macro_inf_imaginary() {
911        let _z = complex32!(1.0_f32, f32::INFINITY);
912    }
913}