Struct TwiceLock

Source
pub struct TwiceLock<A, B> { /* private fields */ }

Implementations§

Source§

impl<A, B> TwiceLock<A, B>

Source

pub const fn new(value: A) -> TwiceLock<A, B>

Creates a new empty cell.

Source

pub fn get(&self) -> Option<&B>

Gets the reference to the underlying value.

Returns None if the cell is unset, or being set. This method never blocks.

Source

pub fn get_mut(&mut self) -> Option<&mut B>

Gets the mutable reference to the underlying value.

Returns None if the cell is unset. This method never blocks.

Source

pub fn get_either_mut(&mut self) -> Either<&mut A, &mut B>

Gets the mutable reference to either underlying value.

Source

pub fn set(&self, value: B) -> Result<(), B>
where A: RefUnwindSafe,

Sets the contents of this cell to value.

May block if another thread is currently attempting to initialize the cell. The cell is guaranteed to contain a value when set returns, though not necessarily the one provided.

§Errors

Returns Ok(()) if the cell’s value was set by this call.

§Examples
use twice_cell::TwiceLock;

static CELL: TwiceLock<&str, i32> = TwiceLock::new("initial value");

fn main() {
    assert!(CELL.get().is_none());

    std::thread::spawn(|| {
        assert_eq!(CELL.set(92), Ok(()));
    }).join().unwrap();

    assert_eq!(CELL.set(62), Err(62));
    assert_eq!(CELL.get(), Some(&92));
}
Source

pub fn try_insert(&self, value: B) -> Result<&B, (&B, B)>
where A: RefUnwindSafe,

Sets the contents of this cell to value if the cell was empty, then returns a reference to it.

May block if another thread is currently attempting to initialize the cell. The cell is guaranteed to contain a value when set returns, though not necessarily the one provided.

§Errors

Returns Ok(&value) if the cell was empty and Err(&current_value, value) if it was full.

§Examples

use twice_cell::TwiceLock;

static CELL: TwiceLock<&'static str, i32> = TwiceLock::new("initial value");

fn main() {
    assert!(CELL.get().is_none());

    std::thread::spawn(|| {
        assert_eq!(CELL.try_insert(92), Ok(&92));
    }).join().unwrap();

    assert_eq!(CELL.try_insert(62), Err((&92, 62)));
    assert_eq!(CELL.get(), Some(&92));
}
Source

pub fn get_or_init<F>(&self, f: F) -> &B
where F: UnwindSafe + FnOnce(&A) -> B, A: RefUnwindSafe,

Gets the contents of the cell, initializing it with f if the cell was empty.

Many threads may call get_or_init concurrently with different initializing functions, but it is guaranteed that only one function will be executed.

§Panics

If f panics, the panic is propagated to the caller, and the cell remains uninitialized.

It is an error to reentrantly initialize the cell from f. The exact outcome is unspecified. Current implementation deadlocks, but this may be changed to a panic in the future.

§Examples
use twice_cell::TwiceLock;

let cell = TwiceLock::new("initial value");
let value = cell.get_or_init(|s| s.len());
assert_eq!(value, &13);
let value = cell.get_or_init(|_| unreachable!());
assert_eq!(value, &13);
Source

pub fn get_mut_or_init<F>(&mut self, f: F) -> &mut B
where F: UnwindSafe + FnOnce(&A) -> B, A: RefUnwindSafe,

Gets the mutable reference of the contents of the cell, initializing it with f if the cell was empty.

Many threads may call get_mut_or_init concurrently with different initializing functions, but it is guaranteed that only one function will be executed.

§Panics

If f panics, the panic is propagated to the caller, and the cell remains uninitialized.

§Examples
use twice_cell::TwiceLock;

let mut cell = TwiceLock::new("initial value");
let value = cell.get_mut_or_init(|s| s.len());
assert_eq!(*value, 13);

*value += 2;
assert_eq!(*value, 15);

let value = cell.get_mut_or_init(|_| unreachable!());
assert_eq!(*value, 15);
Source

pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&B, E>
where F: UnwindSafe + FnOnce(&A) -> Result<B, E>, E: Send + 'static, A: RefUnwindSafe,

Gets the contents of the cell, initializing it with f if the cell was empty.

§Panics

If f panics, the panic is propagated to the caller, and the cell remains uninitialized.

§Errors

If the cell was empty and f failed, an error is returned.

It is an error to reentrantly initialize the cell from f. The exact outcome is unspecified. Current implementation deadlocks, but this may be changed to a panic in the future.

§Examples
use twice_cell::TwiceLock;

let cell = TwiceLock::new("initial value");

assert_eq!(cell.get_or_try_init(|_| Err(())), Err(()));
assert!(cell.get().is_none());

let value = cell.get_or_try_init(|s| -> Result<usize, ()> {
    Ok(s.len())
});
assert_eq!(value, Ok(&13));
assert_eq!(cell.get(), Some(&13))
Source

pub fn get_mut_or_try_init<F, E>(&mut self, f: F) -> Result<&mut B, E>
where F: UnwindSafe + FnOnce(&A) -> Result<B, E>, E: Send + 'static, A: RefUnwindSafe,

Gets the mutable reference of the contents of the cell, initializing it with f if the cell was empty.

§Panics

If f panics, the panic is propagated to the caller, and the cell remains uninitialized.

§Errors

If the cell was empty and f failed, an error is returned.

§Examples
use twice_cell::TwiceLock;

let mut cell: TwiceLock<&'static str, usize> = TwiceLock::new("not a number");

// Failed initializers do not change the value
assert!(cell.get_mut_or_try_init(|s| s.parse()).is_err());
assert!(cell.get().is_none());

let value = cell.get_mut_or_try_init(|_| "1234".parse());
assert_eq!(value, Ok(&mut 1234));

*value.unwrap() += 2;
assert_eq!(cell.get(), Some(&1236));
Source

pub fn replace(&mut self, value: A) -> Either<A, B>

Takes the value out of this TwiceLock, moving it back to an unset state.

Returns Either::Left if the TwiceLock hasn’t been set.

Safety is guaranteed by requiring a mutable reference.

§Examples
use twice_cell::TwiceLock;
use either::Either;

let mut cell: TwiceLock<i32, String> = TwiceLock::new(123);
assert_eq!(cell.replace(456), Either::Left(123));

let mut cell = TwiceLock::new(123);
cell.set("hello").unwrap();

assert_eq!(cell.replace(456), Either::Right("hello"));
assert_eq!(cell.get(), None);

Trait Implementations§

Source§

impl<A: Debug, B: Debug> Debug for TwiceLock<A, B>

Source§

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

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

impl<A: Default, B> Default for TwiceLock<A, B>

Source§

fn default() -> Self

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

impl<A, B> Drop for TwiceLock<A, B>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl<A, B> From<B> for TwiceLock<A, B>

Source§

fn from(value: B) -> Self

Create a new cell with its contents set to value.

§Example
use std::sync::OnceLock;

let a = OnceLock::from(3);
let b = OnceLock::new();
b.set(3)?;
assert_eq!(a, b);
Ok(())
Source§

impl<A: Send, B: Send> Send for TwiceLock<A, B>

Safety: The UnsafeCell exists to enforce borrow checking via the Once primitive instead of the compiler; that is to say, we can override UnsafeCell’s !Send-ness if both A and B are Send.

Source§

impl<A: Sync + Send, B: Sync + Send> Sync for TwiceLock<A, B>

Safety: The same is true for Sync, except that we also need A and B to impl Send for the same reason there’s Send bounds on the OnceLock implementation:

Why do we need T: Send? Thread A creates a OnceLock and shares it with scoped thread B, which fills the cell, which is then destroyed by A. That is, destructor observes a sent value.

Auto Trait Implementations§

§

impl<A, B> !Freeze for TwiceLock<A, B>

§

impl<A, B> !RefUnwindSafe for TwiceLock<A, B>

§

impl<A, B> Unpin for TwiceLock<A, B>
where A: Unpin, B: Unpin,

§

impl<A, B> UnwindSafe for TwiceLock<A, B>
where A: UnwindSafe, B: UnwindSafe,

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<!> for T

Source§

fn from(t: !) -> T

Converts to this type from the input type.
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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
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.