1 // Copyright 2021 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //! A library for safe, in-place construction of Rust (and C++!) objects. 16 //! 17 //! # How It Works 18 //! 19 //! `moveit` revolves around `unsafe trait`s that impose additional guarantees 20 //! on `!Unpin` types, such that they can be moved in the C++ sense. There are 21 //! two senses of "move" frequently used: 22 //! - The Rust sense, which is a blind memcpy and analogous-ish to the 23 //! C++ "std::is_trivially_moveable` type-trait. Rust moves also render the 24 //! moved-from object inaccessible. 25 //! - The C++ sense, where a move is really like a mutating `Clone` operation, 26 //! which leave the moved-from value accessible to be destroyed at the end of 27 //! the scope. 28 //! 29 //! C++ also has *constructors*, which are special functions that produce a new 30 //! value in a particular location. In particular, C++ constructors may assume 31 //! that the address of `*this` will not change; all C++ objects are effectively 32 //! pinned and new objects must be constructed using copy or move constructors. 33 //! 34 //! The [`New`], [`CopyNew`], and [`MoveNew`] traits bring these concepts 35 //! into Rust. A [`New`] is like a nilary [`FnOnce`], except that instead of 36 //! returning its result, it writes it to a `Pin<&mut MaybeUninit<T>>`, which is 37 //! in the "memory may be repurposed" state described in the 38 //! [`Pin` documentation] (i.e., either it is freshly allocated or the 39 //! destructor was recently run). This allows a [`New`] to rely on the 40 //! pointer's address remaining stable, much like `*this` in C++. 41 //! 42 //! Types that implement [`CopyNew`] may be *copy-constructed*: given any 43 //! pointer to `T: CopyNew`, we can generate a constructor that constructs a 44 //! new, identical `T` at a designated location. [`MoveNew`] types may be 45 //! *move-constructed*: given an *owning* pointer (see [`DerefMove`]) to `T`, 46 //! we can generate a similar constructor, except that it also destroys the 47 //! `T` and the owning pointer's storage. 48 //! 49 //! None of this violates the existing `Pin` guarantees: moving out of a 50 //! `Pin<P>` does not perform a move in the Rust sense, but rather in the C++ 51 //! sense: it mutates through the pinned pointer in a safe manner to construct 52 //! a new `P::Target`, and then destroys the pointer and its contents. 53 //! 54 //! In general, move-constructible types are going to want to be `!Unpin` so 55 //! that they can be self-referential. Self-referential types are one of the 56 //! primary motivations for move constructors. 57 //! 58 //! # Constructors 59 //! 60 //! A constructor is any type that implements [`New`]. Constructors are like 61 //! closures that have guaranteed RVO, which can be used to construct a 62 //! self-referential type in-place. To use the example from the `Pin<T>` docs: 63 //! ``` 64 //! use std::marker::PhantomPinned; 65 //! use std::mem::MaybeUninit; 66 //! use std::pin::Pin; 67 //! use std::ptr; 68 //! use std::ptr::NonNull; 69 //! 70 //! use moveit::new; 71 //! use moveit::new::New; 72 //! use moveit::moveit; 73 //! 74 //! // This is a self-referential struct because the slice field points to the 75 //! // data field. We cannot inform the compiler about that with a normal 76 //! // reference, as this pattern cannot be described with the usual borrowing 77 //! // rules. Instead we use a raw pointer, though one which is known not to be 78 //! // null, as we know it's pointing at the string. 79 //! struct Unmovable { 80 //! data: String, 81 //! slice: NonNull<String>, 82 //! _pin: PhantomPinned, 83 //! } 84 //! 85 //! impl Unmovable { 86 //! // Defer construction until the final location is known. 87 //! fn new(data: String) -> impl New<Output = Self> { 88 //! new::of(Unmovable { 89 //! data, 90 //! // We only create the pointer once the data is in place 91 //! // otherwise it will have already moved before we even started. 92 //! slice: NonNull::dangling(), 93 //! _pin: PhantomPinned, 94 //! }).with(|this| unsafe { 95 //! let this = this.get_unchecked_mut(); 96 //! this.slice = NonNull::from(&this.data); 97 //! }) 98 //! 99 //! // It is also possible to use other `new::` helpers, such as 100 //! // `new::by` and `new::by_raw`, to configure construction behavior. 101 //! } 102 //! } 103 //! 104 //! // The constructor can't be used directly, and needs to be emplaced. 105 //! moveit! { 106 //! let unmoved = Unmovable::new("hello".to_string()); 107 //! } 108 //! // The pointer should point to the correct location, 109 //! // so long as the struct hasn't moved. 110 //! // Meanwhile, we are free to move the pointer around. 111 //! # #[allow(unused_mut)] 112 //! let mut still_unmoved = unmoved; 113 //! assert_eq!(still_unmoved.slice, NonNull::from(&still_unmoved.data)); 114 //! 115 //! // Since our type doesn't implement Unpin, this will fail to compile: 116 //! // let mut new_unmoved = Unmovable::new("world".to_string()); 117 //! // std::mem::swap(&mut *still_unmoved, &mut *new_unmoved); 118 //! 119 //! // However, we can implement `MoveNew` to allow it to be "moved" again. 120 //! ``` 121 //! 122 //! The [`new`] module provides various helpers for making constructors. As a 123 //! rule, functions which, in Rust, would normally construct and return a value 124 //! should return `impl New` instead. This is analogous to have `async fn`s and 125 //! `.iter()` functions work. 126 //! 127 //! # Emplacement 128 //! 129 //! The example above makes use of the [`moveit!()`] macro, one of many ways to 130 //! turn a constructor into a value. `moveit` gives you two choices for running 131 //! a constructor: 132 //! - On the stack, using the [`MoveRef`] type (this is what [`moveit!()`] 133 //! generates). 134 //! - On the heap, using the extension methods from the [`Emplace`] trait. 135 //! 136 //! For example, we could have placed the above in a `Box` by writing 137 //! `Box::emplace(Unmovable::new())`. 138 //! 139 //! [`Pin` documentation]: https://doc.rust-lang.org/std/pin/index.html#drop-guarantee 140 141 #![cfg_attr(not(any(test, feature = "cxx")), no_std)] 142 #![deny(warnings, missing_docs, unused)] 143 // These clippy lints are somewhat at odds with our use of `new()`. 144 #![allow(clippy::new_ret_no_self, clippy::wrong_self_convention)] 145 146 #[cfg(feature = "alloc")] 147 extern crate alloc; 148 149 #[cfg(feature = "alloc")] 150 mod alloc_support; 151 152 #[cfg(feature = "cxx")] 153 mod cxx_support; 154 155 pub mod drop_flag; 156 pub mod move_ref; 157 pub mod new; 158 pub mod slot; 159 160 // #[doc(inline)] 161 pub use crate::{ 162 move_ref::{AsMove, DerefMove, MoveRef}, 163 new::{CopyNew, Emplace, MoveNew, New, TryNew}, 164 slot::Slot, 165 }; 166 167 #[cfg(feature = "cxx")] 168 pub use cxx_support::MakeCppStorage; 169