moveit/
lib.rs

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")]
147extern crate alloc;
148
149#[cfg(feature = "alloc")]
150mod alloc_support;
151
152#[cfg(feature = "cxx")]
153mod cxx_support;
154
155pub mod drop_flag;
156pub mod move_ref;
157pub mod new;
158pub mod slot;
159
160// #[doc(inline)]
161pub use crate::{
162  move_ref::{AsMove, DerefMove, MoveRef},
163  new::{CopyNew, Emplace, MoveNew, New, TryNew},
164  slot::Slot,
165};
166
167#[cfg(feature = "cxx")]
168pub use cxx_support::MakeCppStorage;