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