Crate atomic_ptr_cell

Crate atomic_ptr_cell 

Source
Expand description

§atomic_ptr_cell

Safe no_std repr(transparent) wrapper for AtomicPtr and &AtomicPtr with an api similar to a cell.

The crate requires an allocator using extern crate alloc; if used without std.

§Example using owned AtomicPtr:

use std::thread;
use atomic_ptr_cell::*;

static CELL: AtomicPointerCell<String> = AtomicPointerCell::new();

fn test() {
 CELL.set("Hello".to_string());
 let guard = CELL.borrow().unwrap();
 assert_eq!("Hello", guard.as_str());
 let jh = thread::spawn(|| {
    CELL.set("World".to_string());
    let guard = CELL.borrow().unwrap();
    assert!("Hello" == guard.as_str() || "World" == guard.as_str());
    drop(guard);

 });
 drop(guard);

 //This small example already has a surprising amount of possible outcomes :D

 let Some(value) = CELL.take() else {
    _= jh.join();
    let value = CELL.take().unwrap();
    assert!("Hello" == value.as_str() || "World" == value.as_str());
    return;
 };

 assert!("Hello" == value.as_str() || "World" == value.as_str());
 _= jh.join();
 if let Some(value2) = CELL.take() {
    //Depending on the order of execution CELL.take() may return None here.
    assert_ne!(value, value2);
 }
}

§Example using &AtomicPtr reference

use atomic_ptr_cell::*;
use std::ptr::null_mut;
use std::sync::atomic::AtomicPtr;
use std::thread;

static CELL: AtomicPtr<String> = AtomicPtr::new(null_mut());

fn test() {
    // Safety: Caller must guarantee that the AtomicPtr never contains a non-null pointer that is not from Box::into_raw
    let cell: AtomicPtrCell<String> = unsafe { AtomicPtrCell::new(&CELL) };
    cell.set("Hello".to_string());
    let guard = cell.borrow().unwrap();
    assert_eq!("Hello", guard.as_str());
    let jh = thread::spawn(move || {
        //The AtomicPtrCell is copy as its layout is equivalent to &AtomicPtr
        // making it easy to use in closures and threads.
        // You just need to ensure the lifetime of &AtomicPtr outlives the scope.
        // In this example the lifetime is static.
        cell.set("World".to_string());
        let guard = cell.borrow().unwrap();
        assert!("Hello" == guard.as_str() || "World" == guard.as_str());
        drop(guard);
    });
    drop(guard);

    //This small example already has a surprising amount of possible outcomes :D

    let Some(value) = cell.take() else {
        _ = jh.join();
        let value = cell.take().unwrap();
        assert!("Hello" == value.as_str() || "World" == value.as_str());
        return;
    };

    assert!("Hello" == value.as_str() || "World" == value.as_str());
    _ = jh.join();
    if let Some(value2) = cell.take() {
        //Depending on the order of execution CELL.take() may return None here.
        assert_ne!(value, value2);
    }
}

Structs§

AtomicPointerCell
This is a helper struct that is guaranteed to have the exact same layout as AtomicPtr<T>.
AtomicPtrCell
This is a helper struct that is guaranteed to have the exact same layout as &AtomicPtr<T>.
BorrowGuard
Borrow guard of a AtomicCell. Once this cell is dropped the value is moved back into the cell if the cell is empty at that time.

Enums§

BorrowSwapResult
Result enum to indicate the outcomes of a borrow_swap operation.
PresentResult