Struct StackBox

Source
pub struct StackBox<'frame, T: ?Sized + 'frame> { /* private fields */ }
Expand description

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§

Source§

impl<'frame, ImplTrait: 'frame> StackBox<'frame, ImplTrait>

Source

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

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

Source§

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

Source

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

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

use ::stackbox::prelude::*;
let slot = &mut mk_slot();
let arr = slot.stackbox([0, 1, 2]);
let mut slice = arr.into_slice();
assert_eq!(slice.stackbox_pop_first(), Some(0));
Source

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

VecDeque-like behavior for StackBox: pop its last item.

use ::stackbox::prelude::*;
let slot = &mut mk_slot();
let arr = slot.stackbox([0, 1, 2]);
let mut slice = arr.into_slice();
assert_eq!(slice.stackbox_pop_last(), Some(2));
Source

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

StackBox / owned equivalent of the slice splitting methods.

Source§

impl<'frame, Item: 'frame, const N: usize> StackBox<'frame, [Item; N]>

Source

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

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

  • 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_first().unwrap();
Source§

impl<'frame, Item: 'frame> StackBox<'frame, [Item; 1]>

Source

pub fn stackbox_unwrap_1_array( self: StackBox<'frame, [Item; 1]>, ) -> StackBox<'frame, Item>

Convert a StackBox 1-array into a StackBox of its single item.

Source§

impl<'frame, T: 'frame> StackBox<'frame, T>

Source

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

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

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

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({
        /* … */
    });
    // …
}
Source

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

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.

Source§

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

Source

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

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§

Source§

impl<'frame, T: 'frame, U: ?Sized + 'frame> CoerciblePtr<U> for StackBox<'frame, T>

Allows conversion to a StackBox containing an unsized type.

§Usage

use core::fmt::Display;
use unsize::{Coercion, CoerceUnsize};
use stackbox::prelude::*;

let slot = &mut mk_slot();
let num = StackBox::<usize>::new_in(slot, 42);

let display: StackBox<dyn Display> = num.unsize(Coercion::to_display());
Source§

type Pointee = T

The type we point to. This influences which kinds of unsizing are possible.
Source§

type Output = StackBox<'frame, U>

The output type when unsizing the pointee to U.
Source§

fn as_sized_ptr(&mut self) -> *mut T

Get the raw inner pointer.
Source§

unsafe fn replace_ptr(self, new: *mut U) -> StackBox<'frame, U>

Replace the container inner pointer with an unsized version. Read more
Source§

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

Source§

fn default() -> Self

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

impl<'frame, Item: 'frame> Default for StackBox<'frame, [Item; 0]>

Source§

fn default() -> Self

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

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

Source§

type Target = T

The resulting type after dereferencing.
Source§

fn deref(self: &StackBox<'frame, T>) -> &T

Dereferences the value.
Source§

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

Source§

fn deref_mut(self: &mut StackBox<'frame, T>) -> &mut T

Mutably dereferences the value.
Source§

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

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

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

Source§

type IntoIter = Iter<'frame, Item>

Which kind of iterator are we turning this into?
Source§

type Item = Item

The type of the elements being iterated over.
Source§

fn into_iter(self: StackBox<'frame, [Item]>) -> Iter<'frame, Item>

Creates an iterator from a value. Read more
Source§

impl<'frame, Item: 'frame, const N: usize> TryFrom<StackBox<'frame, [Item]>> for StackBox<'frame, [Item; N]>

Source§

type Error = TryFromSliceError<StackBox<'frame, [Item]>>

The type returned in the event of a conversion error.
Source§

fn try_from( stackbox: StackBox<'frame, [Item]>, ) -> Result<StackBox<'frame, [Item; N]>, Self::Error>

Performs the conversion.

Auto Trait Implementations§

§

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

§

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

§

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

§

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

§

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

§

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

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T, U> CoerceUnsize<U> for T
where T: CoerciblePtr<U>, U: ?Sized,

Source§

fn unsize<F>(self, with: Coercion<Self::Pointee, U, F>) -> Self::Output
where F: FnOnce(*const Self::Pointee) -> *const U,

Convert a pointer, as if with unsize coercion. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

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

Source§

impl<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

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

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.