Struct ptr_cell::PtrCell

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

Thread-safe cell based on atomic pointers

This cell type stores its data externally: instead of owning values directly, it holds pointers to leaked values allocated by Box. Synchronization is achieved by atomically manipulating these pointers

This type has the same in-memory representation as a *mut T

§Usage

use ptr_cell::Semantics;

// Construct a cell
let cell: ptr_cell::PtrCell<u16> = 0x81D.into();

// Replace the value inside the cell
assert_eq!(cell.replace(Some(2047), Semantics::Relaxed), Some(0x81D));

// Check whether the cell is empty
assert_eq!(cell.is_empty(Semantics::Relaxed), false);

// Take the value out of the cell
assert_eq!(cell.take(Semantics::Relaxed), Some(2047))

§Semantics

All methods that access this cell’s data through &self inherently require a Semantics variant, as this is the only way to load the underlying atomic pointer. This parameter is omitted from the documentation of individual methods due to its universal applicability

§Pointer Safety

When dereferencing a pointer to the cell’s value, you must ensure that the memory it points to hasn’t been reclaimed. Notice that calls to replace and its derivatives (set and take) automatically reclaim memory. This includes any calls made from other threads

This also applies to external pointers that the cell now manages, 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>,

Replaces the cell’s value with a new one, constructed from the cell itself using the provided new function

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

§Usage
fn main() {
    use ptr_cell::Semantics;

    // Initialize a test sentence
    const SENTENCE: &str = "Hachó en México";

    // Construct an empty cell
    let cell = ptr_cell::PtrCell::default();

    // "encode" the sentence into the cell
    for word in SENTENCE.split_whitespace().rev() {
        // Make the new node set its value to the current word
        let value = word;

        // Replace the node with a new one pointing to it
        cell.map_owner(|next| Node { value, next }, Semantics::Relaxed);
    }

    // Take the first node out of the cell and destructure it
    let Node { value, mut next } = cell
        .take(Semantics::Relaxed)
        .expect("Values should have been inserted into the cell");

    // Initialize the "decoded" sentence with the first word
    let mut decoded = value.to_string();

    // Iterate over each remaining node
    while let Some(node) = next.take(Semantics::Relaxed) {
        // Append the word to the sentence
        decoded += " ";
        decoded += node.value;

        // Set the value to process next
        next = node.next
    }

    // Check that there were no errors
    assert_eq!(decoded, SENTENCE)
}

/// Unit of a linked list
struct Node<T> {
    pub value: T,
    pub next: ptr_cell::PtrCell<Self>,
}

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

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

Swaps the values of two cells

§Usage
use ptr_cell::Semantics;

// Initialize a pair of test values
const ONE: Option<u8> = Some(1);
const TWO: Option<u8> = Some(2);

// Construct a cell from each value
let cell_one = ptr_cell::PtrCell::new(ONE);
let mut cell_two = ptr_cell::PtrCell::new(TWO);

// Swap the cells' contents
cell_one.swap(&mut cell_two, Semantics::Relaxed);

// Check that the cells now contain each other's values
assert_eq!(ONE, cell_two.take(Semantics::Relaxed));
assert_eq!(TWO, cell_one.take(Semantics::Relaxed))
source

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

Returns the cell’s value, replacing it with None

This is an alias for self.replace(None, order)

§Usage
use ptr_cell::Semantics;

// Initialize a test value
const VALUE: Option<u8> = Some(0b01000101);

// Wrap the value in a cell
let cell = ptr_cell::PtrCell::new(VALUE);

// Take the value out
assert_eq!(cell.take(Semantics::Relaxed), VALUE);

// Verify that the cell is now empty
assert_eq!(cell.take(Semantics::Relaxed), None)
source

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

Returns the pointer to the cell’s value, replacing the pointer with a null one

This is an alias for self.replace_ptr(core::ptr::null_mut(), order)

§Usage
use ptr_cell::Semantics;

// Initialize a test value
const VALUE: Option<u8> = Some(0b01000101);

// Wrap the value in a cell
let cell = ptr_cell::PtrCell::new(VALUE);

// Take the pointer out
let ptr = cell.take_ptr(Semantics::Relaxed);

// Get the value back
assert_eq!(unsafe { ptr_cell::PtrCell::heap_reclaim(ptr) }, VALUE)
source

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

Sets the cell’s value to slot

This is an alias for { self.replace(slot, order); }

§Usage
use ptr_cell::Semantics;

// Initialize a test value
const VALUE: Option<u16> = Some(1776);

// Construct an empty cell
let cell: ptr_cell::PtrCell<_> = Default::default();

// Set the cell's value
cell.set(VALUE, Semantics::Relaxed);

// Check that the value was set
assert_eq!(cell.take(Semantics::Relaxed), VALUE)
source

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

Sets the pointer to the cell’s value to ptr

§Safety

The memory ptr points to must conform to the memory layout used by Box

§Usage
use ptr_cell::Semantics;

// Initialize a test value
const VALUE: Option<u16> = Some(1776);

// Construct an empty cell
let cell: ptr_cell::PtrCell<_> = Default::default();

// Allocate the value and get a pointer to it
let ptr = ptr_cell::PtrCell::heap_leak(VALUE);

// Make the cell point to the allocation
unsafe { cell.set_ptr(ptr, Semantics::Relaxed) };

// Check that the value was set
assert_eq!(cell.take(Semantics::Relaxed), VALUE)
source

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

Returns the cell’s value, replacing it with slot

§Usage
use ptr_cell::Semantics;

// Initialize a pair of test values
const SEMI: Option<char> = Some(';');
const COLON: Option<char> = Some(':');

// Wrap one of the values in a cell
let cell = ptr_cell::PtrCell::new(SEMI);

// Replace the value
assert_eq!(cell.replace(COLON, Semantics::Relaxed), SEMI);

// ...and get one back
assert_eq!(cell.replace(None, Semantics::Relaxed), COLON)

Note: For taking the value out of a cell, using take is recommended

source

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

Returns the pointer to the cell’s value, replacing the pointer with ptr

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

§Safety

The memory ptr points to must conform to the memory layout used by Box

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

unsafe {
    // Allocate a pair of test values on the heap
    let semi = PtrCell::heap_leak(Some(';'));
    let colon = PtrCell::heap_leak(Some(':'));

    // Construct a cell from one of the allocations
    let cell = PtrCell::from_ptr(semi);

    // Replace the pointer to the allocation
    assert_eq!(cell.replace_ptr(colon, Semantics::Relaxed), semi);

    // ...and get one back
    let null = std::ptr::null_mut();
    assert_eq!(cell.replace_ptr(null, Semantics::Relaxed), colon);

    // Clean up
    PtrCell::heap_reclaim(semi);
    PtrCell::heap_reclaim(colon);
}

Note: For taking the pointer out of a cell, using take_ptr is recommended

source

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

Mutably borrows the cell’s value

§Usage
use ptr_cell::Semantics;

// Construct a cell with a String inside
let mut text: ptr_cell::PtrCell<_> = "Punto aquí".to_string().into();

// Modify the String
text.get_mut()
    .expect("The cell should contain a value")
    .push_str(" con un puntero");

// Check the String's value
let sentence = "Punto aquí con un puntero".to_string();
assert_eq!(text.take(Semantics::Relaxed), Some(sentence))
source

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

Returns a pointer to the cell’s value

§Safety

The cell’s value may get deallocated at any moment. Because of this, it’s hard to safely dereference the resulting pointer. Refer to the Pointer Safety section for more details

§Usage
use ptr_cell::Semantics;

// Construct an empty cell
let cell: ptr_cell::PtrCell<[u8; 3]> = Default::default();

// Get the cell's pointer
assert_eq!(cell.get_ptr(Semantics::Relaxed), std::ptr::null_mut())
source

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

Determines whether this cell is empty

§Usage
use ptr_cell::Semantics;

// Construct an empty cell
let cell: ptr_cell::PtrCell<[char; 3]> = Default::default();

// Check that the cell's default value is None (empty)
assert!(cell.is_empty(Semantics::Relaxed))
source

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

Constructs a cell with slot inside

§Usage
use ptr_cell::Semantics;

// Initialize a test value
const VALUE: Option<u16> = Some(0xFAA);

// Wrap the value in a cell
let cell = ptr_cell::PtrCell::new(VALUE);

// Take the value out
assert_eq!(cell.take(Semantics::Relaxed), VALUE)
source

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

Constructs a cell that owns the memory to which ptr points

A null pointer represents None

§Safety

The memory must conform the memory layout used by Box

§Usage
use ptr_cell::Semantics;

// Initialize a test value
const VALUE: Option<u16> = Some(0xFAA);

// Allocate the value on the heap and get a pointer to it
let value_ptr = ptr_cell::PtrCell::heap_leak(VALUE);

// Construct a cell from the pointer
let cell = unsafe { ptr_cell::PtrCell::from_ptr(value_ptr) };

// Take the value out
assert_eq!(cell.take(Semantics::Relaxed), VALUE)
source

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

Reclaims ownership of the memory pointed to by ptr and returns the contained value

A null pointer represents None

This function is intended to be the inverse of heap_leak

§Safety

The memory must conform to the memory layout used by Box

Dereferencing ptr after this function has been called is undefined behavior

§Usage
// Initialize a test value
const VALUE: Option<u16> = Some(1155);

// Give up ownership of the value
let ptr = ptr_cell::PtrCell::heap_leak(VALUE);

// Get ownership of the value back
assert_eq!(unsafe { ptr_cell::PtrCell::heap_reclaim(ptr) }, VALUE)
source

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

Leaks slot to the heap and returns a raw pointer to it

None is represented by a null pointer

The memory will be allocated in accordance with the memory layout used by Box

§Usage
use ptr_cell::Semantics;

// Allocate a value
let ptr = ptr_cell::PtrCell::heap_leak(1031_u16.into());

// Transfer ownership of the allocation to a new cell
let cell = unsafe { ptr_cell::PtrCell::from_ptr(ptr) };

// Check that the cell uses the same allocation
assert_eq!(cell.get_ptr(Semantics::Relaxed), ptr)

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>,

§

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>,

§

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.