1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422
use ::core::mem::ManuallyDrop; use crate::{prelude::*, ptr, Slot, }; pub use slice::iter; mod slice; /// Stack<sup>1</sup>-allocated `Box`. Think of this as of `&'frame mut T`, but /// with `move` semantics (no reborrowing!) which allow the "reference" to drop /// its pointee. /// /// <small><sup>1</sup> 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.</small> /// /// 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). /// /// 1. 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: /// /// ```rust /// # use ::core::mem::drop as stuff; /// 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:](https://docs.rs/with_locals): /// /// <details> /// /// ```rust /// # use ::core::mem::drop as stuff; /// 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); /// } /// } /// ``` /// /// ___ /// /// </details> /// /// 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: /// /// ```rust /// # use ::core::mem::drop as stuff; /// use ::core::mem::ManuallyDrop; /// use ::stackbox::prelude::*; /// /// # let some_condition = || true; /// 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][`crate::dyn_traits`]. /// /// ```rust /// use ::stackbox::prelude::*; /// # let some_condition = || true; /// /// mk_slots!(f1, f2); /// let f: StackBoxDynFnOnce_0<()> = if some_condition() { /// f1.stackbox(move || { /// // … /// }).into_dyn() /// } else { /// f2.stackbox(move || { /// // … /// }).into_dyn() /// }; /// // … /// f.call(); /// ``` // TYPE INVARIANTS: // - See the `# Safety` section of [`StackBox::assume_owns`]. #[repr(transparent)] pub struct StackBox<'frame, T : ?Sized + 'frame> { /// Covariant and non-null and, ideally, tagged as unaliased. unique_ptr: ptr::Unique<T>, /// Covariant lifetime (this is an `&'frame mut MD<T>`, afterall). _covariant_lt: ::core::marker::PhantomData<&'frame ()>, } impl<'frame, T : 'frame> 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 [`Slot`]s 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 /// /// ```rust /// 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); /// ``` #[inline(always)] pub fn new_in (slot: &'frame mut Slot<T>, value: T) -> StackBox<'frame, T> { slot.stackbox(value) } /// 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 /// /// ```rust /// 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](https://docs.rs/with_locals): /// /// ```rust /// # macro_rules! ignore {($($t:tt)*) => ()} ignore! { /// use ::stackbox::prelude::*; /// use ::with_locals::with; /// /// #[with] /// fn main () /// { /// let stackbox: StackBox<'ref, /* … */> = StackBox::new({ /// /* … */ /// }); /// // … /// } /// # } fn main () {} /// ``` #[inline] pub fn with_new<R, F> (value: T, ret: F) -> R where F: for<'local> FnOnce(StackBox<'local, T>) -> R, { ret(StackBox::new_in(&mut mk_slot(), value)) } /// Unwraps / extracts / moves the pointee out of the [`StackBox`]. /// /// ### Note /// /// This lets the used [`Slot`] [vacant][`Slot::VACANT`] again, which can /// thus be reused to create another [`StackBox`]. // Note: `self` receiver is fine because there is no `DerefMove` yet. #[inline] pub fn into_inner (self: StackBox<'frame, T>) -> T { unsafe { // Safety: from the type invariant. // 1 - Disable the `Drop` glue. let this = ManuallyDrop::new(self); // 2 - We can now *take* the value: ::core::ptr::read::<T>(&**this) } } } impl<'frame, T : ?Sized + 'frame> 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]( /// https://en.wikipedia.org/wiki/Continuation-passing_style)-based /// [`StackBox::with_new`] constructor). /// /// - Or the [`stackbox!`] macro, for most usages. #[inline] pub unsafe fn assume_owns (it: &'frame mut ManuallyDrop<T>) -> StackBox<'frame, T> { Self { unique_ptr: ptr::Unique::<T>::from_raw(&mut **it), _covariant_lt: Default::default(), } } } impl<'frame, T : ?Sized + 'frame> ::core::ops::Deref for StackBox<'frame, T> { type Target = T; #[inline] fn deref (self: &'_ StackBox<'frame, T>) -> &'_ T { &*self.unique_ptr } } impl<'frame, T : ?Sized + 'frame> ::core::ops::DerefMut for StackBox<'frame, T> { #[inline] fn deref_mut (self: &'_ mut StackBox<'frame, T>) -> &'_ mut T { &mut *self.unique_ptr } } impl<T : ?Sized> Drop for StackBox<'_, T> { #[inline] fn drop (self: &'_ mut Self) { unsafe { // # Safety // // - From the type invariant ptr::Unique::<T>::drop_in_place(&mut self.unique_ptr) } } } /// Convenience macro for more ergonomic [`StackBox`] constructions. #[macro_export] macro_rules! stackbox { ( // Same as `StackBox::new_in`, except for it allowing an unsized // coercion to take place. $place:expr, $value:expr $(,)? ) => (match ($place, $value) { (place, value) => { let ptr = $crate::Slot::__init_raw(place, value); unsafe { let _ = $crate::__::concat!( "Safety: `", stringify!($place), "` has just been initialized", ); $crate::StackBox::assume_owns(ptr) } }}); ( // Create a new `mut` `StackBox` without mentioning the backing _slot_: // `let mut <binding> = stackbox!($expr);` // Examples: // - `stackbox!(let mut new_var = <expr>);` // - `stackbox!(let mut new_var: StackBox<[_]> = <array expr>);` let mut $var:ident $(: $T:ty)? = $expr:expr ) => ( $crate::stackbox!($expr => let mut $var $(: $T)?) ); ( // Create a new `StackBox` without mentioning the backing _slot_: // `let <binding> = stackbox!($expr);` // Examples: // - `stackbox!(let new_var = <expr>);` // - `stackbox!(let new_var: StackBox<[_]> = <array expr>);` let $var:ident $(: $T:ty)? = $expr:expr ) => ( $crate::stackbox!($expr => let $var $(: $T)?) ); ( // Internal-ish: assign the result of a `stackbox!($expr)` to "some place" // where "some place" may be a new `let` binding or an actual assignment. // // No need to explicitly mention the backing _slot_ either. // Examples: // - `let var: Ty; stackbox!(<expr> => var);` $expr:expr => $($binding:tt)* ) => ( let ref mut ptr = $crate::__::ManuallyDrop::new($expr); $($binding)* = unsafe { $crate::StackBox::assume_owns(ptr) }; ); ( // Shorthand for `stackbox!(let mut $var = $var)` let mut $var:ident ) => ( $crate::stackbox!(let mut $var = $var) ); ( // Shorthand for `stackbox!(let $var = $var)` let $var:ident ) => ( $crate::stackbox!(let $var = $var) ); ( // To be used as a temporary fed to a function parameter, or as a // `[::with_locals::with]` "return" value. // // Examples: // - `fun(stackbox!(value))` $expr:expr ) => ( match &mut $crate::__::ManuallyDrop::new($expr) { ptr => { #[allow(unused_unsafe)] { unsafe { // Safety: anonymous temporary is unusable $crate::StackBox::assume_owns(ptr) } } }} ); }