pub struct InitOnceArc<T> { /* private fields */ }Expand description
A thread-safe container that provides synchronized one-time initialization
of an Arc<T> via a closure.
This builds on OnceArc by adding init and try_init methods.
When multiple threads call init concurrently on an empty cell, exactly
one thread will execute the closure — the others block on an internal
mutex and then observe the already-initialized value. If the closure
completes without panicking, its return value becomes the stored Arc<T>.
If it panics, the mutex is poisoned and subsequent calls return an error.
Once set, all reads go through the fast path: a single atomic load,
identical to OnceArc::get — no mutex, no CAS.
§Examples
use std::sync::Arc;
use std::sync::atomic::Ordering;
use once_arc::InitOnceArc;
let cell: InitOnceArc<String> = InitOnceArc::new();
// First call runs the initializer
assert_eq!(cell.init(|| "hello".to_string().into()).unwrap(), true);
// Subsequent calls return Ok(false) without running the closure
assert_eq!(cell.init(|| "world".to_string().into()).unwrap(), false);
assert_eq!(cell.get(Ordering::Acquire).unwrap(), "hello");Implementations§
Source§impl<T> InitOnceArc<T>
impl<T> InitOnceArc<T>
Sourcepub const fn new() -> Self
pub const fn new() -> Self
Creates a new empty InitOnceArc.
§Examples
use once_arc::InitOnceArc;
let cell: InitOnceArc<i32> = InitOnceArc::new();Sourcepub fn store(
&self,
value: Arc<T>,
) -> Result<(), Result<Arc<T>, PoisonError<()>>>
pub fn store( &self, value: Arc<T>, ) -> Result<(), Result<Arc<T>, PoisonError<()>>>
Attempts to store the value. Returns Ok(()) on success,
Err(Ok(value)) if a value was already stored, or Err(Err(_)) if the
mutex is poisoned.
If an init attempt is already ongoing, this store will wait for it,
before trying to store.
§Examples
use std::sync::Arc;
use once_arc::InitOnceArc;
let cell: InitOnceArc<i32> = InitOnceArc::new();
assert!(cell.store(Arc::new(42)).is_ok());
let err = cell.store(Arc::new(99)).unwrap_err().unwrap();
assert_eq!(*err, 99);Sourcepub fn init(&self, f: impl FnOnce() -> Arc<T>) -> Result<bool, PoisonError<()>>
pub fn init(&self, f: impl FnOnce() -> Arc<T>) -> Result<bool, PoisonError<()>>
Initializes the cell with the value produced by f, if not yet set.
Returns Ok(true) if the value was initialized, Ok(false) if it was
already set, or Err if the mutex is poisoned.
Only one initializer will be run per InitOnceArc and if the initializer doesn’t panic,
its return value is guaranteed to become the stored Arc<T>.
If it panics, the mutex is poisoned and subsequent calls will return an error.
While the initializer is running all readers will see the cell as empty.
§Examples
use std::sync::Arc;
use once_arc::InitOnceArc;
let cell: InitOnceArc<i32> = InitOnceArc::new();
assert_eq!(cell.init(|| Arc::new(42)).unwrap(), true);
assert_eq!(cell.init(|| Arc::new(99)).unwrap(), false); // already initializedSourcepub fn try_init<E>(
&self,
f: impl FnOnce() -> Result<Arc<T>, E>,
) -> Result<bool, Result<E, PoisonError<()>>>
pub fn try_init<E>( &self, f: impl FnOnce() -> Result<Arc<T>, E>, ) -> Result<bool, Result<E, PoisonError<()>>>
Initializes the cell with the value produced by f, if not yet set.
If f returns Err, the cell remains empty and the error is propagated.
Returns Ok(true) if initialized, Ok(false) if already set,
Err(Ok(e)) if f failed, or Err(Err(_)) if the mutex is poisoned.
Only one initializer will be run per InitOnceArc at a time and if the initializer doesn’t panic or return an error,
its return value is guaranteed to become the stored Arc<T>.
If it panics, the mutex is poisoned and subsequent calls will return an error.
While the initializer is running all readers will see the cell as empty.
§Examples
use std::sync::Arc;
use once_arc::InitOnceArc;
let cell: InitOnceArc<i32> = InitOnceArc::new();
let err = cell.try_init(|| Err("oops")).unwrap_err().unwrap();
assert_eq!(err, "oops");
assert_eq!(cell.try_init(|| Ok::<_, &str>(Arc::new(42))).unwrap(), true);
assert_eq!(cell.try_init(|| Ok::<_, &str>(Arc::new(99))).unwrap(), false);Sourcepub fn get(&self, ordering: Ordering) -> Option<&T>
pub fn get(&self, ordering: Ordering) -> Option<&T>
Returns a reference to the stored value, or None if not yet initialized.
This is the fast path — a single atomic load, no mutex.
§Examples
use std::sync::Arc;
use std::sync::atomic::Ordering;
use once_arc::InitOnceArc;
let cell: InitOnceArc<i32> = InitOnceArc::new();
assert!(cell.get(Ordering::Acquire).is_none());
cell.init(|| Arc::new(42)).unwrap();
assert_eq!(cell.get(Ordering::Acquire), Some(&42));Sourcepub fn load(&self, ordering: Ordering) -> Option<Arc<T>>
pub fn load(&self, ordering: Ordering) -> Option<Arc<T>>
Loads the stored value as a cloned Arc<T>, or None if not yet
initialized.
§Examples
use std::sync::Arc;
use std::sync::atomic::Ordering;
use once_arc::InitOnceArc;
let cell: InitOnceArc<i32> = InitOnceArc::new();
cell.init(|| Arc::new(42)).unwrap();
let arc = cell.load(Ordering::Acquire).unwrap();
assert_eq!(*arc, 42);Sourcepub fn is_set(&self, ordering: Ordering) -> bool
pub fn is_set(&self, ordering: Ordering) -> bool
Returns true if the value has been initialized.
§Examples
use std::sync::Arc;
use std::sync::atomic::Ordering;
use once_arc::InitOnceArc;
let cell: InitOnceArc<i32> = InitOnceArc::new();
assert!(!cell.is_set(Ordering::Relaxed));
cell.init(|| Arc::new(1)).unwrap();
assert!(cell.is_set(Ordering::Relaxed));Sourcepub fn into_inner(self) -> Option<Arc<T>>
pub fn into_inner(self) -> Option<Arc<T>>
Consumes self and returns the stored Arc<T>, if any.
§Examples
use std::sync::Arc;
use once_arc::InitOnceArc;
let cell: InitOnceArc<i32> = InitOnceArc::new();
cell.init(|| Arc::new(42)).unwrap();
let arc = cell.into_inner().unwrap();
assert_eq!(*arc, 42);Sourcepub fn get_mut(&mut self) -> Option<&mut T>
pub fn get_mut(&mut self) -> Option<&mut T>
Returns a mutable reference to the stored value, or None if not yet set.
Since this requires &mut self, no atomic operations or mutex are needed.
§Examples
use std::sync::Arc;
use std::sync::atomic::Ordering;
use once_arc::InitOnceArc;
let mut cell: InitOnceArc<i32> = InitOnceArc::new();
cell.init(|| Arc::new(10)).unwrap();
*cell.get_mut().unwrap() = 20;
assert_eq!(cell.get(Ordering::Acquire), Some(&20));