Struct stackbox::StackBox[][src]

#[repr(transparent)]pub struct StackBox<'frame, T: ?Sized + 'frame> { /* fields omitted */ }

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, crossing a yield / .await point (thus captured by the generator), 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!(let boxed_slice: StackBox<'_, [_]> = [
    String::from("Hello, "),
    String::from("World!"),
]);
for s in boxed_slice {
    println!("{}", s);
    stuff::<String>(s);
}
  • or with some #[with] sugar::

    use ::stackbox::prelude::*;
    use ::with_locals::with;
    
    #[with('local)]
    fn main ()
    {
        let boxed_array: StackBox<'local, [String; 2]> = StackBox::new([
            String::from("Hello, "),
            String::from("World!"),
        ]);
        let boxed_slice: StackBox<'_, [String]> = boxed_array.into_slice();
        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::*;

mk_slots!(storage1, storage2); // uninit stack allocations.
let boxed_slice_of_strings: StackBox<'_, [String]> =
    if some_condition() {
        StackBox::new_in(storage1, [
            String::from("Hi."),
        ])
        .into_slice() // [String; 1] → [String]
    } else {
        // If using the macro, the coercion happens automagically
        stackbox!(storage2, [
            "Hello, ".into(),
            "World!".into(),
        ])
    }
;
for s in boxed_slice_of_strings {
    println!("{}", s);
    stuff::<String>(s);
}

2 - Allocation-less dyn FnOnce (and owned dyn Any)

See the dedicated module for more info.

use ::stackbox::prelude::*;

mk_slots!(f1, f2);
let f: StackBoxDynFnOnce_0<()> = if some_condition() {
    f1.stackbox(move || {
        // …
    }).into_dyn()
} else {
    f2.stackbox(move || {
        // …
    }).into_dyn()
};
// …
f.call();

Implementations

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

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

Coerces a StackBox<impl Trait> into a StackBox<dyn Trait>, provided the Trait is one of the supported ones.

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

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

Vec-like behavior for StackBox: pop its first item.

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

StackBox / owned equivalent of the slice splitting methods.

impl<'frame, Array: IsArray<'frame>> StackBox<'frame, Array>[src]

Array = [Array::Item; N].

pub fn into_slice(
    self: StackBox<'frame, Array>
) -> StackBox<'frame, [Array::Item]>
[src]

Coerces a StackBox<[T; N]> into a StackBox<[T; N].

Requirements

  • Either the "const-generics" feature needs to be enabled,

  • Or N must be one of the hard-coded ones:

    • a power of 2 up to 4096;

    • some other psychological numbers (some multiples of 25, 50 or 100).

  • Note that you may not need to use .into_slice() if instead of StackBox::new_in you use stackbox! to construct it:

    use ::stackbox::prelude::*;
    
    mk_slots!(slot);
    //      boxed_slice: StackBox<'_, [String]> = StackBox::new_in(slot, [
    let mut boxed_slice: StackBox<'_, [String]> = stackbox!(slot, [
        "Hello, World!".into()
    ]);
    let _: String = boxed_slice.stackbox_pop().unwrap();

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

pub fn new_in(slot: &'frame mut Slot<T>, value: T) -> StackBox<'frame, T>[src]

Main non-unsafe non-macro non-callback constructor.

To be used most of the time (when T : Sized, and when no implicit implicit coercion is needed).

  • Creation of the Slots is possible either manually, by binding the return value of mk_slot() to some variable, by ref mut, or if multiple slots are needed, they can be batch created thanks to the mk_slots! convenience helper macro.

Example

use ::stackbox::prelude::*;

let slot = &mut mk_slot();
let boxed = if true {
    StackBox::new_in(slot, 42)
} else {
    StackBox::new_in(slot, 27)
};
assert_eq!(*boxed, 42);

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

Alternative non-unsafe non-macro constructor, where instead of an explicit Slot that defines the scope of validity of the StackBox (its stack frame), a callback is used: the StackBox is valid for the duration of the callback.

Example

use ::stackbox::prelude::*;

StackBox::with_new(42, |stackbox: StackBox<'_, i32>| {
    let any: StackBoxDynAny<'_> = stackbox.into_dyn();
    assert_eq!(
        any.downcast_ref::<i32>().unwrap(),
        &42,
    );
}) // <- `StackBox` cannot outlive this point.

Ergonomic usage thanks to #[::with_locals::with]

Using this constructor can be made quite ergonomic by 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]

Unwraps / extracts / moves the pointee out of the StackBox.

Note

This lets the used Slot vacant again, which can thus be reused to create another StackBox.

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

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

Raw unsafe constructor, by taking ownership of a borrowing pointer.

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:

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: ?Sized> UnwindSafe for StackBox<'frame, T> where
    T: UnwindSafe

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, 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.