[][src]Struct stackbox::StackBox

#[repr(transparent)]pub struct StackBox<'frame, T: ?Sized + 'frame>(_);

Stack1-allocated Box. Think of this as of &'frame mut T, but with move semantics (no reborrowing!) which allow the "reference" to drop its pointee.

1 Pedantic nit: actually, it is local-allocated: if the local is created inside a generator such as an async block or function, and that generator / future is Box-ed, then the local will be living on the heap.

Given the move semantics / lack of reborrowing, there may seem to be little point in using this over the seemingly more flexible &'frame mut T, or the clearly more simple T.

And indeed that is mostly true: the usage of this wrapper is a bit niche. Use this wrapper when:

  1. You want / need the move semantics (FnOnce) ⇒ no &mut for you (assuming Option::take is too cumbersome, costly or directly unusable for your use case).

  2. You need the indirection:

    • if T is big, and you need move semantics, moving T around may be expensive if the compiler is not able to elide the bitwise-copies (memcpy) that happen when the value is moved.

    • Main usage

      If you need a fat pointer to perform some type erasure, while preserving ownership / move semantics, and you don't want (or actually can't) use the heap allocation from Box, then this type is for you!

Examples of type erasure

1 - Array to slice coercion and IntoIter

IntoIterator for arrays slices:

use ::stackbox::prelude::*;

stackbox!([
    String::from("Hello, "),
    String::from("World!"),
] => let boxed_slice: StackBox<'_, [_]>);
for s in boxed_slice {
    println!("{}", s);
    stuff::<String>(s);
}

While &mut [T; N] → &mut [T] already covers most of the use cases, imagine needing the [T] slice type erasure (e.g., an if branch which yields arrays of different lengths) and also needing to have IntoIterator available to you. And you don't want to "stupidly" pay a heap allocation for something that should not deserve one:

use ::core::mem::ManuallyDrop;
use ::stackbox::prelude::*;

let mut storage = (None, None);
let boxed_slice_of_strings: StackBox<'_, [String]> =
    if some_condition() {
        let p0 = storage.0.get_or_insert(ManuallyDrop::<[String; 1]>::new([
            "Hi.".into(),
        ]));
        unsafe {
            // Safety: nobody else may free `storage.0`
            StackBox::assume_owns(p0)
        }
    } else {
        let p1 = storage.1.get_or_insert(ManuallyDrop::<[String; 2]>::new([
            "Hello, ".into(),
            "World!".into(),
        ]));
        unsafe {
            // Safety: nobody else may free `storage.0`
            StackBox::assume_owns(p1)
        }
    }
;
for s in boxed_slice_of_strings {
    println!("{}", s);
    stuff::<String>(s);
}

Implementations

impl<'frame, ImplTrait: 'frame> StackBox<'frame, ImplTrait>[src]

pub fn coerce_into_dyn<StackBoxDynTrait>(
    self: StackBox<'frame, ImplTrait>
) -> StackBoxDynTrait where
    StackBoxDynTrait: DynCoerce<StackBox<'frame, ImplTrait>>, 
[src]

impl<'frame, T: 'frame> StackBox<'frame, T>[src]

pub fn with_new<R, F>(value: T, ret: F) -> R where
    F: for<'local> FnOnce(StackBox<'local, T>) -> R, 
[src]

#[::with_locals::with]

Using this constructor can be made quite ergonomic if using the #[with] CPS sugar:

use ::stackbox::prelude::*;
use ::with_locals::with;

#[with]
fn main ()
{
    let stackbox: StackBox<'ref, /* … */> = StackBox::new({
        /* … */
    });
    // …
}

pub fn into_inner(self: StackBox<'frame, T>) -> T[src]

impl<'frame, T: ?Sized + 'frame> StackBox<'frame, T>[src]

pub unsafe fn assume_owns(
    it: &'frame mut ManuallyDrop<T>
) -> StackBox<'frame, T>
[src]

Safety

This type has ownership of the pointee T. This means that despite the borrow-looking nature of the &'frame mut, the pointee should not be used (⇒ not dropped!) once it has been pointed to by a StackBox / given to this function: the ManuallyDrop<T> pointee will represent deallocated memory after the 'frame lifetime!

As a rule of thumb, it is sound to call this function when and only when calling ManuallyDrop::drop is.

When possible (T : Sized), prefer to use the non-unsafe constructors:

impl<'frame, Item: 'frame> StackBox<'frame, [Item]>[src]

pub fn stackbox_split_at(
    self: StackBox<'frame, [Item]>,
    mid: usize
) -> (StackBox<'frame, [Item]>, StackBox<'frame, [Item]>)
[src]

pub fn stackbox_pop(self: &mut StackBox<'frame, [Item]>) -> Option<Item>[src]

Trait Implementations

impl<'frame, T: ?Sized + 'frame> Deref for StackBox<'frame, T>[src]

type Target = T

The resulting type after dereferencing.

impl<'frame, T: ?Sized + 'frame> DerefMut for StackBox<'frame, T>[src]

impl<T: ?Sized, '_> Drop for StackBox<'_, T>[src]

impl<'frame, Item: 'frame> IntoIterator for StackBox<'frame, [Item]>[src]

type IntoIter = Iter<'frame, Item>

Which kind of iterator are we turning this into?

type Item = Item

The type of the elements being iterated over.

Auto Trait Implementations

impl<'frame, T: ?Sized> RefUnwindSafe for StackBox<'frame, T> where
    T: RefUnwindSafe

impl<'frame, T: ?Sized> Send for StackBox<'frame, T> where
    T: Send

impl<'frame, T: ?Sized> Sync for StackBox<'frame, T> where
    T: Sync

impl<'frame, T: ?Sized> Unpin for StackBox<'frame, T>

impl<'frame, T> !UnwindSafe for StackBox<'frame, T>

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<I> IntoIterator for I where
    I: Iterator
[src]

type Item = <I as Iterator>::Item

The type of the elements being iterated over.

type IntoIter = I

Which kind of iterator are we turning this into?

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.