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}