Skip to main content

InitOnceArc

Struct InitOnceArc 

Source
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>

Source

pub const fn new() -> Self

Creates a new empty InitOnceArc.

§Examples
use once_arc::InitOnceArc;

let cell: InitOnceArc<i32> = InitOnceArc::new();
Source

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);
Source

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 initialized
Source

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);
Source

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));
Source

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);
Source

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));
Source

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);
Source

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));

Trait Implementations§

Source§

impl<T: Debug> Debug for InitOnceArc<T>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T> Default for InitOnceArc<T>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<T: Send + Sync> Send for InitOnceArc<T>

Source§

impl<T: Send + Sync> Sync for InitOnceArc<T>

Auto Trait Implementations§

§

impl<T> !Freeze for InitOnceArc<T>

§

impl<T> RefUnwindSafe for InitOnceArc<T>

§

impl<T> Unpin for InitOnceArc<T>

§

impl<T> UnsafeUnpin for InitOnceArc<T>

§

impl<T> UnwindSafe for InitOnceArc<T>
where T: RefUnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.