tensor4all_core/
global_default.rs

1//! Global default values with atomic access.
2//!
3//! This module provides a type-safe way to manage global default values
4//! that can be accessed and modified atomically.
5
6use std::sync::atomic::{AtomicU64, Ordering};
7use thiserror::Error;
8
9/// Error for invalid tolerance values.
10#[derive(Debug, Error, Clone, Copy)]
11#[error("Invalid rtol value: {0}. rtol must be finite and non-negative.")]
12pub struct InvalidRtolError(pub f64);
13
14/// A global default f64 value with atomic access.
15///
16/// This type provides thread-safe access to a global default value,
17/// typically used for tolerance parameters like `rtol`.
18///
19/// # Example
20///
21/// ```
22/// use tensor4all_core::GlobalDefault;
23///
24/// static MY_DEFAULT: GlobalDefault = GlobalDefault::new(1e-12);
25///
26/// // Get the default value
27/// let rtol = MY_DEFAULT.get();
28///
29/// // Set a new default value
30/// MY_DEFAULT.set(1e-10).unwrap();
31/// ```
32pub struct GlobalDefault {
33    value: AtomicU64,
34}
35
36impl GlobalDefault {
37    /// Create a new global default with the given initial value.
38    ///
39    /// This is a const fn, so it can be used in static declarations.
40    #[must_use]
41    pub const fn new(initial: f64) -> Self {
42        Self {
43            value: AtomicU64::new(initial.to_bits()),
44        }
45    }
46
47    /// Get the current default value.
48    #[must_use]
49    pub fn get(&self) -> f64 {
50        f64::from_bits(self.value.load(Ordering::Relaxed))
51    }
52
53    /// Set a new default value.
54    ///
55    /// # Errors
56    ///
57    /// Returns `InvalidRtolError` if the value is not finite or is negative.
58    pub fn set(&self, value: f64) -> Result<(), InvalidRtolError> {
59        if !value.is_finite() || value < 0.0 {
60            return Err(InvalidRtolError(value));
61        }
62        self.value.store(value.to_bits(), Ordering::Relaxed);
63        Ok(())
64    }
65
66    /// Set a new default value without validation.
67    ///
68    /// # Safety
69    ///
70    /// The caller must ensure the value is valid (finite and non-negative).
71    pub fn set_unchecked(&self, value: f64) {
72        self.value.store(value.to_bits(), Ordering::Relaxed);
73    }
74}
75
76// Safety: AtomicU64 is Sync, so GlobalDefault is too
77unsafe impl Sync for GlobalDefault {}
78
79#[cfg(test)]
80mod tests;