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>
impl<T> PtrCell<T>
sourcepub fn map_owner<F>(&self, new: F, order: Semantics)
pub fn map_owner<F>(&self, new: F, order: Semantics)
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
}
}
sourcepub fn swap(&self, other: &mut Self, order: Semantics)
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))
sourcepub fn take(&self, order: Semantics) -> Option<T>
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)
sourcepub fn take_ptr(&self, order: Semantics) -> *mut T
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)
sourcepub fn set(&self, slot: Option<T>, order: Semantics)
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)
sourcepub unsafe fn set_ptr(&self, ptr: *mut T, order: Semantics)
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)
sourcepub fn replace(&self, slot: Option<T>, order: Semantics) -> Option<T>
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
sourcepub fn replace_ptr(&self, ptr: *mut T, order: Semantics) -> *mut T
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
sourcepub fn get_mut(&mut self) -> Option<&mut T>
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))
sourcepub fn get_ptr(&self, order: Semantics) -> *mut T
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())
sourcepub fn is_empty(&self, order: Semantics) -> bool
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))
sourcepub fn new(slot: Option<T>) -> Self
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)
sourcepub const unsafe fn from_ptr(ptr: *mut T) -> Self
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)
sourcepub unsafe fn heap_reclaim(ptr: *mut T) -> Option<T>
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)
sourcepub fn heap_leak(slot: Option<T>) -> *mut T
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)