Crate double_checked_cell [] [src]

A thread-safe lazily initialized cell using double-checked locking.

Provides a memory location that can be safely shared between threads and initialized at most once. Once the cell is initialized it becomes immutable.

If you do not need to change the value after initialization DoubleCheckedCell<T> is more efficient than a Mutex<Option<T>>.

Examples

use double_checked_cell::DoubleCheckedCell;

let cell = DoubleCheckedCell::new();

// The cell starts uninitialized.
assert_eq!(cell.get(), None);

// Perform potentially expensive initialization.
let value = cell.get_or_init(|| 21 + 21);
assert_eq!(*value, 42);
assert_eq!(cell.get(), Some(&42));

// The cell is already initialized.
let value = cell.get_or_init(|| {
    panic!("initilization does not run again")
});
assert_eq!(*value, 42);
assert_eq!(cell.get(), Some(&42));

Errors

DoubleCheckedCell supports fallible initialization.

use std::fs::File;
use std::io;
use std::io::prelude::*;
use double_checked_cell::DoubleCheckedCell;

let cell = DoubleCheckedCell::new();

let contents: io::Result<&String> = cell.get_or_try_init(|| {
    let mut file = File::open("not-found.txt")?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    Ok(contents)
});

// File not found.
assert!(contents.is_err());

// Cell remains uninitialized for now.
assert_eq!(cell.get(), None);

Poisoning

DoubleCheckedCell achieves unwind safety by implementing "poisoning". If an initilization closure is executed and panics, the DoubleCheckedCell becomes poisoned. Any subsequent reads will then also panic.

use std::panic;
use double_checked_cell::DoubleCheckedCell;

let cell = DoubleCheckedCell::new();

// Cell gets poisoned.
assert!(panic::catch_unwind(|| {
    cell.get_or_init(|| panic!("oh no!"));
}).is_err());

// Now it is poisoned forever.
assert!(panic::catch_unwind(|| {
    cell.get_or_init(|| true);
}).is_err());

Structs

DoubleCheckedCell

A thread-safe lazily initialized cell.