Expand description
A pointer type for persistent heap allocation.
If Pbox
is mutable, the underlying data can mutate after taking a log.
It is necessary because compound types containing a Pbox
may provide
interior mutability (via PCell
or PRefCell
) though which the
Pbox
become mutably available. The log taken for interior mutability works
only on the pointer value and does not include the referent object. Therefore,
Pbox
provides a logging mechanism to provide mutable dereferencing.
Examples
Create a boxed object in the persistent memory
use corundum::default::*;
type P = Allocator;
let _p = P::open_no_root("foo.pool", O_CF).unwrap();
transaction(|j| {
let five = Pbox::new(5, j);
assert_eq!(*five, 5);
}).unwrap();
Examples
Move a value from the stack to the persistent memory by creating a Pbox
:
transaction(|j| {
let val: u8 = 5;
let boxed: Pbox<u8> = Pbox::new(val, j);
}).unwrap();
Move a value from a Pbox
back to the stack by dereferencing:
transaction(|j| {
let boxed: Pbox<u8> = Pbox::new(5, j);
let val: u8 = *boxed;
}).unwrap();
Creating a recursive data structure:
#[derive(Debug)]
enum List<T: PSafe> {
Cons(T, Pbox<List<T>>),
Nil,
}
transaction(|j| {
let list: List<i32> = List::Cons(1, Pbox::new(List::Cons(2, Pbox::new(List::Nil, j)), j));
println!("{:?}", list);
}).unwrap();
This will print Cons(1, Cons(2, Nil))
.
Recursive structures must be boxed, because if the definition of Cons
looked like this:
Cons(T, List<T>),
It wouldn’t work. This is because the size of a List
depends on how many
elements are in the list, and so we don’t know how much memory to allocate
for a Cons
. By introducing a Pbox<T>
, which has a defined size, we know
how big Cons
needs to be.
Implementations
sourceimpl<T: PSafe, A: MemPool> Pbox<T, A>
impl<T: PSafe, A: MemPool> Pbox<T, A>
sourcepub fn new(x: T, journal: &Journal<A>) -> Pbox<T, A>
pub fn new(x: T, journal: &Journal<A>) -> Pbox<T, A>
Allocates memory on the persistent heap and then places x
into it.
This doesn’t actually allocate if T
is zero-sized.
Examples
Heap::transaction(|j| {
let five = Pbox::new(5, j);
}).unwrap();
pub fn off(&self) -> u64
sourcepub fn new_uninit(journal: &Journal<A>) -> Pbox<MaybeUninit<T>, A>
pub fn new_uninit(journal: &Journal<A>) -> Pbox<MaybeUninit<T>, A>
Constructs a new Pbox with uninitialized contents.
Examples
P::transaction(|j| {
let mut five = Pbox::<u32>::new_uninit(j);
let five = unsafe {
// Deferred initialization:
five.as_mut_ptr().write(5);
five.assume_init()
};
assert_eq!(*five, 5)
}).unwrap()
sourcepub fn new_zeroed(journal: &Journal<A>) -> Pbox<MaybeUninit<T>, A>
pub fn new_zeroed(journal: &Journal<A>) -> Pbox<MaybeUninit<T>, A>
Constructs a new Pbox
with uninitialized contents, with the memory
being filled with 0
bytes.
See MaybeUninit::zeroed
for examples of correct and incorrect usage
of this method.
Examples
P::transaction(|j| {
let zero = Pbox::<u32>::new_zeroed(j);
let zero = unsafe { zero.assume_init() };
assert_eq!(*zero, 0)
}).unwrap()
sourceimpl<T: PSafe, A: MemPool> Pbox<MaybeUninit<T>, A>
impl<T: PSafe, A: MemPool> Pbox<MaybeUninit<T>, A>
sourcepub unsafe fn assume_init(self) -> Pbox<T, A>
pub unsafe fn assume_init(self) -> Pbox<T, A>
Converts to Pbox<T, A>
.
Safety
As with MaybeUninit::assume_init
,
it is up to the caller to guarantee that the value
really is in an initialized state.
Calling this when the content is not yet fully initialized
causes immediate undefined behavior.
sourceimpl<T: PSafe, A: MemPool> Pbox<T, A>
impl<T: PSafe, A: MemPool> Pbox<T, A>
sourcepub fn initialize(boxed: &Option<Pbox<T, A>>, value: T) -> Result<()>
pub fn initialize(boxed: &Option<Pbox<T, A>>, value: T) -> Result<()>
Initializes boxed data with value
in-place if it is None
This function should not be called from a transaction as it updates data without taking high-level logs. If transaction is unsuccessful, there is no way to recover data. However, it is safe to use it outside a transaction because it uses low-level logs to provide safety for a single update without drop. A dynamic check at the beginning makes sure of that.
Examples
use corundum::default::*;
type P = Allocator;
let root = P::open::<Option<Pbox<i32>>>("foo.pool", O_CF).unwrap();
Pbox::initialize(&*root, 25);
let value = **root.as_ref().unwrap();
assert_eq!(value, 25);
sourceimpl<T: PSafe + ?Sized, A: MemPool> Pbox<T, A>
impl<T: PSafe + ?Sized, A: MemPool> Pbox<T, A>
sourcepub unsafe fn from_raw(raw: *mut T) -> Self
pub unsafe fn from_raw(raw: *mut T) -> Self
Constructs a box from a raw pointer.
After calling this function, the raw pointer is owned by the
resulting Pbox
. Specifically, the Pbox
destructor will call
the destructor of T
and free the allocated memory. For this
to be safe, the memory must have been allocated in accordance
with the memory layout used by Pbox
.
Safety
This function is unsafe because improper use may lead to memory problems. For example, a double-free may occur if the function is called twice on the same raw pointer.
sourcepub fn into_raw(b: Pbox<T, A>) -> *mut T
pub fn into_raw(b: Pbox<T, A>) -> *mut T
Consumes the Pbox
, returning a wrapped raw pointer.
The pointer will be properly aligned and non-null.
After calling this function, the caller is responsible for the
memory previously managed by the Pbox
. In particular, the
caller should properly destroy T
and release the memory, taking
into account the [memory layout] used by Pbox
. The easiest way to
do this is to convert the raw pointer back into a Pbox
with the
Pbox::from_raw
function, allowing the Pbox
destructor to perform
the cleanup.
Note: this is an associated function, which means that you have
to call it as Pbox::into_raw(b)
instead of b.into_raw()
. This
is so that there is no conflict with a method on the inner type.
sourcepub fn into_raw_non_null(b: Pbox<T, A>) -> NonNull<T>
pub fn into_raw_non_null(b: Pbox<T, A>) -> NonNull<T>
Consumes the Pbox
, returning the wrapped pointer as NonNull<T>
.
After calling this function, the caller is responsible for the
memory previously managed by the Pbox
. In particular, the
caller should properly destroy T
and release the memory. The
easiest way to do so is to convert the NonNull<T>
pointer
into a raw pointer and back into a Pbox
with the Pbox::from_raw
function.
Note: this is an associated function, which means that you have
to call it as Pbox::into_raw_non_null(b)
instead of b.into_raw_non_null()
. This
is so that there is no conflict with a method on the inner type.
sourcepub unsafe fn leak<'a>(b: Pbox<T, A>) -> &'a mut T where
T: 'a,
pub unsafe fn leak<'a>(b: Pbox<T, A>) -> &'a mut T where
T: 'a,
Consumes and leaks the Pbox
, returning a mutable reference,
&'a mut T
. Note that the type T
must outlive the chosen lifetime
'a
. If the type has only static references, or none at all, then this
may be chosen to be 'static
.
This function is mainly useful for data that lives for the remainder of
the program’s life. Dropping the returned reference will cause a memory
leak. If this is not acceptable, the reference should first be wrapped
with the Pbox::from_raw
function producing a Pbox
. This Pbox
can
then be dropped which will properly destroy T
and release the
allocated memory.
Note: this is an associated function, which means that you have
to call it as Pbox::leak(b)
instead of b.leak()
. This
is so that there is no conflict with a method on the inner type.
Safety
This function is considered unsafe in persistent memory programming because memory leak is permanent and undesirable.
Examples
Simple usage:
Heap::transaction(|j| unsafe {
let x = Pbox::new(41, j);
let static_ref: &'static mut usize = Pbox::leak(x);
*static_ref += 1;
assert_eq!(*static_ref, 42);
}).unwrap();
sourcepub fn into_pin(boxed: Pbox<T, A>) -> Pin<Pbox<T, A>> where
T: Sized,
pub fn into_pin(boxed: Pbox<T, A>) -> Pin<Pbox<T, A>> where
T: Sized,
Converts a Pbox<T, A>
into a Pin<Pbox<T, A>>
This conversion does not allocate on the heap and happens in place.
This is also available via From
.
pub unsafe fn as_mut(&mut self) -> &mut T
Trait Implementations
sourceimpl<T: PSafe + Hasher + ?Sized, A: MemPool> Hasher for Pbox<T, A>
impl<T: PSafe + Hasher + ?Sized, A: MemPool> Hasher for Pbox<T, A>
sourcefn write_u128(&mut self, i: u128)
fn write_u128(&mut self, i: u128)
Writes a single u128
into this hasher.
sourcefn write_usize(&mut self, i: usize)
fn write_usize(&mut self, i: usize)
Writes a single usize
into this hasher.
sourcefn write_i128(&mut self, i: i128)
fn write_i128(&mut self, i: i128)
Writes a single i128
into this hasher.
sourcefn write_isize(&mut self, i: isize)
fn write_isize(&mut self, i: isize)
Writes a single isize
into this hasher.
sourceimpl<T: PSafe + Ord + ?Sized, A: MemPool> Ord for Pbox<T, A>
impl<T: PSafe + Ord + ?Sized, A: MemPool> Ord for Pbox<T, A>
sourceimpl<T: PSafe + PClone<A> + ?Sized, A: MemPool> PClone<A> for Pbox<T, A>
impl<T: PSafe + PClone<A> + ?Sized, A: MemPool> PClone<A> for Pbox<T, A>
sourcedefault fn pclone(&self, journal: &Journal<A>) -> Pbox<T, A>
default fn pclone(&self, journal: &Journal<A>) -> Pbox<T, A>
Returns a new box with a pclone()
of this box’s contents.
Examples
use corundum::clone::PClone;
Heap::transaction(|j| {
let x = Pbox::new(5, j);
let y = x.pclone(j);
// The value is the same
assert_eq!(x, y);
// But they are unique objects
assert_ne!(&*x as *const i32, &*y as *const i32);
}).unwrap();
sourcefn pclone_from(&mut self, source: &Self, journal: &Journal<A>)
fn pclone_from(&mut self, source: &Self, journal: &Journal<A>)
Performs copy-assignment from source
. Read more
sourceimpl<T: PSafe + PartialOrd + ?Sized, A: MemPool> PartialOrd<Pbox<T, A>> for Pbox<T, A>
impl<T: PSafe + PartialOrd + ?Sized, A: MemPool> PartialOrd<Pbox<T, A>> for Pbox<T, A>
sourcefn partial_cmp(&self, other: &Pbox<T, A>) -> Option<Ordering>
fn partial_cmp(&self, other: &Pbox<T, A>) -> Option<Ordering>
This method returns an ordering between self
and other
values if one exists. Read more
sourcefn lt(&self, other: &Pbox<T, A>) -> bool
fn lt(&self, other: &Pbox<T, A>) -> bool
This method tests less than (for self
and other
) and is used by the <
operator. Read more
sourcefn le(&self, other: &Pbox<T, A>) -> bool
fn le(&self, other: &Pbox<T, A>) -> bool
This method tests less than or equal to (for self
and other
) and is used by the <=
operator. Read more
impl<T: PSafe + Eq + ?Sized, A: MemPool> Eq for Pbox<T, A>
impl<A: MemPool, T: ?Sized> !Send for Pbox<T, A>
impl<T: ?Sized, A: MemPool> !TxOutSafe for Pbox<T, A>
impl<T: PSafe + ?Sized, A: MemPool> Unpin for Pbox<T, A>
impl<A: MemPool, T: ?Sized> !VSafe for Pbox<T, A>
Auto Trait Implementations
impl<T: ?Sized, A> LooseTxInUnsafe for Pbox<T, A> where
T: LooseTxInUnsafe,
impl<T: ?Sized, A> PSafe for Pbox<T, A>
impl<T: ?Sized, A> PSend for Pbox<T, A> where
A: PSend,
T: PSend,
impl<T: ?Sized, A> RefUnwindSafe for Pbox<T, A> where
T: RefUnwindSafe,
impl<T, A> !Sync for Pbox<T, A>
impl<T: ?Sized, A> TxInSafe for Pbox<T, A> where
T: TxInSafe,
impl<T: ?Sized, A> UnwindSafe for Pbox<T, A> where
T: UnwindSafe,
Blanket Implementations
sourceimpl<T> BorrowMut<T> for T where
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
const: unstable · sourcefn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more