Struct PtrCell

Source
pub struct PtrCell<T> { /* private fields */ }
Expand description

Thread-safe cell based on atomic pointers

This type stores its data externally by leaking it with Box. Synchronization is achieved by atomically manipulating pointers to the data

§Usage

use ptr_cell::{PtrCell, Semantics::Relaxed};

let cell: PtrCell<u16> = 0x81D.into();

assert_eq!(cell.replace(Some(2047), Relaxed), Some(0x81D));
assert_eq!(cell.is_empty(Relaxed), false);
assert_eq!(cell.take(Relaxed), Some(2047))

§Pointer Safety

When dereferencing a pointer to the cell’s value, you must ensure that the pointed-to memory hasn’t been reclaimed. For example, replace and its derivatives (set and take) automatically reclaim memory. Be careful not to miss any calls to such functions made from other threads

This also applies to externally-sourced pointers, like the ptr parameter in from_ptr

Implementations§

Source§

impl<T> PtrCell<T>

Source

pub fn map_owner<F>(&self, new: F, order: Semantics)
where F: FnOnce(Self) -> T, T: AsMut<Self>,

Inserts the value constructed from this cell by new into the cell itself

Think of this like the push method of a linked list, where each node contains a PtrCell

§Examples

The code below turns a sentence into a naive linked list of words, which is then assembled back into a String

use ptr_cell::{PtrCell, Semantics};

struct Node<T> {
    pub value: T,
    pub next: PtrCell<Self>,
}

impl<T> AsMut<PtrCell<Self>> for Node<T> {
    fn as_mut(&mut self) -> &mut ptr_cell::PtrCell<Self> {
        &mut self.next
    }
}

let cell = PtrCell::default();

for value in "Hachó en México".split_whitespace().rev() {
    cell.map_owner(|next| Node { value, next }, Semantics::Relaxed);
}

let Node { value, mut next } = cell
    .take(Semantics::Relaxed)
    .expect("Some values should've been inserted into the cell");

let mut decoded = value.to_string();
while let Some(node) = next.take(Semantics::Relaxed) {
    decoded.extend([" ", node.value]);
    next = node.next
}

assert_eq!(decoded, "Hachó en México")
Source

pub fn swap(&self, other: &mut Self, order: Semantics)

Swaps the values of two cells

§Usage
use ptr_cell::{PtrCell, Semantics::Relaxed};

let one: PtrCell<u8> = 1.into();
let mut two: PtrCell<u8> = 2.into();

one.swap(&mut two, Relaxed);

assert_eq!(two.take(Relaxed), Some(1));
assert_eq!(one.take(Relaxed), Some(2))
Source

pub fn take(&self, order: Semantics) -> Option<T>

Takes out the cell’s value

§Usage
use ptr_cell::{PtrCell, Semantics::Relaxed};

let cell: PtrCell<u8> = 45.into();

assert_eq!(cell.take(Relaxed), Some(45));
assert_eq!(cell.take(Relaxed), None)
Source

pub fn take_ptr(&self, order: Semantics) -> *mut T

Takes out the cell’s pointer

§Safety

Not inherently unsafe. See Pointer Safety

§Usage
use ptr_cell::{PtrCell, Semantics::Relaxed};

let cell: PtrCell<u8> = 45.into();
let ptr = cell.take_ptr(Relaxed);

assert_eq!(unsafe { ptr_cell::PtrCell::heap_reclaim(ptr) }, Some(45));
assert_eq!(cell.take_ptr(Relaxed), std::ptr::null_mut())
Source

pub fn set(&self, slot: Option<T>, order: Semantics)

Inserts a value into the cell

§Usage
use ptr_cell::{PtrCell, Semantics::Relaxed};

let cell = PtrCell::default();
cell.set(Some(1776), Relaxed);

assert_eq!(cell.take(Relaxed), Some(1776))
Source

pub unsafe fn set_ptr(&self, ptr: *mut T, order: Semantics)

Inserts a pointer into the cell

§Safety

The pointed-to memory must conform to the memory layout used by Box

§Usage
use ptr_cell::{PtrCell, Semantics::Relaxed};

let cell = PtrCell::default();

let ptr = PtrCell::heap_leak(Some(1776));
unsafe { cell.set_ptr(ptr, Relaxed) };

assert_eq!(cell.take(Relaxed), Some(1776))
Source

pub fn replace(&self, slot: Option<T>, order: Semantics) -> Option<T>

Replaces the cell’s value

§Usage
use ptr_cell::{PtrCell, Semantics::Relaxed};

let cell = PtrCell::from('a');

assert_eq!(cell.replace(Some('b'), Relaxed), Some('a'));
assert_eq!(cell.take(Relaxed), Some('b'))
Source

pub fn replace_ptr(&self, ptr: *mut T, order: Semantics) -> *mut T

Replaces the cell’s pointer

WARNING: THIS FUNCTION WAS ERRONEOUSLY LEFT SAFE. IT’S UNSAFE AND WILL BE MARKED AS SUCH IN THE NEXT MAJOR RELEASE

§Safety

The pointed-to memory must conform to the memory layout used by Box

See also: Pointer Safety

§Usage
use ptr_cell::{PtrCell, Semantics::Relaxed};

unsafe {
    let a = PtrCell::heap_leak(Some('a'));
    let b = PtrCell::heap_leak(Some('b'));

    let cell = PtrCell::from_ptr(a);

    assert_eq!(cell.replace_ptr(b, Relaxed), a);
    assert_eq!(cell.take_ptr(Relaxed), b);

    PtrCell::heap_reclaim(a);
    PtrCell::heap_reclaim(b);
}
Source

pub fn get_mut(&mut self) -> Option<&mut T>

Mutably borrows the cell’s value

§Usage
use ptr_cell::{PtrCell, Semantics::Relaxed};

let mut text = PtrCell::from("Point".to_string());
text.get_mut()
    .expect("The cell should contain a value")
    .push_str("er");

assert_eq!(text.take(Relaxed), Some("Pointer".to_string()))
Source

pub fn get_ptr(&self, order: Semantics) -> *mut T

Returns a pointer to the cell’s value

§Safety

Not inherently unsafe. See Pointer Safety

§Usage
use ptr_cell::{PtrCell, Semantics::Relaxed};

let cell = PtrCell::<[u8; 3]>::default();

assert_eq!(cell.get_ptr(Relaxed), std::ptr::null_mut())
Source

pub fn is_empty(&self, order: Semantics) -> bool

Determines whether this cell is empty

§Usage
use ptr_cell::{PtrCell, Semantics::Relaxed};

let cell = PtrCell::<[u8; 3]>::default();

assert!(cell.is_empty(Relaxed))
Source

pub fn new(slot: Option<T>) -> Self

Constructs a cell

§Usage
use ptr_cell::{PtrCell, Semantics::Relaxed};

let cell = PtrCell::new(Some(0xFAA));

assert_eq!(cell.take(Relaxed), Some(0xFAA));
assert!(cell.is_empty(Relaxed))
Source

pub const unsafe fn from_ptr(ptr: *mut T) -> Self

Constructs a cell that owns leaked memory

A null pointer represents None

§Safety

The memory must conform to the memory layout used by Box

§Usage
use ptr_cell::{PtrCell, Semantics::Relaxed};

let ptr = PtrCell::heap_leak(Some(0xFAA));
let cell = unsafe { PtrCell::from_ptr(ptr) };

assert_eq!(cell.take(Relaxed), Some(0xFAA));
assert!(cell.is_empty(Relaxed))
Source

pub unsafe fn heap_reclaim(ptr: *mut T) -> Option<T>

Reclaims ownership of leaked memory

A null pointer represents None

§Safety

The memory must conform to the memory layout used by Box

Dereferencing ptr after this function has been called may cause undefined behavior

§Usage
use ptr_cell::PtrCell;

let ptr = PtrCell::heap_leak(Some(1155));

assert_eq!(unsafe { PtrCell::heap_reclaim(ptr) }, Some(1155))
Source

pub fn heap_leak(slot: Option<T>) -> *mut T

Leaks a value to the heap

None is represented by a null pointer

The memory will conform to the memory layout used by Box

§Usage
use ptr_cell::PtrCell;

let ptr = PtrCell::heap_leak(Some(1155));

assert_eq!(unsafe { PtrCell::heap_reclaim(ptr) }, Some(1155))

Trait Implementations§

Source§

impl<T> Debug for PtrCell<T>

Source§

fn fmt(&self, formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T> Default for PtrCell<T>

Source§

fn default() -> Self

Constructs an empty cell

Source§

impl<T> Drop for PtrCell<T>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl<T> From<T> for PtrCell<T>

Source§

fn from(value: T) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

§

impl<T> !Freeze for PtrCell<T>

§

impl<T> RefUnwindSafe for PtrCell<T>

§

impl<T> Send for PtrCell<T>

§

impl<T> Sync for PtrCell<T>

§

impl<T> Unpin for PtrCell<T>

§

impl<T> UnwindSafe for PtrCell<T>
where T: RefUnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<!> for T

Source§

fn from(t: !) -> T

Converts to this type from the input type.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.