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