Skip to content

OnceCell/Lock::try_insert() #276

Closed
Closed
@daxpedda

Description

@daxpedda

Proposal

Problem statement

I would like to insert a value into a OnceCell/Lock and get back a reference to it while also checking if the value was already set or not.

Motivating examples or use cases

This can be useful in racy conditions, where different threads or Futures are trying to assign to the same OnceCell/Lock. The "loser" should be able to get the old and new value and determine if there is any difference or what that difference is.

static VALUE: OnceLock<Vec<u8>> = OnceLock::new();

if let Some(value) = VALUE.get() {
    println!("report value: {value:?}");
} else {
    match VALUE.try_insert(calculate_value()) {
        Ok(value) => println!("report value: {value:?}");
        // Some other thread has won the race to determine this value first.
        Err(old_value, new_value) => assert_eq!(old_value, new_value, "somehow calculated values differed"),
    }
}

Solution sketch

impl<T> OnceCell/Lock<T> {
    pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)>;
}

Alternatives

This proposal offers an optimization, but it's perfectly possible to do this with the existing methods:

if let Some(value) = VALUE.get() {
    println!("report value: {value:?}");
} else {
    match VALUE.set(calculate_value()) {
        Ok(value) => println!("report value: {value:?}");
        // Some other thread has won the race to determine this value first.
        Err(new_value) => assert_eq!(value.get().unwrap(), new_value, "somehow calculated values differed"),
    }
}

try_insert() would offer an optimized path that doesn't require an additional unwrap().

This method is currently available in once_cell, which as far as I'm aware was the original inspiration for std::cell::OnceCell and std::sync::OnceLock.

Links and related work

Metadata

Metadata

Assignees

No one assigned

    Labels

    ACP-acceptedAPI Change Proposal is accepted (seconded with no objections)T-libs-apiapi-change-proposalA proposal to add or alter unstable APIs in the standard libraries

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions