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.

You can only initialize a DoubleCheckedCell<T> once, but then it 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.