Skip to content

OnceCell/Lock::try_insert() #276

@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

Activity

added
ACP-acceptedAPI Change Proposal is accepted (seconded with no objections)
on Oct 8, 2023
BurntSushi

BurntSushi commented on Oct 8, 2023

@BurntSushi
Member

Seconded. (I will say though that I am somewhat skeptical of this routine and it isn't clear that it pulls its weight. On the path to stabilization, I'd be interested in both how much this optimization buys us and how often it would be used.)

added a commit that references this issue on Oct 14, 2023
fcd75cc
added a commit that references this issue on Oct 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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

        Participants

        @BurntSushi@daxpedda

        Issue actions

          `OnceCell/Lock::try_insert()` · Issue #276 · rust-lang/libs-team