WriteOnce

Struct WriteOnce 

Source
pub struct WriteOnce<T> {
    value: UnsafeCell<MaybeUninit<T>>,
    state: AtomicU8,
}
Expand description

A thread-safe, wait-free, write-once cell that allows a value to be set exactly once.

WriteOnce provides a way to initialize a value exactly once in a thread-safe manner. Once a value is set, it cannot be changed. This is useful in scenarios where you need to ensure that a value is initialized exactly once, even in the presence of concurrent access.

WriteOnce is similar to std::sync::OnceLock, but with a key difference: it takes a value directly rather than a closure that initializes the value. In other words, we assume an optimistic concurrency model, contrary to OnceLock’s pessimistic model.

This concurrency model allows WriteOnce to be fully wait-free. This also implies that, whereas OnceLock guarantees that the closure is called at most once, WriteOnce guarantees that the value is set at most once.

§Thread Safety

WriteOnce is designed to be thread-safe and wait-free, allowing concurrent attempts to set the value from multiple threads. Only the first successful call to set or try_set will initialize the value; subsequent attempts will either panic (with set) or return an error (with try_set).

§Memory Safety

WriteOnce uses atomic operations to ensure memory safety and proper synchronization between threads. It guarantees that:

  • A value can be set exactly once
  • Once set, the value can be safely read from any thread
  • The value is properly dropped when the WriteOnce is dropped

§Examples

use once::write_once::WriteOnce;

// Create a new WriteOnce with no value
let cell = WriteOnce::<String>::none();

// Set the value
cell.set("Hello, world!".to_string());

// Get the value
assert_eq!(cell.get(), Some(&"Hello, world!".to_string()));

// Attempting to set the value again will panic
// cell.set("Another value".to_string()); // This would panic

// Using try_set instead returns an error
let result = cell.try_set("Another value".to_string());
assert!(result.is_err());
if let Err(value) = result {
    assert_eq!(value, "Another value".to_string());
}

Fields§

§value: UnsafeCell<MaybeUninit<T>>§state: AtomicU8

Implementations§

Source§

impl<T> WriteOnce<T>

Source

pub fn none() -> Self

Creates a new WriteOnce with no value.

This initializes the cell in an empty state. The value can be set later using set or try_set.

§Examples
use once::write_once::WriteOnce;

let cell = WriteOnce::<i32>::none();
assert_eq!(cell.get(), None);
assert!(!cell.is_set());
Source

pub fn new(value: T) -> Self

Creates a new WriteOnce with a value.

§Examples
use once::write_once::WriteOnce;

let cell = WriteOnce::new(2);
assert_eq!(cell.get(), Some(&2));
assert!(cell.is_set());
Source

pub fn set(&self, value: T)

Sets the value of the WriteOnce.

This method sets the value of the cell if it hasn’t been set yet. If the cell already has a value, this method will panic.

§Panics

Panics if the cell already has a value.

§Examples
use once::write_once::WriteOnce;

let cell = WriteOnce::<i32>::none();
cell.set(42);
assert_eq!(cell.get(), Some(&42));

// Uncommenting the following line would cause a panic:
// cell.set(100);
Source

pub fn try_set(&self, value: T) -> Result<(), T>

Attempts to set the value of the WriteOnce.

This method tries to set the value of the cell if it hasn’t been set yet. If the cell already has a value, this method will return an error containing the value that was attempted to be set.

§Returns
  • Ok(()) if the value was successfully set
  • Err(value) if the cell already had a value, returning the value that was attempted to be set
§Examples
use once::write_once::WriteOnce;

let cell = WriteOnce::<String>::none();

// First attempt succeeds
let result = cell.try_set("Hello".to_string());
assert!(result.is_ok());
assert_eq!(cell.get(), Some(&"Hello".to_string()));

// Second attempt fails
let result = cell.try_set("World".to_string());
assert!(result.is_err());
if let Err(value) = result {
    assert_eq!(value, "World".to_string());
}

// The value remains unchanged
assert_eq!(cell.get(), Some(&"Hello".to_string()));
Source

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

Gets the value of the WriteOnce.

Returns Some(&T) if the cell has a value, or None if it doesn’t.

§Examples
use once::write_once::WriteOnce;

let cell = WriteOnce::<i32>::none();
assert_eq!(cell.get(), None);

cell.set(42);
assert_eq!(cell.get(), Some(&42));
Source

pub unsafe fn get_unchecked(&self) -> &T

§Safety

This method is unsafe because it returns a reference to the value without checking if the value is initialized. The caller must ensure that the value is initialized before calling this method.

Source

pub fn is_set(&self) -> bool

Checks if the WriteOnce has a value.

Returns true if the cell has a value, or false if it doesn’t.

This method only returns true if the value has been set and is ready to be read. In particular, it will return false if the value is currently being set by another thread. This may be relevant if the value is a large object and moving it in memory is expensive.

§Examples
use once::write_once::WriteOnce;

let cell = WriteOnce::<i32>::none();
assert!(!cell.is_set());

cell.set(42);
assert!(cell.is_set());
Source

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

Gets a mutable reference to the value of the WriteOnce.

Returns Some(&mut T) if the cell has a value, or None if it doesn’t. This method requires a mutable reference to the WriteOnce, which ensures that no other thread is accessing the value.

§Examples
use once::write_once::WriteOnce;

let mut cell = WriteOnce::<String>::none();
assert_eq!(cell.get_mut(), None);

cell.set("Hello".to_string());

// Modify the value through a mutable reference
if let Some(value) = cell.get_mut() {
    value.push_str(", world!");
}

assert_eq!(cell.get(), Some(&"Hello, world!".to_string()));

Trait Implementations§

Source§

impl<T: Clone> Clone for WriteOnce<T>

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T: Debug> Debug for WriteOnce<T>

Source§

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

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

impl<T> Drop for WriteOnce<T>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl<T: Hash> Hash for WriteOnce<T>

Source§

fn hash<H: Hasher>(&self, state: &mut H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl<T: Ord> Ord for WriteOnce<T>

Source§

fn cmp(&self, other: &Self) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · Source§

fn max(self, other: Self) -> Self
where Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · Source§

fn min(self, other: Self) -> Self
where Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · Source§

fn clamp(self, min: Self, max: Self) -> Self
where Self: Sized,

Restrict a value to a certain interval. Read more
Source§

impl<T: PartialEq> PartialEq for WriteOnce<T>

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<T: PartialOrd> PartialOrd for WriteOnce<T>

Source§

fn partial_cmp(&self, other: &Self) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · Source§

fn lt(&self, other: &Rhs) -> bool

Tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · Source§

fn le(&self, other: &Rhs) -> bool

Tests less than or equal to (for self and other) and is used by the <= operator. Read more
1.0.0 · Source§

fn gt(&self, other: &Rhs) -> bool

Tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · Source§

fn ge(&self, other: &Rhs) -> bool

Tests greater than or equal to (for self and other) and is used by the >= operator. Read more
Source§

impl<T: Eq> Eq for WriteOnce<T>

Source§

impl<T: Send> Send for WriteOnce<T>

Source§

impl<T: Sync> Sync for WriteOnce<T>

Auto Trait Implementations§

§

impl<T> !Freeze for WriteOnce<T>

§

impl<T> !RefUnwindSafe for WriteOnce<T>

§

impl<T> Unpin for WriteOnce<T>
where T: Unpin,

§

impl<T> UnwindSafe for WriteOnce<T>
where T: 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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. 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> 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
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. 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.