Skip to content

More methods to OnceCell #77

Description

@tisonkun
  • get_or_try_init
  • get_mut
  • get_mut_or_init
  • get_mut_or_try_init
  • set
  • try_insert
  • take

You can refer to:

Also, it's possible to add a LazyCell primitive that has a pre-configured initializer (closure).

Activity

  1. BewareMyPower commented on Nov 29, 2025

    @BewareMyPower
    Contributor

    I'm wondering if it's worth implementing a get_mut_or_init. This method should accept a mutable reference so that it cannot be called concurrently.

    A typical use case for modifying a mutable reference is calling get_or_init on an OnceCell whose value is something like Arc<Mutex<T>> so that it can be modified concurrently.

    #[test]
    fn multi_init_mut() {
        let rt = tokio::runtime::Builder::new_multi_thread()
            .worker_threads(4)
            .enable_time()
            .build()
            .unwrap();
    
        static CELL: OnceCell<AtomicUsize> = OnceCell::new();
    
        rt.block_on(async {
            const N: usize = 100;
    
            let mut handles = vec![];
            for i in 0..N {
                handles.push(rt.spawn(async move {
                    let result = CELL
                        .get_or_init(move || async move { AtomicUsize::new(1000 + i) })
                        .await;
                    result.fetch_add(1, Ordering::Relaxed);
                    tokio::time::sleep(Duration::from_millis(100)).await;
                    result.load(Ordering::Relaxed)
                }));
            }
            let mut values = vec![];
            for handle in handles {
                values.push(handle.await.unwrap());
            }
            let value = CELL.get().unwrap().load(Ordering::Relaxed);
            assert!(
                value >= 1000 + N && value < 1000 + N + N,
                "final value: {}",
                value
            );
            for v in values {
                assert_eq!(v, value);
            }
        });
    }
  2. tisonkun commented on Nov 29, 2025

    @tisonkun
    MemberAuthor

    You can see the linked issue.

    While async primitives can be used to share cross threads, our OnceCell can be used as an analogy to std OnceLock while its pass-in function is an async fn.

    Thus, this can be used as a cell that initialized only once and need not shared among threads.

  3. tisonkun commented on Nov 29, 2025

    @tisonkun
    MemberAuthor
  4. BewareMyPower commented on Nov 29, 2025

    @BewareMyPower
    Contributor

    Okay, it makes sense

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

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions