moveit 0.5.1

A library for safe, in-place construction of Rust (and C++!) objects.
Documentation
// 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.

//! A library for safe, in-place construction of Rust (and C++!) objects.
//!
//! # How It Works
//!
//! `moveit` revolves around `unsafe trait`s that impose additional guarantees
//! on `!Unpin` types, such that they can be moved in the C++ sense. There are
//! two senses of "move" frequently used:
//! - The Rust sense, which is a blind memcpy and analogous-ish to the
//!   C++ "std::is_trivially_moveable` type-trait. Rust moves also render the
//!   moved-from object inaccessible.
//! - The C++ sense, where a move is really like a mutating `Clone` operation,
//!   which leave the moved-from value accessible to be destroyed at the end of
//!   the scope.
//!   
//! C++ also has *constructors*, which are special functions that produce a new
//! value in a particular location. In particular, C++ constructors may assume
//! that the address of `*this` will not change; all C++ objects are effectively
//! pinned and new objects must be constructed using copy or move constructors.
//!
//! The [`New`], [`CopyNew`], and [`MoveNew`] traits bring these concepts
//! into Rust. A [`New`] is like a nilary [`FnOnce`], except that instead of
//! returning its result, it writes it to a `Pin<&mut MaybeUninit<T>>`, which is
//! in the "memory may be repurposed" state described in the
//! [`Pin` documentation] (i.e., either it is freshly allocated or the
//! destructor was recently run). This allows a [`New`] to rely on the
//! pointer's address remaining stable, much like `*this` in C++.
//!
//! Types that implement [`CopyNew`] may be *copy-constructed*: given any
//! pointer to `T: CopyNew`, we can generate a constructor that constructs a
//! new, identical `T` at a designated location. [`MoveNew`] types may be
//! *move-constructed*: given an *owning* pointer (see [`DerefMove`]) to `T`,
//! we can generate a similar constructor, except that it also destroys the
//! `T` and the owning pointer's storage.
//!
//! None of this violates the existing `Pin` guarantees: moving out of a
//! `Pin<P>` does not perform a move in the Rust sense, but rather in the C++
//! sense: it mutates through the pinned pointer in a safe manner to construct
//! a new `P::Target`, and then destroys the pointer and its contents.
//!
//! In general, move-constructible types are going to want to be `!Unpin` so
//! that they can be self-referential. Self-referential types are one of the
//! primary motivations for move constructors.
//!
//! # Constructors
//!
//! A constructor is any type that implements [`New`]. Constructors are like
//! closures that have guaranteed RVO, which can be used to construct a
//! self-referential type in-place. To use the example from the `Pin<T>` docs:
//! ```
//! use std::marker::PhantomPinned;
//! use std::mem::MaybeUninit;
//! use std::pin::Pin;
//! use std::ptr;
//! use std::ptr::NonNull;
//!
//! use moveit::new;
//! use moveit::new::New;
//! use moveit::moveit;
//!
//! // This is a self-referential struct because the slice field points to the
//! // data field. We cannot inform the compiler about that with a normal
//! // reference, as this pattern cannot be described with the usual borrowing
//! // rules. Instead we use a raw pointer, though one which is known not to be
//! // null, as we know it's pointing at the string.
//! struct Unmovable {
//!   data: String,
//!   slice: NonNull<String>,
//!   _pin: PhantomPinned,
//! }
//!
//! impl Unmovable {
//!   // Defer construction until the final location is known.
//!   fn new(data: String) -> impl New<Output = Self> {
//!     new::of(Unmovable {
//!       data,
//!       // We only create the pointer once the data is in place
//!       // otherwise it will have already moved before we even started.
//!       slice: NonNull::dangling(),
//!       _pin: PhantomPinned,
//!     }).with(|this| unsafe {
//!       let this = this.get_unchecked_mut();
//!       this.slice = NonNull::from(&this.data);
//!     })
//!     
//!     // It is also possible to use other `new::` helpers, such as
//!     // `new::by` and `new::by_raw`, to configure construction behavior.
//!   }
//! }
//!
//! // The constructor can't be used directly, and needs to be emplaced.
//! moveit! {
//!   let unmoved = Unmovable::new("hello".to_string());
//! }
//! // The pointer should point to the correct location,
//! // so long as the struct hasn't moved.
//! // Meanwhile, we are free to move the pointer around.
//! # #[allow(unused_mut)]
//! let mut still_unmoved = unmoved;
//! assert_eq!(still_unmoved.slice, NonNull::from(&still_unmoved.data));
//!
//! // Since our type doesn't implement Unpin, this will fail to compile:
//! // let mut new_unmoved = Unmovable::new("world".to_string());
//! // std::mem::swap(&mut *still_unmoved, &mut *new_unmoved);
//!
//! // However, we can implement `MoveNew` to allow it to be "moved" again.
//! ```
//!
//! The [`new`] module provides various helpers for making constructors. As a
//! rule, functions which, in Rust, would normally construct and return a value
//! should return `impl New` instead. This is analogous to have `async fn`s and
//! `.iter()` functions work.
//!
//! # Emplacement
//!
//! The example above makes use of the [`moveit!()`] macro, one of many ways to
//! turn a constructor into a value. `moveit` gives you two choices for running
//! a constructor:
//! - On the stack, using the [`MoveRef`] type (this is what [`moveit!()`]
//!   generates).
//! - On the heap, using the extension methods from the [`Emplace`] trait.
//!
//! For example, we could have placed the above in a `Box` by writing
//! `Box::emplace(Unmovable::new())`.
//!
//! [`Pin` documentation]: https://doc.rust-lang.org/std/pin/index.html#drop-guarantee

#![cfg_attr(not(any(test, feature = "cxx")), no_std)]
#![deny(warnings, missing_docs, unused)]
// These clippy lints are somewhat at odds with our use of `new()`.
#![allow(clippy::new_ret_no_self, clippy::wrong_self_convention)]

#[cfg(feature = "alloc")]
extern crate alloc;

#[cfg(feature = "alloc")]
mod alloc_support;

#[cfg(feature = "cxx")]
mod cxx_support;

pub mod drop_flag;
pub mod move_ref;
pub mod new;
pub mod slot;

// #[doc(inline)]
pub use crate::{
  move_ref::{DerefMove, MoveRef},
  new::{CopyNew, Emplace, EmplaceUnpinned, MoveNew, New, TryNew},
  slot::Slot,
};

#[cfg(feature = "cxx")]
pub use cxx_support::MakeCppStorage;