# Crate once_cell [−] [src]

# Overview

`once_cell` provides two new cell-like types, `unsync::OnceCell` and `sync::OnceCell`. A `OnceCell` might store arbitrary non-`Copy` types, can be assigned to at most once and provides direct access to the stored contents. The core API looks roughly like this (and there’s much more inside, read on!):

ⓘ

    impl<T> OnceCell<T> {
        fn new() -> OnceCell<T> { ... }
        fn set(&self, value: T) -> Result<(), T> { ... }
        fn get(&self) -> Option<&T> { ... }
    }

Note that, like with `RefCell` and `Mutex`, the `set` method requires only a shared reference. Because of the single assignment restriction `get` can return a `&T` instead of `Ref<T>` or `MutexGuard<T>`.

The `sync` flavor is thread-safe (that is, implements the `Sync` trait), while the `unsync` one is not.

# Patterns

`OnceCell` might be useful for a variety of patterns.

## Safe Initialization of global data

    use std::{env, io};

    use once_cell::sync::OnceCell;

    #[derive(Debug)]
    pub struct Logger {
        // ...
    }
    static INSTANCE: OnceCell<Logger> = OnceCell::new();

    impl Logger {
        pub fn global() -> &'static Logger {
            INSTANCE.get().expect("logger is not initialized")
        }

        fn from_cli(args: env::Args) -> Result<Logger, std::io::Error> {
           // ...
        }
    }

    fn main() {
        let logger = Logger::from_cli(env::args()).unwrap();
        INSTANCE.set(logger).unwrap();
        // use `Logger::global()` from now on
    }

## Lazy initialized global data

This is essentially the `lazy_static!` macro, but without a macro.

    use std::{sync::Mutex, collections::HashMap};

    use once_cell::sync::OnceCell;

    fn global_data() -> &'static Mutex<HashMap<i32, String>> {
        static INSTANCE: OnceCell<Mutex<HashMap<i32, String>>> = OnceCell::new();
        INSTANCE.get_or_init(|| {
            let mut m = HashMap::new();
            m.insert(13, "Spica".to_string());
            m.insert(74, "Hoyten".to_string());
            Mutex::new(m)
        })
    }

There are also the `sync::Lazy` and `unsync::Lazy` convenience types to streamline this pattern:

    use std::{sync::Mutex, collections::HashMap};
    use once_cell::sync::Lazy;

    static GLOBAL_DATA: Lazy<Mutex<HashMap<i32, String>>> = Lazy::new(|| {
        let mut m = HashMap::new();
        m.insert(13, "Spica".to_string());
        m.insert(74, "Hoyten".to_string());
        Mutex::new(m)
    });

    fn main() {
        println!("{:?}", GLOBAL_DATA.lock().unwrap());
    }

## General purpose lazy evaluation

Unlike `lazy_static!`, `Lazy` works with local variables.

    use once_cell::unsync::Lazy;

    fn main() {
        let ctx = vec![1, 2, 3];
        let thunk = Lazy::new(|| {
            ctx.iter().sum::<i32>()
        });
        assert_eq!(*thunk, 6);
    }

If you need a lazy field in a struct, you probably should use `OnceCell` directly, because that will allow you to access `self` during initialization.

    use std::{fs, path::PathBuf};

    use once_cell::unsync::OnceCell;

    struct Ctx {
        config_path: PathBuf,
        config: OnceCell<String>,
    }

    impl Ctx {
        pub fn get_config(&self) -> Result<&str, std::io::Error> {
            let cfg = self.config.get_or_try_init(|| {
                fs::read_to_string(&self.config_path)
            })?;
            Ok(cfg.as_str())
        }
    }

## Building block

Naturally, it is possible to build other abstractions on top of `OnceCell`. For example, this is a `regex!` macro which takes a string literal and returns an expression that evaluates to a `&'static Regex`:

    macro_rules! regex {
        ($re:literal $(,)?) => {{
            static RE: once_cell::sync::OnceCell<regex::Regex> = once_cell::sync::OnceCell::new();
            RE.get_or_init(|| regex::Regex::new($re).unwrap())
        }};
    }

This macro can be useful to avoid the “compile regex on every loop iteration” problem.

Another pattern would be a `LateInit` type for delayed initialization:

    use once_cell::sync::OnceCell;

    #[derive(Debug)]
    pub struct LateInit<T> { cell: OnceCell<T> }

    impl<T> LateInit<T> {
        pub fn init(&self, value: T) {
            assert!(self.cell.set(value).is_ok())
        }
    }

    impl<T> Default for LateInit<T> {
        fn default() -> Self { LateInit { cell: OnceCell::default() } }
    }

    impl<T> std::ops::Deref for LateInit<T> {
        type Target = T;
        fn deref(&self) -> &T {
            self.cell.get().unwrap()
        }
    }

    #[derive(Default, Debug)]
    struct A<'a> {
        b: LateInit<&'a B<'a>>,
    }

    #[derive(Default, Debug)]
    struct B<'a> {
        a: LateInit<&'a A<'a>>
    }

    fn build_cycle() {
        let a = A::default();
        let b = B::default();
        a.b.init(&b);
        b.a.init(&a);
        println!("{:?}", a.b.a.b.a);
    }

# Comparison with std

`!Sync` types | Access Mode | Drawbacks
--- | --- | ---
`Cell<T>` | `T` | requires `T: Copy` for `get`
`RefCell<T>` | `RefMut<T>` / `Ref<T>` | may panic at runtime
`unsync::OnceCell<T>` | `&T` | assignable only once

`Sync` types | Access Mode | Drawbacks
--- | --- | ---
`AtomicT` | `T` | works only with certain `Copy` types
`Mutex<T>` | `MutexGuard<T>` | may deadlock at runtime, may block the thread
`sync::OnceCell<T>` | `&T` | assignable only once, may block the thread

Technically, calling `get_or_init` will also cause a panic or a deadlock if it recursively calls itself. However, because the assignment can happen only once, such cases should be more rare than equivalents with `RefCell` and `Mutex`.

# Minimum Supported `rustc` Version

This crate’s minimum supported `rustc` version is `1.36.0`.

If only the `std` feature is enabled, MSRV will be updated conservatively. When using other features, like `parking_lot`, MSRV might be updated more frequently, up to the latest stable. In both cases, increasing MSRV is not considered a semver-breaking change.

# Implementation details

The implementation is based on the `lazy_static` and `lazy_cell` crates and `std::sync::Once`. In some sense, `once_cell` just streamlines and unifies those APIs.

To implement a sync flavor of `OnceCell`, this crates uses either a custom re-implementation of `std::sync::Once` or `parking_lot::Mutex`. This is controlled by the `parking_lot` feature (disabled by default). Performance is the same for both cases, but the `parking_lot` based `OnceCell<T>` is smaller by up to 16 bytes.

This crate uses `unsafe`.

# F.A.Q.

Should I use lazy_static or once_cell?

To the first approximation, `once_cell` is both more flexible and more convenient than `lazy_static` and should be preferred.

Unlike `once_cell`, `lazy_static` supports spinlock-based implementation of blocking which works with `#![no_std]`.

`lazy_static` has received significantly more real world testing, but `once_cell` is also a widely used crate.

Should I use the sync or unsync flavor?

Because Rust compiler checks thread safety for you, it’s impossible to accidentally use `unsync` where `sync` is required. So, use `unsync` in single-threaded code and `sync` in multi-threaded. It’s easy to switch between the two if code becomes multi-threaded later.

At the moment, `unsync` has an additional benefit that reentrant initialization causes a panic, which might be easier to debug than a deadlock.

# Related crates

- double-checked-cell
- lazy-init
- lazycell
- mitochondria
- lazy_static

Most of this crate’s functionality is available in `std` in nightly Rust. See the tracking issue.

## Modules

race | “First one wins” flavor of `OnceCell`.
sync |
unsync |