# num-valid Architecture Guide

**Version**: 0.2.5  
**Last Updated**: December 3, 2025  
**Audience**: Contributors, maintainers, and advanced users

---

## Table of Contents

1. [Overview](#overview)
2. [The 4-Layer Design Philosophy](#the-4-layer-design-philosophy)
3. [Layer 1: Raw Trait Contracts](#layer-1-raw-trait-contracts)
4. [Layer 2: Validation Policies](#layer-2-validation-policies)
5. [Layer 3: Validated Wrappers](#layer-3-validated-wrappers)
6. [Layer 4: High-Level Traits](#layer-4-high-level-traits)
7. [Adding a New Backend](#adding-a-new-backend)
8. [Adding Mathematical Functions](#adding-mathematical-functions)
9. [Error Handling Architecture](#error-handling-architecture)
10. [Macro System](#macro-system)
11. [Performance Considerations](#performance-considerations)
12. [Design Patterns Reference](#design-patterns-reference)

---

## Overview

`num-valid` implements a **layered architecture** that separates computational logic from validation logic, enabling zero-overhead abstractions while maintaining type-level safety guarantees.

### Core Design Principles

1. **Separation of Concerns**: Raw operations (Layer 1) are independent of validation (Layer 2)
2. **Zero-Cost Abstractions**: Validation overhead can be eliminated in release builds via policies
3. **Type-Level Guarantees**: Invalid states are unrepresentable (e.g., NaN in validated types)
4. **Backend Agnostic**: Support for both native f64 and arbitrary-precision arithmetic
5. **Composability**: Layers are orthogonal and can be mixed/matched

### Architecture Diagram

```
┌─────────────────────────────────────────────────────────────┐
│  Layer 4: High-Level Traits (FpScalar, RealScalar, etc.)   │
│  - User-facing generic programming interface                │
│  - Trait bounds for algorithms                              │
└─────────────────────────────────────────────────────────────┘
                            ▼
┌─────────────────────────────────────────────────────────────┐
│  Layer 3: Validated Wrappers (RealValidated<K>)            │
│  - Newtype pattern with validation                          │
│  - Implements high-level traits                             │
└─────────────────────────────────────────────────────────────┘
                            ▼
┌─────────────────────────────────────────────────────────────┐
│  Layer 2: Validation Policies (NumKernel)                   │
│  - StrictFinitePolicy, DebugValidationPolicy                │
│  - GuaranteesFiniteValues marker trait                      │
└─────────────────────────────────────────────────────────────┘
                            ▼
┌─────────────────────────────────────────────────────────────┐
│  Layer 1: Raw Trait Contracts (RawRealTrait, etc.)         │
│  - Unchecked operations (unchecked_sqrt, unchecked_ln)      │
│  - Implemented by f64, Complex<f64>, rug::Float             │
└─────────────────────────────────────────────────────────────┘
```

---

## The 4-Layer Design Philosophy

### Why Four Layers?

Each layer has a single, well-defined responsibility:

| Layer | Responsibility | Example |
|-------|----------------|---------|
| **1** | Pure computation without validation | `f64::unchecked_sqrt(x)` |
| **2** | Validation policy configuration | `StrictFinitePolicy` rejects NaN/Inf |
| **3** | Validated computation | `RealValidated::sqrt()` validates input & output |
| **4** | Generic interface | `fn compute<T: RealScalar>(x: T)` |

This separation enables:
- **Testing**: Each layer can be tested independently
- **Flexibility**: Change validation policy without touching computation
- **Performance**: Compile-time elimination of validation in release builds
- **Extensibility**: Add new backends by implementing Layer 1 only

---

## Layer 1: Raw Trait Contracts

**Location**: `src/kernels.rs`

### Core Traits

```rust
pub trait RawScalarTrait: Sized + Clone {
    type ValidationErrors: std::error::Error;
    
    // Validation is caller's responsibility
    fn unchecked_add(self, other: Self) -> Self;
    fn unchecked_mul(self, other: Self) -> Self;
    // ... more operations
}

pub trait RawRealTrait: RawScalarTrait {
    fn unchecked_sqrt(self) -> Self;
    fn unchecked_reciprocal(self) -> Self;
    fn unchecked_ln(self) -> Self;
    // ... more real-specific operations
}

pub trait RawComplexTrait: RawScalarTrait {
    type RealType: RawRealTrait;
    
    fn unchecked_from_polar(r: Self::RealType, theta: Self::RealType) -> Self;
    // ... more complex-specific operations
}
```

### Contract: The `unchecked_*` Naming Convention

**CRITICAL**: All methods in Layer 1 are prefixed with `unchecked_*` to communicate:

1. **No input validation**: Caller guarantees input validity
2. **No output validation**: Result may be NaN/Inf if input was invalid
3. **Performance**: Zero overhead, direct hardware/library call

**Example Contract Documentation**:

```rust
/// Computes the square root without validation.
///
/// # Contract
///
/// The caller MUST guarantee that `self` is:
/// - Finite (not NaN or infinity)
/// - Non-negative (for real numbers)
///
/// If the contract is violated, the result is unspecified (may be NaN).
fn unchecked_sqrt(self) -> Self;
```

### When to Implement Raw Traits

Implement `RawRealTrait` when adding a new numeric backend:

- Native types: `f64`, `f32`
- Arbitrary precision: `rug::Float`, `bigdecimal::BigDecimal`
- Fixed-point: Custom fixed-point types
- Symbolic: Expression trees (advanced)

**Implementation Checklist**:
- [ ] All methods return correct mathematical results for valid inputs
- [ ] Invalid inputs produce predictable outputs (NaN for reals)
- [ ] Performance is optimal (no unnecessary checks)
- [ ] Tests verify correctness on valid inputs only

---

## Layer 2: Validation Policies

**Location**: `src/validation.rs`

### The NumKernel Trait

The `NumKernel` trait bundles a raw type with its validation policy:

```rust
pub trait NumKernel {
    type RawReal: RawRealTrait;
    type RawComplex: RawComplexTrait<RealType = Self::RawReal>;
    type RealPolicy: ValidationPolicyReal<Value = Self::RawReal>;
    type ComplexPolicy: ValidationPolicyComplex<Value = Self::RawComplex>;
    const PRECISION: u32;
}
```

### Validation Policies

#### StrictFinitePolicy

**Guarantees**: All values are finite and normal (not subnormal)

```rust
pub struct StrictFinitePolicy<ScalarType, const PRECISION: u32>;

impl<T: RawRealTrait, const P: u32> ValidationPolicyReal 
    for StrictFinitePolicy<T, P> 
{
    const PRECISION: u32 = P;
    
    fn validate(value: &T) -> Result<(), ErrorsValidationRawReal<T>> {
        if !value.is_finite() {
            return Err(ErrorsValidationRawReal::NotFinite { /* ... */ });
        }
        if value.is_subnormal() && value != &T::zero() {
            return Err(ErrorsValidationRawReal::Subnormal { /* ... */ });
        }
        Ok(())
    }
}
```

**Use Cases**:
- Production code requiring strict correctness
- Numerical algorithms where NaN propagation must be prevented
- HashMap keys (requires `Eq` + `Hash`)

#### DebugValidationPolicy

**Guarantees**: Validation only in debug builds, zero overhead in release

```rust
pub struct DebugValidationPolicy<P: ValidationPolicy>(PhantomData<P>);

impl<P: ValidationPolicyReal> ValidationPolicyReal 
    for DebugValidationPolicy<P> 
{
    fn validate(value: &P::Value) -> Result<(), P::Error> {
        #[cfg(debug_assertions)]
        {
            P::validate(value)
        }
        #[cfg(not(debug_assertions))]
        {
            Ok(())
        }
    }
}
```

**Use Cases**:
- Performance-critical hot paths
- Code where correctness is guaranteed by construction
- After thorough testing with `StrictFinitePolicy`

### The GuaranteesFiniteValues Marker Trait

This is a **key architectural pattern** enabling conditional trait implementations:

```rust
pub trait GuaranteesFiniteValues {}

impl<T, const P: u32> GuaranteesFiniteValues 
    for StrictFinitePolicy<T, P> {}

// NOT implemented for DebugValidationPolicy (release builds don't validate)
```

**Enables**:

```rust
// Only validated types with finite guarantees can be HashMap keys
impl<K> Eq for RealValidated<K> 
where K::RealPolicy: GuaranteesFiniteValues {}

impl<K> Hash for RealValidated<K> 
where K::RealPolicy: GuaranteesFiniteValues {}
```

### Creating Custom Validation Policies

**Example**: Permissive policy allowing infinities

```rust
pub struct AllowInfinityPolicy<T, const P: u32>(PhantomData<T>);

impl<T: RawRealTrait, const P: u32> ValidationPolicyReal 
    for AllowInfinityPolicy<T, P> 
{
    const PRECISION: u32 = P;
    
    fn validate(value: &T) -> Result<(), ErrorsValidationRawReal<T>> {
        if value.is_nan() {
            return Err(ErrorsValidationRawReal::IsNaN { /* ... */ });
        }
        Ok(()) // Allow ±infinity
    }
}

// Define kernel
pub struct AllowInfinityKernel;
impl NumKernel for AllowInfinityKernel {
    type RawReal = f64;
    type RawComplex = Complex<f64>;
    type RealPolicy = AllowInfinityPolicy<f64, 53>;
    type ComplexPolicy = AllowInfinityPolicy<Complex<f64>, 53>;
    const PRECISION: u32 = 53;
}

// Use with validated wrapper
type RealAllowInf = RealValidated<AllowInfinityKernel>;
```

---

## Layer 3: Validated Wrappers

**Location**: `src/kernels/validated.rs`

### The Newtype Pattern

```rust
#[repr(transparent)]
pub struct RealValidated<K: NumKernel> {
    pub(crate) value: K::RawReal,
    pub(crate) _phantom: PhantomData<K>,
}
```

**Key Properties**:
- `#[repr(transparent)]`: Same memory layout as underlying type
- `pub(crate) value`: Internal access for crate, opaque to users
- `PhantomData<K>`: Zero-sized marker for kernel type

### Conditional Copy Implementation

**Pattern**: Automatically derive `Copy` when raw type is `Copy`

```rust
impl<K> Copy for RealValidated<K> 
where 
    K: NumKernel,
    K::RawReal: Copy 
{}
```

**Result**:
- `RealNative64StrictFinite` is `Copy` (wraps `f64`)
- `RealRugStrictFinite<100>` is `Clone` only (wraps `rug::Float`)

### Validation Pattern

**Standard flow**: Validate input → unchecked operation → validate output

```rust
impl<K: NumKernel> RealValidated<K> {
    pub fn sqrt(self) -> Result<Self, SqrtRealErrors<K::RawReal>> {
        // 1. Validate input
        K::RealPolicy::validate(&self.value)
            .map_err(|e| SqrtRealErrors::Input { 
                source: SqrtRealInputErrors::InvalidArgument { source: e } 
            })?;
        
        // Domain check
        if self.value < K::RawReal::zero() {
            return Err(SqrtRealErrors::Input { 
                source: SqrtRealInputErrors::NegativeValue { value: self.value } 
            });
        }
        
        // 2. Unchecked operation (fast)
        let result = self.value.unchecked_sqrt();
        
        // 3. Validate output
        K::RealPolicy::validate(&result)
            .map_err(|e| SqrtRealErrors::Output { source: e })?;
        
        Ok(RealValidated { 
            value: result, 
            _phantom: PhantomData 
        })
    }
}
```

### Panicking vs Fallible Methods

**Pattern**: Provide both variants for user convenience

```rust
impl<K: NumKernel> RealValidated<K> {
    /// Fallible version (returns Result)
    pub fn try_sqrt(self) -> Result<Self, SqrtRealErrors<K::RawReal>> {
        // ... implementation from above
    }
    
    /// Panicking version (unwraps or panics)
    pub fn sqrt(self) -> Self {
        self.try_sqrt().unwrap_or_else(|e| {
            panic!("sqrt failed: {}", e)
        })
    }
}
```

**Naming Convention**:
- `try_*`: Returns `Result`, never panics
- `*` (no prefix): Panics on error (for convenience/literals)

**Documentation**: Always clarify that panicking methods are **memory-safe** (not `unsafe`):

```rust
/// Computes the square root and returns the value directly.
///
/// This is a **panicking method** (not `unsafe`) that panics on invalid input.
/// For error handling, use [`try_sqrt`](Self::try_sqrt).
///
/// # Panics
///
/// Panics if the input is negative or if validation fails.
```

---

## Layer 4: High-Level Traits

**Location**: `src/lib.rs`

### The Trait Hierarchy

```rust
pub trait FpScalar: ScalarCore {
    type Kind: scalar_kind::Sealed;  // Real or Complex
    type RealType: RealScalar;       // Self for reals, component type for complex
    
    // Common operations for all scalars
    fn abs(self) -> Self::RealType;
    fn kernel_signum(self) -> Self;
    // ...
}

pub trait RealScalar: FpScalar<Kind = scalar_kind::Real> {
    // Real-specific operations
    fn sqrt(self) -> Self;
    fn ln(self) -> Self;
    // ...
}

pub trait ComplexScalar: FpScalar<Kind = scalar_kind::Complex> {
    // Complex-specific operations
    fn into_polar(self) -> (Self::RealType, Self::RealType);
    // ...
}
```

### Sealed Trait Pattern for Mutual Exclusion

**Problem**: A type should be **either** real **or** complex, never both.

**Solution**: Sealed trait with two implementors

```rust
mod scalar_kind {
    pub trait Sealed {}
    
    pub struct Real;
    pub struct Complex;
    
    impl Sealed for Real {}
    impl Sealed for Complex {}
}

pub trait FpScalar {
    type Kind: scalar_kind::Sealed;  // Can only be Real or Complex
}
```

**Result**: Type system enforces mutual exclusion at compile time.

### Writing Generic Algorithms

**Example**: Euclidean norm

```rust
pub fn euclidean_norm<T: RealScalar>(values: &[T]) -> T {
    values.iter()
        .map(|x| x.clone() * x.clone())
        .sum::<T>()
        .sqrt()
}

// Works for any RealScalar:
let norm_f64 = euclidean_norm(&[3.0, 4.0]);  // f64
let norm_validated = euclidean_norm(&[
    RealNative64StrictFinite::from_f64(3.0),
    RealNative64StrictFinite::from_f64(4.0),
]);
```

### The ScalarCore Trait Alias

**Purpose**: Reduce repetitive bounds

```rust
pub trait ScalarCore = Sized + Clone + Debug + Display + PartialEq 
    + Send + Sync + Zero + One + Serialize + DeserializeOwned + 'static;

// Instead of:
pub trait FpScalar: Sized + Clone + Debug + Display + PartialEq 
    + Send + Sync + Zero + One + Serialize + DeserializeOwned + 'static { }

// Write:
pub trait FpScalar: ScalarCore { }
```

**Benefits**:
- Single source of truth
- Easier maintenance
- Clearer intent

---

## Adding a New Backend

### Step-by-Step Guide

#### 1. Implement RawScalarTrait

```rust
use my_bignum::BigNum;

impl RawScalarTrait for BigNum {
    type ValidationErrors = BigNumValidationError;
    
    fn unchecked_add(self, other: Self) -> Self {
        self + other  // Direct delegation to library
    }
    
    fn unchecked_mul(self, other: Self) -> Self {
        self * other
    }
    
    // ... implement all required methods
}
```

#### 2. Implement RawRealTrait or RawComplexTrait

```rust
impl RawRealTrait for BigNum {
    fn unchecked_sqrt(self) -> Self {
        self.sqrt()  // Library's sqrt method
    }
    
    fn unchecked_ln(self) -> Self {
        self.ln()
    }
    
    // ... implement all required methods
}
```

#### 3. Create NumKernel Configuration

```rust
pub struct BigNumKernel<const PRECISION: u32>;

impl<const P: u32> NumKernel for BigNumKernel<P> {
    type RawReal = BigNum;
    type RawComplex = Complex<BigNum>;  // Or custom complex type
    type RealPolicy = StrictFinitePolicy<BigNum, P>;
    type ComplexPolicy = StrictFinitePolicy<Complex<BigNum>, P>;
    const PRECISION: u32 = P;
}
```

#### 4. Define Type Aliases

```rust
pub type RealBigNumStrictFinite<const P: u32> = RealValidated<BigNumKernel<P>>;
pub type ComplexBigNumStrictFinite<const P: u32> = ComplexValidated<BigNumKernel<P>>;
```

#### 5. Test Matrix

Create comprehensive tests:

```rust
#[cfg(test)]
mod tests {
    use super::*;
    
    type Real = RealBigNumStrictFinite<100>;
    
    #[test]
    fn test_basic_arithmetic() {
        let a = Real::from_f64(2.0);
        let b = Real::from_f64(3.0);
        assert_eq!(a + b, Real::from_f64(5.0));
    }
    
    #[test]
    fn test_sqrt() {
        let x = Real::from_f64(4.0);
        assert_eq!(x.sqrt(), Real::from_f64(2.0));
    }
    
    #[test]
    #[should_panic]
    fn test_sqrt_negative() {
        let x = Real::from_f64(-1.0);
        x.sqrt();  // Should panic
    }
    
    // ... more tests
}
```

### Backend Implementation Checklist

- [ ] `RawScalarTrait` implemented
- [ ] `RawRealTrait` or `RawComplexTrait` implemented
- [ ] `NumKernel` configuration created
- [ ] Type aliases defined
- [ ] Unit tests for all operations
- [ ] Edge case tests (NaN, infinity, subnormal)
- [ ] Performance benchmarks
- [ ] Documentation with examples
- [ ] Integration with existing traits (if needed)

---

## Adding Mathematical Functions

### Template for New Functions

#### 1. Define Trait in `src/functions/<category>.rs`

```rust
/// Trait for computing the hyperbolic arccosine of a number.
///
/// Provides both a fallible method ([`try_acosh`](ACosH::try_acosh)) that 
/// returns a [`Result`], and a panicking method ([`acosh`](ACosH::acosh)) 
/// that returns the value directly or panics on invalid input.
///
/// # Domain
///
/// - **Real**: x ≥ 1
/// - **Complex**: All finite values
pub trait ACosH: Sized {
    type Error: std::error::Error;
    
    /// Computes the hyperbolic arccosine and returns a [`Result`].
    fn try_acosh(self) -> Result<Self, Self::Error>;
    
    /// Computes the hyperbolic arccosine or panics on invalid input.
    ///
    /// # Panics
    ///
    /// Panics if the input is invalid (e.g., x < 1 for real numbers).
    fn acosh(self) -> Self;
}
```

#### 2. Define Error Types

```rust
/// Input errors for acosh computation on real numbers.
#[derive(Debug, Error)]
pub enum ACosHRealInputErrors<RawReal: RawRealTrait> {
    /// The argument is invalid (NaN, infinity, or subnormal).
    #[error("the argument is invalid")]
    InvalidArgument {
        #[source]
        source: RawReal::ValidationErrors,
    },
    
    /// The value is less than 1 (outside domain).
    #[error("acosh domain error: value {value} < 1")]
    ValueLessThanOne {
        value: RawReal,
        #[cfg(feature = "backtrace")]
        backtrace: Backtrace,
    },
}

/// Full error type combining input and output errors.
pub type ACosHRealErrors<RawReal> = FunctionErrors<
    ACosHRealInputErrors<RawReal>,
    ErrorsValidationRawReal<RawReal>
>;
```

#### 3. Implement for Raw Types

```rust
impl ACosH for f64 {
    type Error = ACosHRealErrors<Self>;
    
    fn try_acosh(self) -> Result<Self, Self::Error> {
        // Validate input
        Native64RawRealStrictFinitePolicy::validate(&self)
            .map_err(|e| FunctionErrors::Input {
                source: ACosHRealInputErrors::InvalidArgument { source: e }
            })?;
        
        // Domain check
        if self < 1.0 {
            return Err(FunctionErrors::Input {
                source: ACosHRealInputErrors::ValueLessThanOne {
                    value: self,
                    #[cfg(feature = "backtrace")]
                    backtrace: capture_backtrace(),
                }
            });
        }
        
        // Compute
        let result = self.acosh();  // f64's inherent method
        
        // Validate output
        Native64RawRealStrictFinitePolicy::validate(&result)
            .map_err(|e| FunctionErrors::Output { source: e })?;
        
        Ok(result)
    }
    
    fn acosh(self) -> Self {
        self.try_acosh().unwrap()
    }
}
```

#### 4. Implement for Complex (if applicable)

```rust
impl ACosH for Complex<f64> {
    type Error = ACosHComplexErrors<Self>;
    
    fn try_acosh(self) -> Result<Self, Self::Error> {
        // Complex acosh is defined for all finite values
        Native64RawComplexStrictFinitePolicy::validate(&self)
            .map_err(|e| FunctionErrors::Input {
                source: ACosHComplexInputErrors::InvalidArgument { source: e }
            })?;
        
        let result = self.acosh();  // Complex<f64>'s method
        
        Native64RawComplexStrictFinitePolicy::validate(&result)
            .map_err(|e| FunctionErrors::Output { source: e })?;
        
        Ok(result)
    }
    
    fn acosh(self) -> Self {
        self.try_acosh().unwrap()
    }
}
```

#### 5. Implement for Validated Wrappers (using duplicate macro)

```rust
#[duplicate_item(
    kernel_type;
    [Native64StrictFinite];
    [Native64StrictFiniteInDebug];
    // Add rug kernels if feature enabled
)]
impl ACosH for RealValidated<kernel_type> {
    type Error = ACosHRealErrors<kernel_type::RawReal>;
    
    fn try_acosh(self) -> Result<Self, Self::Error> {
        let result = self.value.try_acosh()?;
        Ok(RealValidated { 
            value: result, 
            _phantom: PhantomData 
        })
    }
    
    fn acosh(self) -> Self {
        self.try_acosh().unwrap()
    }
}
```

#### 6. Write Tests

```rust
#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_acosh_valid() {
        let x = RealNative64StrictFinite::from_f64(2.0);
        let result = x.try_acosh().unwrap();
        assert!((result.to_f64() - 1.3169578969248166).abs() < 1e-10);
    }
    
    #[test]
    fn test_acosh_domain_error() {
        let x = RealNative64StrictFinite::from_f64(0.5);
        assert!(x.try_acosh().is_err());
    }
    
    #[test]
    #[should_panic(expected = "domain error")]
    fn test_acosh_panic() {
        let x = RealNative64StrictFinite::from_f64(0.5);
        x.acosh();  // Should panic
    }
}
```

### Function Implementation Checklist

- [ ] Trait defined with clear documentation
- [ ] Domain documented (real and complex if applicable)
- [ ] Input error type created
- [ ] Output error type aliased (using `FunctionErrors`)
- [ ] Implemented for `f64`
- [ ] Implemented for `Complex<f64>` (if applicable)
- [ ] Implemented for `rug::Float` (if feature enabled)
- [ ] Implemented for validated wrappers (using macro)
- [ ] Unit tests for valid inputs
- [ ] Unit tests for domain errors
- [ ] Unit tests for validation errors
- [ ] Doctests in trait documentation
- [ ] Mathematical definition documented

---

## Error Handling Architecture

### Two-Phase Error Model

**Key Insight**: Errors occur at two distinct phases:

1. **Input Phase**: Argument validation and domain checking
2. **Output Phase**: Result validation (e.g., overflow detection)

### The FunctionErrors Struct

```rust
#[derive(Debug, Error)]
pub enum FunctionErrors<InputError, OutputError> {
    #[error("input error")]
    Input {
        #[source]
        source: InputError,
    },
    
    #[error("output error")]
    Output {
        #[source]
        source: OutputError,
    },
}
```

**Usage Pattern**:

```rust
pub type SqrtRealErrors<RawReal> = FunctionErrors<
    SqrtRealInputErrors<RawReal>,
    ErrorsValidationRawReal<RawReal>
>;
```

### Input Error Design

**Template**:

```rust
#[derive(Debug, Error)]
pub enum FunctionNameInputErrors<RawType: RawTrait> {
    #[error("the argument is invalid")]
    InvalidArgument {
        #[source]
        source: RawType::ValidationErrors,
    },
    
    #[error("specific domain error: {details}")]
    DomainError {
        details: String,
        value: RawType,
        #[cfg(feature = "backtrace")]
        backtrace: Backtrace,
    },
}
```

### Backtrace Handling

**Pattern**: Conditional backtrace capture

```rust
use crate::validation::capture_backtrace;

return Err(SomeError {
    value: x,
    #[cfg(feature = "backtrace")]
    backtrace: capture_backtrace(),
});
```

**Implementation** (in `validation.rs`):

```rust
#[inline]
pub fn capture_backtrace() -> Backtrace {
    if is_backtrace_enabled() {
        Backtrace::capture()
    } else {
        Backtrace::disabled()
    }
}

pub fn is_backtrace_enabled() -> bool {
    std::env::var("RUST_BACKTRACE")
        .map(|v| v == "1" || v == "full")
        .unwrap_or(false)
}
```

### Error Propagation Example

```rust
fn complex_computation<T: RealScalar>(x: T) -> Result<T, MyError> {
    // Input validation automatically done by try_sqrt
    let sqrt_x = x.try_sqrt()
        .map_err(|e| MyError::SqrtFailed { source: e })?;
    
    let ln_x = sqrt_x.try_ln()
        .map_err(|e| MyError::LnFailed { source: e })?;
    
    Ok(ln_x)
}
```

---

## Macro System

### The duplicate_item! Macro

**Purpose**: Reduce boilerplate for repetitive implementations

**Location**: Used throughout codebase via `duplicate` crate

### Common Pattern: Trait Implementation for Multiple Kernels

```rust
#[duplicate_item(
    kernel_type;
    [Native64StrictFinite];
    [Native64StrictFiniteInDebug];
)]
impl SomeTrait for RealValidated<kernel_type> {
    // Implementation identical for both kernels
    fn some_method(&self) -> SomeType {
        // ...
    }
}
```

**Expands to**:

```rust
impl SomeTrait for RealValidated<Native64StrictFinite> {
    fn some_method(&self) -> SomeType { /* ... */ }
}

impl SomeTrait for RealValidated<Native64StrictFiniteInDebug> {
    fn some_method(&self) -> SomeType { /* ... */ }
}
```

### Pattern: Function Trait Definition

```rust
#[duplicate::duplicate_item(
    T      try_func   func   trait_doc;
    [Sin]  [try_sin]  [sin]  ["Computes the sine"];
    [Cos]  [try_cos]  [cos]  ["Computes the cosine"];
    [Tan]  [try_tan]  [tan]  ["Computes the tangent"];
)]
#[doc = trait_doc]
pub trait T: Sized {
    type Error: std::error::Error;
    fn try_func(self) -> Result<Self, Self::Error>;
    fn func(self) -> Self;
}
```

### The define_validated_struct! Macro

**Location**: `src/kernels/validated.rs`

**Purpose**: Generate entire validated wrapper with all trait implementations

**Warning**: This macro is **monolithic** (200+ lines) and could be refactored.

**Current Usage**:

```rust
define_validated_struct!(
    RealValidated,      // Struct name
    RealPolicy,         // Policy type
    RawReal             // Raw type
);
```

**Generates**:
- Struct definition
- Constructors (`new`, `try_new`)
- Arithmetic operators (4 variants each: `T op T`, `&T op T`, `T op &T`, `&T op &T`)
- Standard traits (`Zero`, `One`, `Sum`, etc.)
- Conversion methods
- Debug/Display implementations

### Refactoring Proposal (Future Work)

Break into composable macros:

```rust
// Proposed structure
define_validated_struct! { /* struct definition only */ }
impl_validated_constructors! { /* new, try_new */ }
impl_validated_arithmetic! { /* Add, Sub, Mul, Div */ }
impl_validated_traits! { /* Zero, One, Sum, etc. */ }
```

---

## Performance Considerations

### Zero-Cost Abstractions

**Key mechanisms**:

1. **`#[inline(always)]`** on validated wrapper methods
2. **`#[repr(transparent)]`** for newtype wrappers
3. **Const generics** for compile-time precision
4. **Conditional compilation** for debug-only validation

### Validation Overhead

**StrictFinitePolicy in Release**:
- Overhead: ~5-15% compared to raw `f64`
- Benefit: NaN propagation prevented, type safety guaranteed

**DebugValidationPolicy in Release**:
- Overhead: **0%** (validation compiled out)
- Benefit: Full validation during development

### Optimization: MPFR Constants (rug backend)

**Pattern**: Use precomputed MPFR constants

```rust
// SLOW (recalculates π every time)
fn slow_pi(precision: u32) -> rug::Float {
    rug::Float::with_val(precision, -1).acos()  // ~50-100 µs
}

// FAST (uses MPFR constant)
fn fast_pi(precision: u32) -> rug::Float {
    rug::Float::with_val(precision, rug::float::Constant::Pi)  // ~5-10 µs
}
```

**Available Constants**:
- `Pi`
- `Log2`
- `Euler`
- `Catalan`

### Reference vs Value Semantics

**Guideline**: For rug types, prefer references to avoid clones

```rust
// GOOD: Reference-based
fn compute_with_refs(a: &RealRugStrictFinite<100>, b: &RealRugStrictFinite<100>) {
    let result = a + b;  // Only one allocation for result
}

// LESS EFFICIENT: Value-based
fn compute_with_values(a: RealRugStrictFinite<100>, b: RealRugStrictFinite<100>) {
    let result = a + b;  // Two moves, same allocation
}
```

**All arithmetic ops support 4 variants**:
- `T op T`
- `&T op T`
- `T op &T`
- `&T op &T`

---

## Design Patterns Reference

### 1. Newtype Pattern with Phantom Data

```rust
#[repr(transparent)]
pub struct Validated<K: Kernel> {
    value: K::Raw,
    _phantom: PhantomData<K>,
}
```

**Benefits**:
- Zero runtime cost
- Type-level configuration (K)
- Memory layout identical to raw type

### 2. Marker Trait for Conditional Implementation

```rust
pub trait GuaranteesFiniteValues {}

impl<K> Eq for Validated<K> 
where K::Policy: GuaranteesFiniteValues {}
```

**Use Case**: Only policies that guarantee finite values can implement `Eq`/`Hash`.

### 3. Sealed Trait for Closed Set

```rust
mod sealed {
    pub trait Sealed {}
    pub struct TypeA;
    pub struct TypeB;
    impl Sealed for TypeA {}
    impl Sealed for TypeB {}
}

pub trait PublicTrait {
    type Kind: sealed::Sealed;  // Can only be TypeA or TypeB
}
```

**Use Case**: `FpScalar::Kind` can only be `Real` or `Complex`.

### 4. Const Generic Precision

```rust
pub struct RealRug<const PRECISION: u32>;

// Compile-time error if mismatched
fn compute() {
    let a: RealRug<100> = /* ... */;
    let b: RealRug<200> = /* ... */;
    let c = a + b;  // ERROR: type mismatch
}
```

### 5. Trait Alias for Bounds Reduction

```rust
pub trait ScalarCore = Sized + Clone + Debug + /* ... */;

// Instead of repeating all bounds
pub trait FpScalar: ScalarCore { /* ... */ }
```

### 6. Panicking + Fallible Pair

```rust
pub trait Sqrt {
    fn try_sqrt(self) -> Result<Self, Error>;
    fn sqrt(self) -> Self { self.try_sqrt().unwrap() }
}
```

**Convention**: `try_*` returns `Result`, `*` panics (but is memory-safe).

### 7. Progressive Disclosure Documentation

```rust
/// Short summary (3-5 lines).
///
/// <details>
/// <summary>Detailed Behavior and Edge Cases</summary>
///
/// [100+ lines of comprehensive documentation]
///
/// </details>
```

**Use Case**: Complex methods like `truncate_to_usize`.

---

## Conclusion

This architecture guide provides a complete reference for understanding and contributing to `num-valid`. The 4-layer design is the core innovation that enables:

- **Type safety** without runtime overhead
- **Backend flexibility** (f64, rug, custom types)
- **Validation configurability** (strict, debug-only, custom)
- **Generic programming** via high-level traits

When in doubt:
1. Check existing implementations for patterns
2. Refer to this guide for architectural decisions
3. Ask maintainers for clarification

**Happy contributing!** 🦀

---

**Document Version**: 1.0  
**Compatibility**: num-valid 0.2.5+  
**Feedback**: Please open an issue for corrections or improvements
