Struct stackbox::StackBox [−][src]
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:
-
You want / need the move semantics (
FnOnce
) ⇒ no&mut
for you (assumingOption::take
is too cumbersome, costly or directly unusable for your use case). -
You need the indirection:
-
if
T
is big, and you need move semantics, movingT
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 fromBox
, 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]
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.
impl<'frame, Item: 'frame> StackBox<'frame, [Item]>
[src]
pub fn stackbox_pop(self: &mut StackBox<'frame, [Item]>) -> Option<Item>
[src]
pub fn stackbox_split_at(
self: StackBox<'frame, [Item]>,
mid: usize
) -> (StackBox<'frame, [Item]>, StackBox<'frame, [Item]>)
[src]
self: StackBox<'frame, [Item]>,
mid: usize
) -> (StackBox<'frame, [Item]>, StackBox<'frame, [Item]>)
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]
self: StackBox<'frame, Array>
) -> StackBox<'frame, [Array::Item]>
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 to4096
; -
some other psychological numbers (some multiples of 25, 50 or 100).
-
-
Note that you may not need to use
.into_slice()
if instead ofStackBox::new_in
you usestackbox!
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
Slot
s is possible either manually, by binding the return value ofmk_slot()
to some variable, byref mut
, or if multiple slots are needed, they can be batch created thanks to themk_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]
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({ /* … */ }); // … }
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]
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:
-
Either
StackBox::new_in
(e.g.,Sized
case),- (or the CPS / callback-based
StackBox::with_new
constructor).
- (or the CPS / callback-based
-
Or the
stackbox!
macro, for most usages.
Trait Implementations
impl<'frame, T: ?Sized + 'frame> Deref for StackBox<'frame, T>
[src]
type Target = T
The resulting type after dereferencing.
fn deref(self: &StackBox<'frame, T>) -> &T
[src]
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]
Auto Trait Implementations
impl<'frame, T: ?Sized> RefUnwindSafe for StackBox<'frame, T> where
T: RefUnwindSafe,
T: RefUnwindSafe,
impl<'frame, T: ?Sized> Send for StackBox<'frame, T> where
T: Send,
T: Send,
impl<'frame, T: ?Sized> Sync for StackBox<'frame, T> where
T: Sync,
T: Sync,
impl<'frame, T: ?Sized> Unpin for StackBox<'frame, T>
impl<'frame, T: ?Sized> UnwindSafe for StackBox<'frame, T> where
T: UnwindSafe,
T: UnwindSafe,
Blanket Implementations
impl<T> Any for T where
T: 'static + ?Sized,
[src]
T: 'static + ?Sized,
impl<T> Borrow<T> for T where
T: ?Sized,
[src]
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]
T: ?Sized,
pub fn borrow_mut(&mut self) -> &mut T
[src]
impl<T> From<T> for T
[src]
impl<T, U> Into<U> for T where
U: From<T>,
[src]
U: From<T>,
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]
U: Into<T>,
type Error = Infallible
The type returned in the event of a conversion error.
pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]
impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]
U: TryFrom<T>,