pub struct QCellOwnerPinned { /* private fields */ }
Expand description

Borrowing-owner of zero or more QCell instances, based on a pinned struct

This type uses its own memory address to provide a unique owner ID, which requires no allocations and only 2 bytes of storage. So this is suitable for a no_std environment without an allocator. The owner can be created on the stack, or on the heap, as required. To ensure its memory address cannot change while cells exist that are owned by it, it requires itself to be pinned before any operation interacting with the ID is attempted.

There are many ways to safely pin a value, such as Box::pin, pin-utils::pin_mut!, tokio::pin!, or the pin-project crate.

The following example uses the pin_mut! macro from the pin-utils crate:

use pin_utils::pin_mut;
use qcell::{QCell, QCellOwnerPinned};
let mut owner = QCellOwnerPinned::new();
pin_mut!(owner);
let item = Rc::new(owner.as_ref().cell(Vec::<u8>::new()));
owner.as_mut().rw(&item).push(1);
test(owner, &item);

fn test(owner: Pin<&mut QCellOwnerPinned>, item: &Rc<QCell<Vec<u8>>>) {
    owner.rw(&item).push(2);
}

This example incorporates the QCellOwnerPinned into a larger structure kept on the stack, and accesses it using the pin-project crate:

use crate::qcell::{QCell, QCellOwnerPinned};
use pin_project::pin_project;
use pin_utils::pin_mut;

#[pin_project]
struct MyStruct {
    _misc: usize,  // Unpinned value
    #[pin]
    owner: QCellOwnerPinned,
}

let mystruct = MyStruct {
    _misc: 0,
    owner: QCellOwnerPinned::new(),
};

pin_mut!(mystruct);

let item = Rc::new(
    mystruct.as_mut().project().owner.as_ref().cell(Vec::<u8>::new())
);
mystruct.as_mut().project().owner.rw(&item).push(1);
test(mystruct.as_mut().project().owner, &item);

fn test(owner: Pin<&mut QCellOwnerPinned>, item: &Rc<QCell<Vec<u8>>>) {
    owner.rw(&item).push(2);
}

Safety

After the owner is pinned, its address is used as a temporally unique ID. This detects use of the wrong owner to access a cell at runtime, which is a programming error.

Note that even without Pin, this would still be sound, because there would still be only one owner valid at any one time with the same ID, because two owners cannot occupy the same memory. However Pin is useful because it helps the coder avoid accidentally moving an owner from one address to another without realizing it, and causing panics due to the changed owner ID.

The ID generated from this type cannot clash with IDs generated by QCellOwner (which is also based on the addresses of occupied memory, but always on the heap), or QCellOwnerSeq (which only allocates odd IDs, which cannot clash with addresses from this type which always have an alignment of 2). So this should successfully defend against all malicious and unsafe use. If not, please raise an issue.

The same unique ID may later be allocated to someone else once you drop the returned owner, but this cannot be abused to cause unsafe access to cells because there will still be only one owner active at any one time with that ID. Also it cannot be used maliciously to access cells which don’t belong to the new caller, because you also need a reference to the cells. So for example if you have a graph of cells that is only accessible through a private structure, then someone else getting the same owner ID makes no difference, because they have no way to get a reference to those cells. In any case, you are probably going to drop all those cells at the same time as dropping the owner, because they are no longer of any use without the owner ID.

Implementations

Create an owner that can be used for creating many QCell instances.

Get the internal owner ID. This may be used to create QCell instances without needing a borrow on this structure, which is useful if this structure is already borrowed.

Requires this owner to be pinned before use.

Create a new cell owned by this owner instance.

Requires this owner to be pinned before use.

Borrow contents of a QCell immutably (read-only). Many QCell instances can be borrowed immutably at the same time from the same owner. Panics if the QCell is not owned by this QCellOwnerPinned.

Requires this owner to be pinned before use.

Borrow contents of a QCell mutably (read-write). Only one QCell at a time can be borrowed from the owner using this call. The returned reference must go out of scope before another can be borrowed. Panics if the QCell is not owned by this QCellOwnerPinned.

Requires this owner to be pinned before use.

Borrow contents of two QCell instances mutably. Panics if the two QCell instances point to the same memory. Panics if either QCell is not owned by this QCellOwnerPinned.

Requires this owner to be pinned before use.

Borrow contents of three QCell instances mutably. Panics if any pair of QCell instances point to the same memory. Panics if any QCell is not owned by this QCellOwnerPinned.

Requires this owner to be pinned before use.

Trait Implementations

Returns the “default value” for a type. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

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

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.