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