stackbox/stackbox/
mod.rs

1use ::core::mem::ManuallyDrop;
2use crate::{prelude::*,
3    ptr,
4    Slot,
5};
6
7pub
8mod slice;
9
10/// Stack<sup>1</sup>-allocated `Box`. Think of this as of `&'frame mut T`, but
11/// with `move` semantics (no reborrowing!) which allow the "reference" to drop
12/// its pointee.
13///
14/// <small><sup>1</sup> Pedantic nit: actually, it is _local_-allocated: if the
15/// local is created inside a generator such as an `async` block or function,
16/// crossing a `yield` / `.await` point (thus captured by the generator),
17/// and that generator / future is `Box`-ed, then the local will be living on
18/// the heap.</small>
19///
20/// Given the `move` semantics / lack of reborrowing, there may seem to be
21/// little point in using this over the seemingly more flexible
22/// `&'frame mut T`, or the clearly more simple `T`.
23///
24/// And indeed that is mostly true: the usage of this wrapper is a bit _niche_.
25/// Use this wrapper when:
26///
27///  1. You want / _need_ the move semantics (`FnOnce`) ⇒ no `&mut` for you
28///     (assuming `Option::take` is too cumbersome, costly or directly unusable
29///     for your use case).
30///
31///  1. You _need_ the indirection:
32///
33///       - if `T` is big, and you need move semantics, moving `T` around may
34///         be expensive if the compiler is not able to elide the
35///         bitwise-copies (`memcpy`) that happen when the value is moved.
36///
37///       - ### Main usage
38///
39///         If you need a **fat pointer to perform some type erasure**, while
40///         preserving ownership / `move` semantics, and you don't want (or
41///         actually _can't_) use the heap allocation from [`Box`], then this
42///         type is for you!
43///
44/// ### Examples of type erasure
45///
46/// #### 1 - Array to slice coercion and `IntoIter`
47///
48/// `IntoIterator` for ~~arrays~~ slices:
49///
50/// ```rust
51/// # use ::core::mem::drop as stuff;
52/// use ::stackbox::prelude::*;
53///
54/// stackbox!(let boxed_slice: StackBox<'_, [_]> = [
55///     String::from("Hello, "),
56///     String::from("World!"),
57/// ]);
58/// for s in boxed_slice {
59///     println!("{}", s);
60///     stuff::<String>(s);
61/// }
62/// ```
63///
64///   - or with some [`#[with]` sugar:](https://docs.rs/with_locals):
65///
66///     <details>
67///
68///     ```rust
69///     # use ::core::mem::drop as stuff;
70///     use ::stackbox::prelude::*;
71///     use ::with_locals::with;
72///
73///     #[with('local)]
74///     fn main ()
75///     {
76///         let boxed_array: StackBox<'local, [String; 2]> = StackBox::new([
77///             String::from("Hello, "),
78///             String::from("World!"),
79///         ]);
80///         let boxed_slice: StackBox<'_, [String]> = boxed_array.into_slice();
81///         for s in boxed_slice {
82///             println!("{}", s);
83///             stuff::<String>(s);
84///         }
85///     }
86///     ```
87///
88///     ___
89///
90///     </details>
91///
92/// While `&mut [T; N] → &mut [T]` already covers most of the use cases,
93/// imagine needing the `[T]` slice type erasure (_e.g._, an `if` branch which
94/// yields arrays of different lengths) and also needing to have
95/// [`IntoIterator`] available to you. And you don't want to "stupidly" pay a
96/// heap allocation for something that should not deserve one:
97///
98/// ```rust
99/// # use ::core::mem::drop as stuff;
100/// use ::core::mem::ManuallyDrop;
101/// use ::stackbox::prelude::*;
102///
103/// # let some_condition = || true;
104/// mk_slots!(storage1, storage2); // uninit stack allocations.
105/// let boxed_slice_of_strings: StackBox<'_, [String]> =
106///     if some_condition() {
107///         StackBox::new_in(storage1, [
108///             String::from("Hi."),
109///         ])
110///         .into_slice() // [String; 1] → [String]
111///     } else {
112///         // If using the macro, the coercion happens automagically
113///         stackbox!(storage2, [
114///             "Hello, ".into(),
115///             "World!".into(),
116///         ])
117///     }
118/// ;
119/// for s in boxed_slice_of_strings {
120///     println!("{}", s);
121///     stuff::<String>(s);
122/// }
123/// ```
124///
125/// #### 2 - Allocation-less `dyn FnOnce` (and owned `dyn Any`)
126///
127/// See the [dedicated module for more info][`crate::dyn_traits`].
128///
129/// ```rust
130/// use ::stackbox::prelude::*;
131/// # let some_condition = || true;
132///
133/// mk_slots!(f1, f2);
134/// let f: StackBoxDynFnOnce_0<()> = if some_condition() {
135///     f1.stackbox(move || {
136///         // …
137///     }).into_dyn()
138/// } else {
139///     f2.stackbox(move || {
140///         // …
141///     }).into_dyn()
142/// };
143/// // …
144/// f.call();
145/// ```
146    // TYPE INVARIANTS:
147    //   - See the `# Safety` section of [`StackBox::assume_owns`].
148#[repr(transparent)]
149pub
150struct StackBox<'frame, T : ?Sized + 'frame> {
151    /// Covariant and non-null and, ideally, tagged as unaliased.
152    unique_ptr: ptr::Unique<T>,
153    /// Covariant lifetime (this is an `&'frame mut MD<T>`, afterall).
154    _covariant_lt: ::core::marker::PhantomData<&'frame ()>,
155}
156
157impl<'frame, T : 'frame> StackBox<'frame, T> {
158    /// # Main non-`unsafe` non-macro non-callback constructor.
159    ///
160    /// To be used most of the time (when `T : Sized`, and when no implicit
161    /// implicit coercion is needed).
162    ///
163    ///   - Creation of the [`Slot`]s is possible either manually, by binding
164    ///     the return value of [`mk_slot()`] to some variable, by `ref mut`,
165    ///     or if multiple slots are needed, they can be batch created thanks
166    ///     to the [`mk_slots!`] convenience helper macro.
167    ///
168    /// ## Example
169    ///
170    /// ```rust
171    /// use ::stackbox::prelude::*;
172    ///
173    /// let slot = &mut mk_slot();
174    /// let boxed = if true {
175    ///     StackBox::new_in(slot, 42)
176    /// } else {
177    ///     StackBox::new_in(slot, 27)
178    /// };
179    /// assert_eq!(*boxed, 42);
180    /// ```
181    #[inline(always)]
182    pub
183    fn new_in (slot: &'frame mut Slot<T>, value: T)
184      -> StackBox<'frame, T>
185    {
186        slot.stackbox(value)
187    }
188
189    /// Alternative non-`unsafe` non-macro constructor, where instead of an
190    /// explicit [`Slot`] that defines the scope of validity of the
191    /// [`StackBox`] (its stack frame), a callback is used: the `StackBox` is
192    /// valid for the duration of the callback.
193    ///
194    /// ## Example
195    ///
196    /// ```rust
197    /// use ::stackbox::prelude::*;
198    ///
199    /// StackBox::with_new(42, |stackbox: StackBox<'_, i32>| {
200    ///     let any: StackBoxDynAny<'_> = stackbox.into_dyn();
201    ///     assert_eq!(
202    ///         any.downcast_ref::<i32>().unwrap(),
203    ///         &42,
204    ///     );
205    /// }) // <- `StackBox` cannot outlive this point.
206    /// ```
207    ///
208    /// ## Ergonomic usage thanks to `#[::with_locals::with]`
209    ///
210    /// Using this constructor can be made quite ergonomic by using the
211    /// [`#[with]` CPS sugar](https://docs.rs/with_locals):
212    ///
213    /// ```rust
214    /// # macro_rules! ignore {($($t:tt)*) => ()} ignore! {
215    /// use ::stackbox::prelude::*;
216    /// use ::with_locals::with;
217    ///
218    /// #[with]
219    /// fn main ()
220    /// {
221    ///     let stackbox: StackBox<'ref, /* … */> = StackBox::new({
222    ///         /* … */
223    ///     });
224    ///     // …
225    /// }
226    /// # } fn main () {}
227    /// ```
228    #[inline]
229    pub
230    fn with_new<R, F> (value: T, ret: F) -> R
231    where
232        F: for<'local> FnOnce(StackBox<'local, T>) -> R,
233    {
234        ret(StackBox::new_in(&mut mk_slot(), value))
235    }
236
237    /// Unwraps / extracts / moves the pointee out of the [`StackBox`].
238    ///
239    /// ### Note
240    ///
241    /// This lets the used [`Slot`] [vacant][`Slot::VACANT`] again, which can
242    /// thus be reused to create another [`StackBox`].
243    // Note: `self` receiver is fine because there is no `DerefMove` yet.
244    #[inline]
245    pub
246    fn into_inner (self: StackBox<'frame, T>)
247      -> T
248    {
249        unsafe {
250            // Safety: from the type invariant.
251
252            // 1 - Disable the `Drop` glue.
253            let this = ManuallyDrop::new(self);
254            // 2 - We can now *take* the value:
255            ::core::ptr::read::<T>(&**this)
256        }
257    }
258}
259
260impl<'frame, T : ?Sized + 'frame> StackBox<'frame, T> {
261    /// Raw `unsafe` constructor, by taking ownership of a borrowing pointer.
262    ///
263    /// # Safety
264    ///
265    /// This type has ownership of the pointee `T`. This means that despite the
266    /// borrow-looking nature of the `&'frame mut`, the pointee should not be
267    /// used (⇒ not dropped!) once it has been pointed to by a `StackBox` /
268    /// given to this function: the `ManuallyDrop<T>` pointee will represent
269    /// deallocated memory after the `'frame` lifetime!
270    ///
271    /// As a rule of thumb, it is _sound_ to call this function when and only
272    /// when calling [`ManuallyDrop::drop`] is.
273    ///
274    /// When possible (`T : Sized`), prefer to use the non-`unsafe`
275    /// constructors:
276    ///
277    ///   - Either [`StackBox::new_in`] (_e.g._, `Sized` case),
278    ///
279    ///       - (or the [CPS / callback](
280    ///         https://en.wikipedia.org/wiki/Continuation-passing_style)-based
281    ///         [`StackBox::with_new`] constructor).
282    ///
283    ///   - Or the [`stackbox!`] macro, for most usages.
284    #[inline]
285    pub
286    unsafe
287    fn assume_owns (it: &'frame mut ManuallyDrop<T>)
288      -> StackBox<'frame, T>
289    {
290        Self {
291            unique_ptr: ptr::Unique::<T>::from_raw(&mut **it),
292            _covariant_lt: Default::default(),
293        }
294    }
295
296    #[cfg(feature = "unsize")]
297    #[inline]
298    pub(in crate)
299    fn into_inner_unique(self)
300        -> ptr::Unique<T>
301    {
302        let this = ManuallyDrop::new(self);
303        unsafe {
304            // Safety: moving out of this which is not dropped.
305            // This is basically destructuring self which impls `Drop`.
306            ::core::ptr::read(&this.unique_ptr)
307        }
308    }
309}
310
311impl<'frame, T : ?Sized + 'frame>
312    ::core::ops::Deref
313for
314    StackBox<'frame, T>
315{
316    type Target = T;
317
318    #[inline]
319    fn deref (self: &'_ StackBox<'frame, T>)
320      -> &'_ T
321    {
322        &*self.unique_ptr
323    }
324}
325
326impl<'frame, T : ?Sized + 'frame>
327    ::core::ops::DerefMut
328for
329    StackBox<'frame, T>
330{
331    #[inline]
332    fn deref_mut (self: &'_ mut StackBox<'frame, T>)
333      -> &'_ mut T
334    {
335        &mut *self.unique_ptr
336    }
337}
338
339impl<T : ?Sized> Drop for StackBox<'_, T> {
340    #[inline]
341    fn drop (self: &'_ mut Self)
342    {
343        unsafe {
344            // # Safety
345            //
346            //   - From the type invariant
347            ptr::Unique::<T>::drop_in_place(&mut self.unique_ptr)
348        }
349    }
350}
351
352#[cfg(feature = "unsize")]
353/// Allows conversion to a `StackBox` containing an unsized type.
354///
355/// # Usage
356///
357/// ```
358/// use core::fmt::Display;
359/// use unsize::{Coercion, CoerceUnsize};
360/// use stackbox::prelude::*;
361///
362/// let slot = &mut mk_slot();
363/// let num = StackBox::<usize>::new_in(slot, 42);
364///
365/// let display: StackBox<dyn Display> = num.unsize(Coercion::to_display());
366/// ```
367unsafe impl<'frame, T : 'frame, U: ?Sized + 'frame>
368    ::unsize::CoerciblePtr<U>
369for
370    StackBox<'frame, T>
371{
372    type Pointee = T;
373    type Output = StackBox<'frame, U>;
374
375    fn as_sized_ptr(self: &mut Self) -> *mut T {
376        &*self.unique_ptr as *const T as *mut T
377    }
378
379    unsafe fn replace_ptr(self, new: *mut U) -> StackBox<'frame, U> {
380        let _covariant_lt = self._covariant_lt;
381
382        let new_ptr = self
383            .into_inner_unique()
384            .into_raw_nonnull()
385            .as_mut()
386            .replace_ptr(new);
387
388        // Safety: we've forgotten the old pointer and this is the correctly unsized old pointer so
389        // valid for the pointed-to memory.
390        let unique_ptr = ptr::Unique::from_raw(new_ptr);
391
392        StackBox {
393            unique_ptr,
394            _covariant_lt,
395        }
396    }
397}
398
399/// Convenience macro for more ergonomic [`StackBox`] constructions.
400#[macro_export]
401macro_rules! stackbox {
402    (
403        // Same as `StackBox::new_in`, except for it allowing an unsized
404        // coercion to take place.
405        $place:expr,
406        $value:expr $(,)?
407    ) => (match ($place, $value) { (place, value) => {
408        let ptr = $crate::Slot::__init_raw(place, value);
409        unsafe {
410            let _ = $crate::__::concat!(
411                "Safety: `", stringify!($place), "` has just been initialized",
412            );
413            $crate::StackBox::assume_owns(ptr)
414        }
415    }});
416
417    (
418        // Create a new `mut` `StackBox` without mentioning the backing _slot_:
419        // `let mut <binding> = stackbox!($expr);`
420        // Examples:
421        //   - `stackbox!(let mut new_var = <expr>);`
422        //   - `stackbox!(let mut new_var: StackBox<[_]> = <array expr>);`
423        let mut $var:ident $(: $T:ty)? = $expr:expr
424    ) => (
425        $crate::stackbox!($expr => let mut $var $(: $T)?)
426    );
427
428    (
429        // Create a new `StackBox` without mentioning the backing _slot_:
430        // `let <binding> = stackbox!($expr);`
431        // Examples:
432        //   - `stackbox!(let new_var = <expr>);`
433        //   - `stackbox!(let new_var: StackBox<[_]> = <array expr>);`
434        let $var:ident $(: $T:ty)? = $expr:expr
435    ) => (
436        $crate::stackbox!($expr => let $var $(: $T)?)
437    );
438
439    (
440        // Internal-ish: assign the result of a `stackbox!($expr)` to "some place"
441        // where "some place" may be a new `let` binding or an actual assignment.
442        //
443        // No need to explicitly mention the backing _slot_ either.
444        // Examples:
445        //   - `let var: Ty; stackbox!(<expr> => var);`
446        $expr:expr => $($binding:tt)*
447    ) => (
448        let ref mut ptr = $crate::__::ManuallyDrop::new($expr);
449        $($binding)* = unsafe { $crate::StackBox::assume_owns(ptr) };
450    );
451
452    (
453        // Shorthand for `stackbox!(let mut $var = $var)`
454        let mut $var:ident
455    ) => (
456        $crate::stackbox!(let mut $var = $var)
457    );
458
459    (
460        // Shorthand for `stackbox!(let $var = $var)`
461        let $var:ident
462    ) => (
463        $crate::stackbox!(let $var = $var)
464    );
465
466    (
467        // To be used as a temporary fed to a function parameter, or as a
468        // `[::with_locals::with]` "return" value.
469        //
470        // Examples:
471        //   - `fun(stackbox!(value))`
472        $expr:expr
473    ) => (
474        match &mut $crate::__::ManuallyDrop::new($expr) { ptr => {
475            #[allow(unused_unsafe)] {
476                unsafe {
477                    // Safety: anonymous temporary is unusable
478                    $crate::StackBox::assume_owns(ptr)
479                }
480            }
481        }}
482    );
483}