| // Copyright 2021 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| //! Move references. |
| //! |
| //! A move reference represents an owned value that is stored "somewhere else". |
| //! We own the value, not the storage. |
| //! |
| //! A [`MoveRef<'a, T>`] represents a *permanent* unique reference to `T` for |
| //! the lifetime `'a`: it is the longest-lived *possible* reference to the |
| //! pointee, making it closer to a [`Box<T>`] |
| //! |
| //! Like [`&mut T`] but unlike [`Box<T>`], a [`MoveRef<T>`] is not responsible |
| //! for destroying its storage, meaning that it is storage agnostic. The storage |
| //! might be on the stack *or* on the heap; some RAII value on the stack is |
| //! responsible for destroying just the storage, once the [`MoveRef<T>`] itself |
| //! is gone. |
| //! |
| //! The main mechanism for obtaining [`MoveRef`]s is the [`moveit!()`] macro, |
| //! which is analogous to a theoretical `&move expr` operator. This macro |
| //! wraps [`DerefMove`], much like `&mut expr` wraps [`DerefMut`]. |
| //! |
| //! Implementing [`DerefMove`] is a delicate affair; its documentation details |
| //! exactly how it should be done. |
| //! |
| //! # Drop Flags |
| //! |
| //! In order to be sound, a `MoveRef` must also hold a pointer to a drop flag, |
| //! which is used to detect if the `MoveRef` was dropped without destruction. |
| //! |
| //! In general, [`mem::forget`]ing a `MoveRef` is a very, very bad idea. In the |
| //! best case it will leak memory, but in some cases will crash the program in |
| //! order to observe safety guarantees. |
| |
| use core::mem; |
| use core::ops::Deref; |
| use core::ops::DerefMut; |
| use core::pin::Pin; |
| use core::ptr; |
| |
| #[cfg(doc)] |
| use { |
| crate::{drop_flag, moveit}, |
| alloc::{boxed::Box, rc::Rc, sync::Arc}, |
| core::mem::{ManuallyDrop, MaybeUninit}, |
| }; |
| |
| use crate::drop_flag::DropFlag; |
| use crate::slot::DroppingSlot; |
| |
| /// A `MoveRef<'a, T>` represents an owned `T` whose storage location is valid |
| /// but unspecified. |
| /// |
| /// See [the module documentation][self] for more details. |
| pub struct MoveRef<'a, T: ?Sized> { |
| ptr: &'a mut T, |
| drop_flag: DropFlag<'a>, |
| } |
| |
| impl<'a, T: ?Sized> MoveRef<'a, T> { |
| /// Creates a new `MoveRef<T>` out of a mutable reference. |
| /// |
| /// # Safety |
| /// |
| /// `ptr` must satisfy the *longest-lived* criterion: after the return value |
| /// goes out of scope, `ptr` must also be out-of-scope. Calling this function |
| /// correctly is non-trivial, and should be left to [`moveit!()`] instead. |
| /// |
| /// In particular, if `ptr` outlives the returned `MoveRef`, it will point |
| /// to dropped memory, which is UB. |
| /// |
| /// `drop_flag`'s value must not be dead, and must be a drop flag governing |
| /// the destruction of `ptr`'s storage in an appropriate manner as described |
| /// in [`moveit::drop_flag`][crate::drop_flag]. |
| #[inline] |
| pub unsafe fn new_unchecked(ptr: &'a mut T, drop_flag: DropFlag<'a>) -> Self { |
| Self { ptr, drop_flag } |
| } |
| |
| /// Converts a `MoveRef<T>` into a `Pin<MoveRef<T>>`. |
| /// |
| /// Because we own the referent, we are entitled to pin it permanently. See |
| /// [`Box::into_pin()`] for a standard-library equivalent. |
| #[inline] |
| pub fn into_pin(this: Self) -> Pin<Self> { |
| unsafe { Pin::new_unchecked(this) } |
| } |
| |
| /// Returns this `MoveRef<T>` as a raw pointer, without creating an |
| /// intermediate reference. |
| /// |
| /// The usual caveats for casting a reference to a pointer apply. |
| #[inline] |
| pub fn as_ptr(this: &Self) -> *const T { |
| this.ptr |
| } |
| |
| /// Returns this `MoveRef<T>` as a raw mutable pointer, without creating an |
| /// intermediate reference. |
| /// |
| /// The usual caveats for casting a reference to a pointer apply. |
| #[inline] |
| pub fn as_mut_ptr(this: &mut Self) -> *mut T { |
| this.ptr |
| } |
| |
| #[allow(unused)] |
| pub(crate) fn drop_flag(this: &Self) -> DropFlag<'a> { |
| this.drop_flag |
| } |
| } |
| |
| // Extremely dangerous casts used by DerefMove below. |
| impl<'a, T> MoveRef<'a, T> { |
| /// Consumes `self`, blindly casting the inner pointer to `U`. |
| pub(crate) unsafe fn cast<U>(mut self) -> MoveRef<'a, U> { |
| let mr = MoveRef { |
| ptr: &mut *Self::as_mut_ptr(&mut self).cast(), |
| drop_flag: self.drop_flag, |
| }; |
| mem::forget(self); |
| mr |
| } |
| } |
| |
| impl<'a, T> MoveRef<'a, T> { |
| /// Consume the `MoveRef<T>`, returning the wrapped value. |
| #[inline] |
| pub fn into_inner(this: Self) -> T { |
| unsafe { |
| let val = ptr::read(this.ptr); |
| let _ = this.cast::<()>(); |
| val |
| } |
| } |
| } |
| |
| impl<T: ?Sized> Deref for MoveRef<'_, T> { |
| type Target = T; |
| |
| #[inline] |
| fn deref(&self) -> &Self::Target { |
| self.ptr |
| } |
| } |
| |
| impl<T: ?Sized> DerefMut for MoveRef<'_, T> { |
| #[inline] |
| fn deref_mut(&mut self) -> &mut Self::Target { |
| self.ptr |
| } |
| } |
| |
| impl<T: ?Sized> Drop for MoveRef<'_, T> { |
| #[inline] |
| fn drop(&mut self) { |
| self.drop_flag.dec_and_check_if_died(); |
| unsafe { ptr::drop_in_place(self.ptr) } |
| } |
| } |
| |
| impl<'a, T> From<MoveRef<'a, T>> for Pin<MoveRef<'a, T>> { |
| #[inline] |
| fn from(x: MoveRef<'a, T>) -> Self { |
| MoveRef::into_pin(x) |
| } |
| } |
| |
| /// A trait for getting a pinned [`MoveRef`] for some pointer type `Self`. |
| /// |
| /// Conceptually, this trait is similar to [`DerefMove`], except that where |
| /// [`DerefMove::deref_move`] produces a `MoveRef<T>`, [`AsMove::as_move`] produces a |
| /// `Pin<MoveRef<T>>`. |
| /// |
| /// `DerefMove` can be seen as a refinement of `AsMove` where stronger guarantees about the memory |
| /// behavior (specifically the Pin-safety) of `Self` are present. |
| /// |
| /// Codifying this notion is the fact that `DerefMove` requires that `Self: DerefMut + AsMove`, |
| /// whereas `AsMove` only requires the weaker constraints of `Self: Deref`. |
| /// |
| /// Although `AsMove` is a supertrait of `DerefMove`, but `DerefMove` is *not* a supertrait of |
| /// `AsMove`, the two traits are nevertheless intended to have their impls for a given type defined |
| /// together *simultanteously*. |
| /// |
| /// It is expected in this situation that the impl for one of the traits will be (trivially) defined |
| /// in terms of the other, depending on the API for the pointer type `Self` with respect to |
| /// [`DerefMut`]. |
| /// |
| /// For example, the `Box<T>: AsMove` impl is defined in terms of the `Box<T>: DerefMove` impl, |
| /// because it is always the case that `Box<T>: DerefMut` regardless of whether `T: Unpin`. Hence, |
| /// `Box<T>: AsMove` simply performs the `Box<T>: DerefMove` operation then subsequently |
| /// (and trivially) pins the resulting `MoveRef<T>` with [`MoveRef::into_pin`]. |
| /// |
| /// On the other hand, the `cxx::UniquePtr<T>: DerefMove` impl is defined in terms of the |
| /// `UniquePtr<T>: AsMove` impl, because a `cxx::UniquePtr<T>: DerefMut` only if `T: Unpin`. Given |
| /// that `cxx::UniquePtr<T>` behaves like `Pin<Box<T>>` with respect to `DerefMut`, it is always |
| /// possible to safely produce a `Pin<MoveRef<T>>`, but *not* always possible to safely produce a |
| /// `MoveRef<T>`. Hence, when `T: Unpin`, only then `cxx::UniquePtr<T>: DerefMove` is defined, |
| /// which simply performs the `cxx::UniquePtr<T>: AsMove` operation then subsequently |
| /// (and trivially) unpins the resulting `Pin<MoveRef<T>>` with [`Pin::into_inner`]. |
| pub trait AsMove: Deref + Sized { |
| /// The "pure storage" form of `Self`, which owns the storage but not the |
| /// pointee. |
| type Storage: Sized; |
| |
| /// Gets a pinned `MoveRef` out of `Self`. |
| /// |
| /// This function is best paired with [`moveit!()`]: |
| /// ``` |
| /// # use core::pin::Pin; |
| /// # use moveit::{moveit, slot::DroppingSlot, move_ref::AsMove}; |
| /// let ptr = Box::pin(5); |
| /// moveit::slot!(#[dropping] storage); |
| /// ptr.as_move(storage); |
| /// ``` |
| /// Taking a trip through [`moveit!()`] is unavoidable due to the nature of |
| /// `MoveRef`. |
| /// |
| /// Compare with [`Pin::as_mut()`]. |
| fn as_move<'frame>( |
| self, |
| storage: DroppingSlot<'frame, Self::Storage>, |
| ) -> Pin<MoveRef<'frame, Self::Target>> |
| where |
| Self: 'frame; |
| } |
| |
| impl<'f, T: ?Sized> AsMove for MoveRef<'f, T> { |
| type Storage = (); |
| |
| #[inline] |
| fn as_move<'frame>( |
| self, |
| storage: DroppingSlot<'frame, Self::Storage>, |
| ) -> Pin<MoveRef<'frame, Self::Target>> |
| where |
| Self: 'frame, |
| { |
| MoveRef::into_pin(DerefMove::deref_move(self, storage)) |
| } |
| } |
| |
| impl<P: DerefMove> AsMove for Pin<P> { |
| type Storage = P::Storage; |
| |
| #[inline] |
| fn as_move<'frame>( |
| self, |
| storage: DroppingSlot<'frame, Self::Storage>, |
| ) -> Pin<MoveRef<'frame, Self::Target>> |
| where |
| Self: 'frame, |
| { |
| unsafe { |
| // SAFETY: |
| // |
| // It is safe to unwrap the `Pin` because `deref_move()` must not move out of the actual |
| // storage, merely shuffle pointers around, and immediately after the call to `deref_move()` |
| // we repin with `MoveRef::into_pin`, so the `Pin` API invariants are not violated later. |
| MoveRef::into_pin(P::deref_move(Pin::into_inner_unchecked(self), storage)) |
| } |
| } |
| } |
| |
| /// Moving dereference operations. |
| /// |
| /// *Note: This trait is intended to be defined in conjunction with [`AsMove`], |
| /// and there is a subtle interdependency between the two traits. We recommend |
| /// also reading it's documentation for a better understanding of how these |
| /// traits fit together.* |
| /// |
| /// This trait is the `&move` analogue of [`Deref`], for taking a pointer that |
| /// is the *sole owner* its pointee and converting it to a [`MoveRef`]. In |
| /// particular, a pointer type `P` owns its contents if dropping it would cause |
| /// its pointee's destructor to run. |
| /// |
| /// For example: |
| /// - [`MoveRef<T>`] implements `DerefMove` by definition. |
| /// - [`Box<T>`] implements `DerefMove`, since it drops the `T` in its |
| /// destructor. |
| /// - [`&mut T`] does *not* implement `DerefMove`, because it is |
| /// necessarily a borrow of a longer-lived, "truly owning" reference. |
| /// - [`Rc<T>`] and [`Arc<T>`] do *not* implement `DerefMove`, because even |
| /// though they own their pointees, they are not the *sole* owners. Dropping |
| /// a reference-counted pointer need not run the destructor if other pointers |
| /// are still alive. |
| /// - [`Pin<P>`] for `P: DerefMove` implements `DerefMove` only when |
| /// `P::Target: Unpin`, since `DerefMove: DerefMut`. |
| /// |
| /// # Principle of Operation |
| /// |
| /// Unfortunately, because we don't yet have language support for `&move`, we |
| /// need to break the implementation into two steps: |
| /// - Inhibit the "inner destructor" of the pointee, so that the smart pointer |
| /// is now managing dumb bytes. This is usually accomplished by converting the |
| /// pointee type to [`MaybeUninit<T>`]. |
| /// - Extract a [`MoveRef`] out of the "deinitialized" pointer. |
| /// |
| /// The first part of this consists of converting the pointer into the |
| /// "partially deinitialized" form, represented by the type |
| /// [`AsMove::Storage`]: it is the pointer as "pure storage". |
| /// |
| /// This pointer should be placed into the [`DroppingSlot`] passed into |
| /// `deref_move`, so that it has a fixed lifetime for the duration of the frame |
| /// that the [`MoveRef`] will exist for. The [`DroppingSlot`] will also provide |
| /// a drop flag to use to build the returned [`MoveRef`]. |
| /// |
| /// The mutable reference returned by the [`DroppingSlot`] should then be |
| /// converted into a [`MoveRef`]. The end result is that the [`DroppingSlot`] |
| /// owns the "outer" part of the pointer, while the [`MoveRef`] owns the "inner" |
| /// part. The `'frame` lifetime enforces the correct destruction order of these |
| /// two parts, since the [`MoveRef`] borrows the [`DroppingSlot`]. |
| /// |
| /// The [`moveit!()`] macro helps by constructing the [`DroppingSlot`] for you. |
| /// |
| /// ## Worked Example: [`Box<T>`] |
| /// |
| /// To inhibit the inner destructor of [`Box<T>`], we can use `Box<MaybeUninit<T>>` |
| /// as [`AsMove::Storage`]. [`MaybeUninit`] is preferred over [`ManuallyDrop`], |
| /// since it helps avoid otherwise scary aliasing problems with `Box<&mut T>`. |
| /// |
| /// The first step is to "cast" `Box<T>` into `Box<MaybeUninit<T>>` via |
| /// [`Box::into_raw()`] and [`Box::from_raw()`]. This is then placed into the |
| /// final storage location using [`DroppingSlot::put()`]. |
| /// |
| /// This returns a `&mut Box<MaybeUninit<T>>` and a [`DropFlag`]; the former is |
| /// converted into an `&mut T` via [`MaybeUninit::assume_init_mut()`]. |
| /// |
| /// Finally, [`MoveRef::new_unchecked()`] is used to combine these into the |
| /// return value. |
| /// |
| /// The first step is safe because we construct a `MoveRef` to reinstate the |
| /// destructor at the end of the function. The second step is safe because |
| /// we know, a priori, that the `Box` contains an initialized value. The final |
| /// step is safe, because we know, a priori, that the `Box` owns its pointee. |
| /// |
| /// The use of the drop flag in this way makes it so that dropping the resulting |
| /// `MoveRef` will leak the storage on the heap, exactly the same way as if we |
| /// had leaked a `Box`. |
| /// |
| /// ## Worked Example: [`MoveRef<T>`] |
| /// |
| /// We don't need to inhibit any destructors: we just need to convert a |
| /// `MoveRef<MoveRef<T>>` into a `MoveRef<T>`, which we can do by using |
| /// [`MoveRef::into_inner()`]. [`AsMove::Storage`] can be whatever, so we |
| /// simply choose [`()`] for this; the choice is arbitrary. |
| /// |
| /// # Safety |
| /// |
| /// Implementing `DerefMove` correctly requires that the uniqueness requirement |
| /// of [`MoveRef`] is upheld. In particular, the following function *must not* |
| /// violate memory safety: |
| /// ``` |
| /// # use moveit::{DerefMove, MoveRef, moveit}; |
| /// fn move_out_of<P>(p: P) -> P::Target |
| /// where |
| /// P: DerefMove, |
| /// P::Target: Sized, |
| /// { |
| /// unsafe { |
| /// // Replace `p` with a move reference into it. |
| /// moveit!(let p = &move *p); |
| /// |
| /// // Move out of `p`. From this point on, the `P::Target` destructor must |
| /// // run when, and only when, the function's return value goes out of |
| /// // scope per the usual Rust rules. |
| /// // |
| /// // In particular, the original `p` or any pointer it came from must not |
| /// // run the destructor when they go out of scope, under any circumstance. |
| /// MoveRef::into_inner(p) |
| /// } |
| /// } |
| /// ``` |
| /// |
| /// `deref_move()` must also be `Pin`-safe; even though it does not accept a |
| /// pinned reference, it must take care to not move its contents at any time. |
| /// In particular, the implementation of [`AsMove::as_move()`] must be safe by |
| /// definition. |
| pub unsafe trait DerefMove: DerefMut + AsMove { |
| /// Moves out of `self`, producing a [`MoveRef`] that owns its contents. |
| /// |
| /// `storage` is a location *somewhere* responsible for rooting the lifetime |
| /// of `*this`'s storage. The location is unimportant, so long as it outlives |
| /// the resulting [`MoveRef`], which is enforced by the type signature. |
| /// |
| /// [`moveit!()`] provides a convenient syntax for calling this function. |
| fn deref_move<'frame>( |
| self, |
| storage: DroppingSlot<'frame, Self::Storage>, |
| ) -> MoveRef<'frame, Self::Target> |
| where |
| Self: 'frame; |
| } |
| |
| unsafe impl<'a, T: ?Sized> DerefMove for MoveRef<'a, T> { |
| #[inline] |
| fn deref_move<'frame>( |
| self, |
| _storage: DroppingSlot<'frame, Self::Storage>, |
| ) -> MoveRef<'frame, Self::Target> |
| where |
| Self: 'frame, |
| { |
| self |
| } |
| } |
| |
| /// Note that `DerefMove` cannot be used to move out of a `Pin<P>` when `P::Target: !Unpin`. |
| /// ```compile_fail |
| /// # use crate::{moveit::{Emplace, MoveRef, moveit}}; |
| /// # use core::{marker::PhantomPinned, pin::Pin}; |
| /// // Fails to compile because `Box<PhantomPinned>: Deref<Target = PhantomPinned>` and `PhantomPinned: !Unpin`. |
| /// let ptr: Pin<Box<PhantomPinned>> = Box::emplace(moveit::new::default::<PhantomPinned>()); |
| /// moveit!(let mref = &move *ptr); |
| /// |
| /// // Fails to compile because `MoveRef<PhantomPinned>: Deref<Target = PhantomPinned>` and `PhantomPinned: !Unpin`. |
| /// moveit! { |
| /// let mref0: Pin<MoveRef<PhantomPinned>> = moveit::new::default::<PhantomPinned>(); |
| /// let mref1 = &move *mref0; |
| /// } |
| unsafe impl<P> DerefMove for Pin<P> |
| where |
| P: DerefMove, // needed for `AsMove: Pin<P>` for the call to `Self::as_move` |
| P::Target: Unpin, // needed for the call to `Pin::into_inner` |
| { |
| #[inline] |
| fn deref_move<'frame>( |
| self, |
| storage: DroppingSlot<'frame, Self::Storage>, |
| ) -> MoveRef<'frame, Self::Target> |
| where |
| Self: 'frame, |
| { |
| Pin::into_inner(self.as_move(storage)) |
| } |
| } |
| |
| #[doc(hidden)] |
| pub mod __macro { |
| use super::*; |
| use core::marker::PhantomData; |
| |
| /// Type-inference helper for `moveit!`. |
| pub struct DerefPhantom<T>(PhantomData<*const T>); |
| impl<T: DerefMove> DerefPhantom<T> { |
| #[inline] |
| pub fn new(_: &T) -> Self { |
| Self(PhantomData) |
| } |
| |
| #[inline] |
| pub fn deref_move<'frame>( |
| self, |
| this: T, |
| storage: DroppingSlot<'frame, T::Storage>, |
| ) -> MoveRef<'frame, T::Target> |
| where |
| Self: 'frame, |
| { |
| T::deref_move(this, storage) |
| } |
| } |
| } |
| |
| /// Performs an emplacement operation. |
| /// |
| /// This macro allows for three exotic types of `let` bindings: |
| /// ``` |
| /// # use moveit::{moveit, new, move_ref::MoveRef}; |
| /// # use core::pin::Pin; |
| /// let bx = Box::new(42); |
| /// |
| /// moveit! { |
| /// // Use a `New` to construct a new value in place on the stack. This |
| /// // produces a value of type `Pin<MoveRef<_>>`. |
| /// let x = new::default::<i32>(); |
| /// |
| /// // Move out of an existing `DerefMove` type, such as a `Box`. This has |
| /// // type `MoveRef<_>`, but can be pinned using `MoveRef::into_pin()`. |
| /// let y = &move *bx; |
| /// |
| /// // Create a `MoveRef` of an existing type on the stack. This also has |
| /// // type `MoveRef<_>`. |
| /// let z = &move y; |
| /// } |
| /// ``` |
| /// |
| /// All three `lets`, including in-place construction, pin to the stack. |
| /// Consider using something like [`Box::emplace()`] to perform construction on |
| /// the heap. |
| /// |
| /// This macro also has *temporary* forms, where rather than creating a binding, |
| /// a temporary (which cannot outlive its complete expression) is created: |
| /// |
| /// ``` |
| /// # use moveit::{moveit, new, move_ref::MoveRef}; |
| /// # use core::pin::Pin; |
| /// fn do_thing(x: Pin<MoveRef<i32>>) { |
| /// // ... |
| /// # let _ = x; |
| /// } |
| /// |
| /// do_thing(moveit!(new::of(42))); |
| /// ``` |
| /// |
| /// Note that these bindings cannot outlive the subexpression: |
| /// ```compile_fail |
| /// # use moveit::{moveit, new}; |
| /// let x = moveit!(new::of(42)); |
| /// let y = *x; // Borrow checker error. |
| /// ``` |
| /// |
| /// [`Box::emplace()`]: crate::new::Emplace::emplace |
| #[macro_export] |
| macro_rules! moveit { |
| (let $name:ident $(: $ty:ty)? = &move *$expr:expr $(; $($rest:tt)*)?) => { |
| $crate::moveit!(@move $name, $($ty)?, $expr); |
| $crate::moveit!($($($rest)*)?); |
| }; |
| (let mut $name:ident $(: $ty:ty)? = &move *$expr:expr $(; $($rest:tt)*)?) => { |
| $crate::moveit!(@move(mut) $name, $($ty)?, $expr); |
| $crate::moveit!($($($rest)*)?); |
| }; |
| (let $name:ident $(: $ty:ty)? = &move $expr:expr $(; $($rest:tt)*)?) => { |
| $crate::moveit!(@put $name, $($ty)?, $expr); |
| $crate::moveit!($($($rest)*)?); |
| }; |
| (let mut $name:ident $(: $ty:ty)? = &move $expr:expr $(; $($rest:tt)*)?) => { |
| $crate::emplace!(@put(mut) $name, $($ty)?, $expr); |
| $crate::emplace!($($($rest)*)?); |
| }; |
| (let $name:ident $(: $ty:ty)? = $expr:expr $(; $($rest:tt)*)?) => { |
| $crate::moveit!(@emplace $name, $($ty)?, $expr); |
| $crate::moveit!($($($rest)*)?); |
| }; |
| (let mut $name:ident $(: $ty:ty)? = $expr:expr $(; $($rest:tt)*)?) => { |
| $crate::moveit!(@emplace(mut) $name, $($ty)?, $expr); |
| $crate::moveit!($($($rest)*)?); |
| }; |
| ($(;)?) => {}; |
| |
| (&move *$expr:expr) => { |
| $crate::move_ref::DerefMove::deref_move( |
| $expr, $crate::slot!(#[dropping]), |
| ) |
| }; |
| |
| (&move $expr:expr) => {$crate::slot!().put($expr)}; |
| ($expr:expr) => {$crate::slot!().emplace($expr)}; |
| |
| (@move $(($mut:tt))? $name:ident, $($ty:ty)?, $expr:expr) => { |
| $crate::slot!(#[dropping] storage); |
| |
| #[allow(unused_mut)] |
| let $($mut)? $name $(: $ty)? = $crate::move_ref::DerefMove::deref_move($expr, storage); |
| }; |
| (@put $(($mut:tt))? $name:ident, $($ty:ty)?, $expr:expr) => { |
| $crate::slot!(slot); |
| let $($mut)? $name $(: $ty)? = slot.put($expr); |
| }; |
| (@emplace $(($mut:tt))? $name:ident, $($ty:ty)?, $expr:expr) => { |
| $crate::slot!(slot); |
| let $($mut)? $name $(: $ty)? = slot.emplace($expr); |
| }; |
| } |
| |
| #[cfg(test)] |
| pub(crate) mod test { |
| use crate::new; |
| use crate::MoveNew; |
| use crate::New; |
| |
| use super::*; |
| use std::alloc; |
| use std::alloc::Layout; |
| use std::marker::PhantomPinned; |
| use std::mem::MaybeUninit; |
| |
| #[test] |
| fn deref_move_of_move_ref() { |
| moveit! { |
| let x: MoveRef<Box<i32>> = &move Box::new(5); |
| let y: MoveRef<Box<i32>> = &move *x; |
| } |
| let _ = y; |
| } |
| |
| #[test] |
| fn deref_move_of_box() { |
| let x = Box::new(5); |
| moveit!(let y: MoveRef<i32> = &move *x); |
| let _ = y; |
| } |
| |
| #[test] |
| fn move_ref_into_inner() { |
| moveit!(let x: MoveRef<Box<i32>> = &move Box::new(5)); |
| let _ = MoveRef::into_inner(x); |
| } |
| |
| #[test] |
| #[should_panic] |
| fn unforgettable() { |
| moveit!(let x: MoveRef<i32> = &move 42); |
| mem::forget(x); |
| } |
| |
| #[test] |
| #[should_panic] |
| fn unforgettable_temporary() { |
| mem::forget(moveit!(&move 42)); |
| } |
| |
| #[test] |
| fn forgettable_box() { |
| let mut x = Box::new(5); |
| |
| // Save the pointer for later, so that we can free it to make Miri happy. |
| let ptr = x.as_mut() as *mut i32; |
| |
| moveit!(let y: MoveRef<i32> = &move *x); |
| |
| // This should leak but be otherwise safe. |
| mem::forget(y); |
| |
| // Free the leaked pointer; Miri will notice if this turns out to be a |
| // double-free. |
| unsafe { |
| alloc::dealloc(ptr as *mut u8, Layout::new::<i32>()); |
| } |
| } |
| |
| #[test] |
| fn forgettable_box_temporary() { |
| let mut x = Box::new(5); |
| |
| // Save the pointer for later, so that we can free it to make Miri happy. |
| let ptr = x.as_mut() as *mut i32; |
| |
| // This should leak but be otherwise safe. |
| mem::forget(moveit!(&move *x)); |
| |
| // Free the leaked pointer; Miri will notice if this turns out to be a |
| // double-free. |
| unsafe { |
| alloc::dealloc(ptr as *mut u8, Layout::new::<i32>()); |
| } |
| } |
| |
| // This type is reused in test code in cxx_support. |
| #[derive(Default)] |
| pub(crate) struct Immovable { |
| _pin: PhantomPinned, |
| } |
| |
| impl Immovable { |
| pub(crate) fn new() -> impl New<Output = Self> { |
| new::default() |
| } |
| } |
| |
| unsafe impl MoveNew for Immovable { |
| unsafe fn move_new( |
| _src: Pin<MoveRef<Self>>, |
| _this: Pin<&mut MaybeUninit<Self>>, |
| ) { |
| } |
| } |
| |
| #[test] |
| fn test_mov() { |
| moveit! { |
| let foo = Immovable::new(); |
| let _foo = new::mov(foo); |
| } |
| } |
| } |