stackbox/
slot.rs

1use crate::prelude::*;
2
3use ::core::{
4    // marker::PhantomData,
5    mem,
6};
7
8/// Same as [`Slot::VACANT`], but using function call syntax to avoid firing
9/// the [trigger-happy `const_item_mutation` lint](
10/// https://github.com/rust-lang/rust/pull/75573).
11///
12/// A so-created `&mut Slot<T>` is then to be used to derive a
13/// [`StackBox`]`<'slot, T>` out of it, by feeding a value to the slot:
14///
15///   - either by using [`StackBox::new_in()`],
16///
17///   - or the equivalent [`.stackbox()`] convenience method on [`Slot`]s.
18///
19/// [`.stackbox()`]: `Slot::stackbox`
20#[inline(always)]
21pub
22const
23fn mk_slot<T> ()
24  -> Slot<T>
25{
26    Slot::VACANT
27}
28
29/// A `Sized` and [`uninit`][`::core::mem::MaybeUninit`] slot to
30/// manually handle the scope of [`StackBox`]'s backing inline allocations.
31///
32/// If needed, multiple such slots can be defined within the local scope and
33/// bound to a variadic number of identifiers (variable names) using the
34/// [`mk_slots!`][`crate::mk_slots`] macro.
35pub
36struct Slot<T> {
37    place: mem::MaybeUninit<T>,
38    // /// Invariant lifetime just in case.
39    // _borrow_mut_once: PhantomData<fn(&()) -> &mut &'frame ()>,
40}
41
42impl<T> Slot<T> {
43    /// A vacant slot, to be used to derive a [`StackBox`]`<'slot, T>` out of
44    /// it, by feeding a value to the slot:
45    ///
46    ///   - either by using [`StackBox::new_in()`],
47    ///
48    ///   - or the equivalent [`.stackbox()`] convenience method on [`Slot`]s.
49    ///
50    /// [`.stackbox()`]: `Slot::stackbox`
51    pub
52    const VACANT: Self = Slot {
53        place: mem::MaybeUninit::uninit(),
54        // _borrow_mut_once: PhantomData,
55    };
56
57    /// Convenience shortcut for [`StackBox::new_in()`].
58    #[inline(always)]
59    pub
60    fn stackbox<'frame> (self: &'frame mut Slot<T>, value: T)
61      -> StackBox<'frame, T>
62    where
63        T : 'frame,
64    {
65        let ptr = Self::__init_raw(self, value);
66        unsafe {
67            // Safety: `mem::MaybeUninit` does not drop it.
68            StackBox::assume_owns(ptr)
69        }
70    }
71
72    #[doc(hidden)] /** Not part of the public API */ pub
73    fn __init_raw<'frame> (this: &'frame mut Slot<T>, value: T)
74      -> &'frame mut ::core::mem::ManuallyDrop<T>
75    {
76        this.place = mem::MaybeUninit::new(value);
77        unsafe {
78            // Safety: value has been initialized.
79            mem::transmute::<
80                &'_ mut mem::MaybeUninit<T>,
81                &'_ mut mem::ManuallyDrop<T>,
82            >(
83                &mut this.place,
84            )
85        }
86    }
87}
88
89/// Convenience macro to batch-create multiple [`Slot`]s.
90///
91/// ```rust
92/// # use ::stackbox::prelude::*;
93/// mk_slots!(foo, bar, baz);
94/// # drop::<[&mut ::stackbox::Slot<()>; 3]>([foo, bar, baz]);
95/// ```
96///
97/// is a shorthand for multiple [`mk_slot()`][`mk_slot`] calls:
98///
99/// ```rust
100/// # use ::stackbox::prelude::*;
101/// let foo = &mut mk_slot();
102/// let bar = &mut mk_slot();
103/// let baz = &mut mk_slot();
104/// # drop::<[&mut ::stackbox::Slot<()>; 3]>([foo, bar, baz]);
105/// ```
106///
107/// A so-created `&mut Slot<T>` is then to be used to derive a
108/// [`StackBox`]`<'slot, T>` out of it, by feeding a value to the slot:
109///
110///   - either by using [`StackBox::new_in()`],
111///
112///   - or the equivalent [`.stackbox()`] convenience method on [`Slot`]s.
113///
114/// [`.stackbox()`]: `Slot::stackbox`
115#[macro_export]
116macro_rules! mk_slots {(
117    $($var_name:ident),+ $(,)?
118) => (
119    $(
120        let ref mut $var_name = $crate::prelude::mk_slot();
121    )+
122)}