[][src]Struct crndm::boxed::Pbox

pub struct Pbox<T: PSafe + ?Sized, A: MemPool>(_, _);

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 LogCell or LogRefCell) 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 crndm::default::*;

type P = BuddyAlloc;

let _ = 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:

This example deliberately fails to compile
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

impl<T: PSafe, A: MemPool> Pbox<T, A>[src]

pub fn new(x: T, journal: &Journal<A>) -> Pbox<T, A>[src]

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[src]

pub fn new_uninit(journal: &Journal<A>) -> Pbox<MaybeUninit<T>, A>[src]

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()

pub fn new_zeroed(journal: &Journal<A>) -> Pbox<MaybeUninit<T>, A>[src]

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()

pub fn pin(x: T, journal: &Journal<A>) -> Pin<Pbox<T, A>>[src]

Constructs a new Pin<Pbox<T, A>>. If T does not implement Unpin, then x will be pinned in memory and unable to be moved.

impl<T: PSafe, A: MemPool> Pbox<MaybeUninit<T>, A>[src]

pub unsafe fn assume_init(self) -> Pbox<T, A>[src]

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.

impl<T: PSafe, A: MemPool> Pbox<T, A>[src]

pub fn initialize(boxed: &Option<Pbox<T, A>>, value: T) -> Result<()>[src]

Initializes boxed data with value inplace if it is Null

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 crndm::default::*;
 
type P = BuddyAlloc;

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);

impl<T: PSafe + ?Sized, A: MemPool> Pbox<T, A>[src]

pub unsafe fn from_raw(raw: *mut T) -> Self[src]

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.

pub fn into_raw(b: Pbox<T, A>) -> *mut T[src]

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.

pub fn into_raw_non_null(b: Pbox<T, A>) -> NonNull<T>[src]

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.

pub unsafe fn leak<'a>(b: Pbox<T, A>) -> &'a mut T where
    T: 'a, 
[src]

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();

pub fn into_pin(boxed: Pbox<T, A>) -> Pin<Pbox<T, A>> where
    T: Sized
[src]

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.

Trait Implementations

impl<T: PSafe + ?Sized, A: MemPool> AsRef<T> for Pbox<T, A>[src]

impl<T: PSafe + Debug + ?Sized, A: MemPool> Debug for Pbox<T, A>[src]

impl<T: PSafe + ?Sized, A: MemPool> Deref for Pbox<T, A>[src]

type Target = T

The resulting type after dereferencing.

impl<T: PSafe + ?Sized, A: MemPool> DerefMut for Pbox<T, A>[src]

impl<T: PSafe + Display + ?Sized, A: MemPool> Display for Pbox<T, A>[src]

impl<T: PSafe + ?Sized, A: MemPool> Drop for Pbox<T, A>[src]

impl<T: PSafe + Eq + ?Sized, A: MemPool> Eq for Pbox<T, A>[src]

impl<T: PSafe, A: MemPool> From<Pbox<T, A>> for Pin<Pbox<T, A>>[src]

pub fn from(boxed: Pbox<T, A>) -> Self[src]

Converts a Pbox<T, A> into a Pin<Pbox<T, A>>

This conversion does not allocate on the heap and happens in place.

impl<T: PSafe + Hash + ?Sized, A: MemPool> Hash for Pbox<T, A>[src]

impl<T: PSafe + Hasher + ?Sized, A: MemPool> Hasher for Pbox<T, A>[src]

impl<T: PSafe + Ord + ?Sized, A: MemPool> Ord for Pbox<T, A>[src]

impl<T: PSafe + PClone<A> + ?Sized, A: MemPool> PClone<A> for Pbox<T, A>[src]

pub default fn pclone(&self, journal: &Journal<A>) -> Pbox<T, A>[src]

Returns a new box with a pclone() of this box's contents.

Examples

use crndm::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();

impl<T: PSafe + PartialEq + ?Sized, A: MemPool> PartialEq<Pbox<T, A>> for Pbox<T, A>[src]

impl<T: PSafe + PartialOrd + ?Sized, A: MemPool> PartialOrd<Pbox<T, A>> for Pbox<T, A>[src]

impl<T: Default + PSafe, A: MemPool> RootObj<A> for Pbox<T, A>[src]

impl<T: RootObj<A> + PSafe, A: MemPool> RootObj<A> for Pbox<T, A>[src]

impl<A: MemPool, T: ?Sized> !Send for Pbox<T, A>[src]

impl<T: ?Sized, A: MemPool> !TxOutSafe for Pbox<T, A>[src]

impl<T: PSafe + ?Sized, A: MemPool> Unpin for Pbox<T, A>[src]

impl<A: MemPool, T: ?Sized> !VSafe for Pbox<T, A>[src]

Auto Trait Implementations

impl<T: ?Sized, A> LooseTxInUnsafe for Pbox<T, A> where
    A: LooseTxInUnsafe,
    T: LooseTxInUnsafe
[src]

impl<T: ?Sized, A> PSafe for Pbox<T, A>[src]

impl<T: ?Sized, A> RefUnwindSafe for Pbox<T, A> where
    A: RefUnwindSafe,
    T: RefUnwindSafe
[src]

impl<T, A> !Sync for Pbox<T, A>[src]

impl<T: ?Sized, A> TxInSafe for Pbox<T, A> where
    A: TxInSafe,
    T: TxInSafe
[src]

impl<T: ?Sized, A> UnwindSafe for Pbox<T, A> where
    A: UnwindSafe,
    T: UnwindSafe
[src]

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> ToString for T where
    T: Display + ?Sized
[src]

impl<T, A> ToString<A> for T where
    A: MemPool,
    T: Display + ?Sized
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

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

The type returned in the event of a conversion error.

impl<V, T> VZip<V> for T where
    V: MultiLane<T>,