Skip to main content

Once

Struct Once 

Source
pub struct Once { /* private fields */ }
Expand description

A synchronization primitive which can be used to run a one-time async initialization.

Unlike std::sync::Once, this type never blocks a thread. The provided closure must produce a future and the future is awaited inside the primitive. Coordination happens with asynchronous Semaphore, which keeps the implementation runtime-agnostic.

This type also intentionally omits “poisoning” semantics. If an initialization future is cancelled or panics, the attempt is abandoned and other tasks may retry the operation. Encode partial-initialization detection in the future itself (e.g. return a Result) when needed.

See the module level documentation for additional context.

§Examples

use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;

use asyncband::once::Once;

static ONCE: Once = Once::new();
static COUNTER: AtomicUsize = AtomicUsize::new(0);

let handle1 = tokio::spawn(async {
    ONCE.call_once(async || {
        COUNTER.fetch_add(1, Ordering::SeqCst);
    })
    .await;
});

let handle2 = tokio::spawn(async {
    ONCE.call_once(async || {
        COUNTER.fetch_add(1, Ordering::SeqCst);
    })
    .await;
});

handle1.await.unwrap();
handle2.await.unwrap();

// The counter is incremented only once, even though two tasks called `call_once`.
assert_eq!(COUNTER.load(Ordering::SeqCst), 1);

Implementations§

Source§

impl Once

Source

pub const fn new() -> Self

Creates a new Once instance.

§Examples
use asyncband::once::Once;

static ONCE: Once = Once::new();
Source

pub fn is_completed(&self) -> bool

Returns true if some call_once has completed successfully.

§Examples
use asyncband::once::Once;

static ONCE: Once = Once::new();

assert!(!ONCE.is_completed());

ONCE.call_once(async || {}).await;

assert!(ONCE.is_completed());
Source

pub async fn call_once<F>(&self, f: F)
where F: AsyncFnOnce(),

Calls the given async closure if this is the first time call_once has been called on this Once instance.

If another task is currently running the closure, this call will wait for that task to complete.

If the provided operation is cancelled, the initialization attempt is cancelled. If there are other tasks waiting, one of them will start another attempt.

Calling call_once recursively on the same Once from within the closure will deadlock, because the closure holds the semaphore permit while trying to acquire it again.

§Examples
use asyncband::once::Once;

static ONCE: Once = Once::new();

ONCE.call_once(async || {
    println!("Do some one-time async thing.");
})
.await;
Source

pub async fn wait(&self)

Waits asynchronously until some call_once has completed successfully.

§Examples
use asyncband::once::Once;

static ONCE: Once = Once::new();

let handle = tokio::spawn(async {
    ONCE.wait().await;
});

ONCE.call_once(async || {
    println!("initialized");
})
.await;

handle.await.unwrap();

Trait Implementations§

Source§

impl Debug for Once

Source§

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

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

impl Default for Once

Source§

fn default() -> Self

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

Auto Trait Implementations§

§

impl !Freeze for Once

§

impl RefUnwindSafe for Once

§

impl Send for Once

§

impl Sync for Once

§

impl Unpin for Once

§

impl UnsafeUnpin for Once

§

impl UnwindSafe for Once

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.