blob: eeb8e2e0b25804a0c679a96533b498686bc7de83 [file] [edit]
// Part of the Crubit project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#![cfg_attr(not(test), no_std)]
#![feature(auto_traits, negative_impls, allow_internal_unstable)]
#![allow(internal_features)] // allow_internal_unstable 🤔
//! Support for in-place construction and mutation of Rust types, especially those that were
//! originally defined in C++.
//!
//! This draws from moveit, pin-init, and the current in-place initialization proposal at
//! https://hackmd.io/@aliceryhl/BJutRcPblx.
//!
//! * Introductory documentation: crubit.rs/types/non_rust_movable/intro_short
//! * Full documentation: crubit.rs/types/non_rust_movable/intro_advanced
//! * Cheat sheet: crubit.rs/types/non_rust_movable/cheat_sheet
//!
//! # Unstable Rust Features
//!
//! This library requires the following unstable features enabled in users:
//!
//! **negative_impls:**
//! This is used to allow trait coherence checking for `!Unpin` types. A
//! "blanket impl for all `Unpin` types is used to make them constructible with
//! `ctor`, and Rust believes this may conflict with types that use
//! `PhantomPinned`. It knows no conflict exists if, instead, types impl
//! `!Unpin`.
extern crate alloc;
use alloc::boxed::Box;
use alloc::rc::Rc;
use alloc::sync::Arc;
use core::fmt::Debug;
use core::marker::{PhantomData, Unpin};
use core::mem::{ManuallyDrop, MaybeUninit};
use core::ops::{Deref, DerefMut};
use core::pin::Pin;
pub use ctor_proc_macros::{
project_pin_type, project_ref_type, recursively_pinned, CtorFrom_Default, MoveAndAssignViaCopy,
};
/// The error type for an infallible `Ctor`.
///
/// This error type is special-cased for unfallible operations,
/// such as `emplace()`. If you need to handle an error, use
/// the `try_` variants, instead.
pub type Infallible = core::convert::Infallible;
/// The string constant for #[must_use] to describe why you must use a `Ctor`.
macro_rules! must_use_ctor {
() => {
"A Ctor is not invoked unless emplaced, using e.g. `emplace!()`, or `Box::emplace()`."
};
}
/// The string constant for #[must_use] to describe why you must use a
/// `Ctor`/`Assign` source.
macro_rules! must_use_ctor_assign {
($name:literal) => {
concat!(
$name,
" is not invoked unless emplaced, using e.g. `emplace!()`, or `Box::emplace()`, or",
" unless assigned from, using `.assign()`."
)
};
}
// ============================
// Core construction operations
// ============================
/// A trait for pinned in-place initialization of values.
///
/// A parameter or return value of type `impl Ctor<Output=T, Error=Infallible>` (commonly spelled
/// `Ctor![T]`) is analogous to a parameter or return value of type `T`, except that it can be
/// initialized in place and pinned. This means that the construction logic can assume that its
/// address will never change, and can construct values directly into their final location.
///
/// The `Ctor` implementation doesn't represent the value itself, but deferred initialization for
/// that value. To actually construct it, you must use `emplace!()` or methods like `Box::emplace`
/// from the `Emplace` trait, which are analogous to `pin!()` and `Box::pin` respectively.
///
/// More generally, because passing or returning `Ctor` is analogous to passing or returning by
/// value, there is a corresponding family of analogues for things you might do by value:
///
/// * `ctor!{MyStruct{a: b})` is analogous to `MyStruct {a: b}`, but constructs the field and the
/// struct itself in-place. `b` is a `Ctor`, and the expression evaluates to a `Ctor`.
/// * `CtorNew<T>` is analogous to `From<T>`, except it returns a `Ctor![Self]`.
/// * `emplace!(ctor)` is analogous to `pin!(value)`, but it evaluates the `ctor` to construct the
/// value in-place.
/// * The `Emplace` trait is analogous to methods like `Box::pin`, but accepts a `Ctor![T]`.
///
/// # Safety
///
/// Implementations must satisfy the postconditions of the `ctor` method.
#[must_use = must_use_ctor!()]
pub unsafe trait Ctor: Sized {
/// The constructed output type.
type Output: ?Sized;
/// The error type if initialization fails. This should typically
/// be `Infallible`, as there's only limited support for real
/// errors currently.
type Error;
/// Constructs a value in place.
///
/// Before this call, `dest` is uninitialized. After this call,
/// if `ctor` does not panic, and returns `Ok`, then `dest` is
/// initialized to the constructed value.
///
/// If `ctor` panics or returns `Err`, the caller treats `dest` as
/// uninitialized and will not drop it. An implementation which initializes
/// `*dest` and then fails must drop it before returning or unwinding,
/// to uphold the `Pin` drop guarantee.
///
/// # Safety
///
/// `dest` is valid for writes and uninitialized.
///
/// This function pins `dest`, so unless `Output: Unpin`, `*dest` must not be moved or otherwise
/// invalidated.
unsafe fn ctor(self, dest: *mut Self::Output) -> Result<(), Self::Error>;
/// Converts a `Ctor` with error type `Infallible` to one with the provided error type `E`.
///
/// This is useful for chaining possibly-fallible operations (such as `ctor_then`) on top of
/// an existing infallible `Ctor`.
fn ctor_make_fallible<E>(self) -> CtorMakeFallible<Self, E>
where
Self: Ctor<Error = Infallible>,
{
CtorMakeFallible { ctor: self, marker: PhantomData }
}
/// Maps this `Ctor`'s error type into a new error type using the `Into` trait.
fn ctor_err_into<E>(self) -> CtorErrInto<Self, E>
where
Self::Error: Into<E>,
{
CtorErrInto { ctor: self, marker: PhantomData }
}
/// Returns a `Ctor`, which will invoke `f` after construction, if successful.
///
/// This functions similarly to `Result::and_then`.
///
/// If `f` returns an error or panics, the constructed value is dropped in place before the
/// error is returned or the panic propagates.
///
/// For example, these two snippets are equivalent:
///
/// ```
/// let mut x = emplace!(y);
/// x.mutating_method();
/// ```
///
/// ```
/// let new_ctor = y.ctor_then(|mut initialized| {
/// initialized.mutating_method();
/// Ok(())
/// });
/// let x = emplace!(new_ctor);
/// ```
fn ctor_then<F>(self, f: F) -> CtorThen<Self, F>
where
F: FnOnce(Pin<&mut Self::Output>) -> Result<(), Self::Error>,
{
CtorThen { ctor: self, f }
}
/// Returns a `Ctor` which will invoke `f` if construction fails,
/// transforming the error type.
///
/// This functions similarly to `Result::map_err`.
///
/// For example, these two snippets are equivalent:
///
/// ```
/// let x: Result<Pin<&mut T>, E> = try_emplace!(y);
/// let x = x.map_err(|e| e.into_new_error())
/// ```
///
/// ```
/// let new_ctor = y.ctor_map_err(|e| e.into_new_error());
/// let x = try_emplace!(new_ctor);
/// ```
fn ctor_map_err<F, E>(self, f: F) -> CtorMapErr<Self, F, E>
where
F: FnOnce(Self::Error) -> E,
{
CtorMapErr { ctor: self, f }
}
/// Returns a `Ctor` which, if the original construction fails,
/// invoke `f` in order to attempt to produce the value.
///
/// This functions similarly to `Result::or_else`.
///
/// For example:
///
/// ```
/// let new_ctor = Y::first_attempt().ctor_or_else(|_| Y::fallback_attempt());
/// let x = try_emplace!(new_ctor);
/// ```
fn ctor_or_else<F, O>(self, f: F) -> CtorOrElse<Self, F, O>
where
F: FnOnce(Self::Error) -> O,
O: Ctor<Output = Self::Output>,
{
CtorOrElse { ctor: self, f }
}
/// Returns a `Ctor` which will panic with the given message if the original construction
/// fails.
///
/// This functions similarly to `Result::expect`.
fn ctor_expect<'a>(self, msg: &'a str) -> CtorExpect<'a, Self>
where
Self::Error: Debug,
{
CtorExpect { ctor: self, msg }
}
/// Returns a `Ctor` which will panic if the original construction fails.
///
/// This functions similarly to `Result::unwrap`.
fn ctor_unwrap(self) -> CtorUnwrap<Self>
where
Self::Error: Debug,
{
CtorUnwrap { ctor: self }
}
/// Returns a `Ctor` which will return a default value if the original construction fails.
///
/// This functions similarly to `Result::unwrap_or_default`.
fn ctor_unwrap_or_default(self) -> CtorUnwrapOrDefault<Self>
where
Self::Output: CtorNew<()>,
{
CtorUnwrapOrDefault { ctor: self }
}
}
// =======================
// Ctor trait return types
// =======================
/// Return type of [`Ctor::ctor_make_fallible`].
pub struct CtorMakeFallible<C, E>
where
C: Ctor<Error = Infallible>,
{
ctor: C,
marker: PhantomData<fn() -> E>,
}
impl<C, E> !SelfCtor for CtorMakeFallible<C, E> where C: Ctor<Error = Infallible> {}
unsafe impl<C, E> Ctor for CtorMakeFallible<C, E>
where
C: Ctor<Error = Infallible>,
{
type Output = C::Output;
type Error = E;
unsafe fn ctor(self, dest: *mut Self::Output) -> Result<(), Self::Error> {
unsafe { self.ctor.ctor(dest).map_err(|e| match e {}) }
}
}
/// Return type of [`Ctor::ctor_err_into`].
pub struct CtorErrInto<C, E>
where
C: Ctor,
C::Error: Into<E>,
{
ctor: C,
marker: PhantomData<fn() -> E>,
}
impl<C, E> !SelfCtor for CtorErrInto<C, E>
where
C: Ctor,
C::Error: Into<E>,
{
}
unsafe impl<C, E> Ctor for CtorErrInto<C, E>
where
C: Ctor,
C::Error: Into<E>,
{
type Output = C::Output;
type Error = E;
unsafe fn ctor(self, dest: *mut Self::Output) -> Result<(), Self::Error> {
unsafe { self.ctor.ctor(dest).map_err(Into::into) }
}
}
/// Return type of [`Ctor::ctor_then`].
pub struct CtorThen<C: Ctor, F: FnOnce(Pin<&mut C::Output>) -> Result<(), C::Error>> {
ctor: C,
f: F,
}
impl<C, F> !SelfCtor for CtorThen<C, F>
where
C: Ctor,
F: FnOnce(Pin<&mut C::Output>) -> Result<(), C::Error>,
{
}
// SAFETY: initializes dest, or returns an error / panics with dest uninitialized.
unsafe impl<C: Ctor, F: FnOnce(Pin<&mut C::Output>) -> Result<(), C::Error>> Ctor
for CtorThen<C, F>
{
type Output = C::Output;
type Error = C::Error;
unsafe fn ctor(self, dest: *mut Self::Output) -> Result<(), Self::Error> {
/// Drops the pointee when dropped.
struct DropGuard<T: ?Sized>(*mut T);
impl<T: ?Sized> Drop for DropGuard<T> {
fn drop(&mut self) {
// SAFETY: the pointee is initialized, and is not used again after this.
unsafe { core::ptr::drop_in_place(self.0) }
}
}
// SAFETY: the caller guarantees that `dest` is valid for writes, uninitialized, and pinned.
unsafe {
self.ctor.ctor(dest)?;
}
// `*dest` is now initialized and pinned. If `f` returns an error or panics, our caller
// treats `dest` as uninitialized and will not drop it, so we must drop it here to uphold
// the `Pin` drop guarantee.
let guard = DropGuard(dest);
// SAFETY: `*dest` was initialized above, and the caller guarantees it is pinned.
let pinned = unsafe { Pin::new_unchecked(&mut *dest) };
let result = (self.f)(pinned);
if result.is_ok() {
core::mem::forget(guard);
}
result
}
}
/// Return type of [`Ctor::ctor_map_err`].
pub struct CtorMapErr<C, F, E>
where
C: Ctor,
F: FnOnce(C::Error) -> E,
{
ctor: C,
f: F,
}
impl<C, F, E> !SelfCtor for CtorMapErr<C, F, E>
where
C: Ctor,
F: FnOnce(C::Error) -> E,
{
}
unsafe impl<C, F, E> Ctor for CtorMapErr<C, F, E>
where
C: Ctor,
F: FnOnce(C::Error) -> E,
{
type Output = C::Output;
type Error = E;
unsafe fn ctor(self, dest: *mut Self::Output) -> Result<(), Self::Error> {
unsafe { self.ctor.ctor(dest).map_err(|e| (self.f)(e)) }
}
}
/// Return type of [`Ctor::ctor_or_else`].
pub struct CtorOrElse<C, F, O>
where
C: Ctor,
F: FnOnce(C::Error) -> O,
O: Ctor<Output = C::Output>,
{
ctor: C,
f: F,
}
impl<C, F, O> !SelfCtor for CtorOrElse<C, F, O>
where
C: Ctor,
F: FnOnce(C::Error) -> O,
O: Ctor<Output = C::Output>,
{
}
// SAFETY: initializes dest or returns an error.
unsafe impl<C, F, O> Ctor for CtorOrElse<C, F, O>
where
C: Ctor,
F: FnOnce(C::Error) -> O,
O: Ctor<Output = C::Output>,
{
type Output = C::Output;
type Error = O::Error;
unsafe fn ctor(self, dest: *mut Self::Output) -> Result<(), Self::Error> {
unsafe {
let Err(e) = self.ctor.ctor(dest) else { return Ok(()) };
(self.f)(e).ctor(dest)
}
}
}
/// Return type of [`Ctor::ctor_expect`].
pub struct CtorExpect<'a, C>
where
C: Ctor,
{
ctor: C,
msg: &'a str,
}
impl<'a, C> !SelfCtor for CtorExpect<'a, C> where C: Ctor {}
unsafe impl<'a, C> Ctor for CtorExpect<'a, C>
where
C: Ctor,
C::Error: Debug,
{
type Output = C::Output;
type Error = Infallible;
unsafe fn ctor(self, dest: *mut Self::Output) -> Result<(), Self::Error> {
unsafe {
self.ctor.ctor(dest).unwrap_or_else(|e| panic!("{}: {:?}", self.msg, e));
Ok(())
}
}
}
/// Return type of [`Ctor::ctor_unwrap`].
pub struct CtorUnwrap<C>
where
C: Ctor,
{
ctor: C,
}
impl<C> !SelfCtor for CtorUnwrap<C> where C: Ctor {}
unsafe impl<C> Ctor for CtorUnwrap<C>
where
C: Ctor,
C::Error: Debug,
{
type Output = C::Output;
type Error = Infallible;
unsafe fn ctor(self, dest: *mut Self::Output) -> Result<(), Self::Error> {
unsafe {
self.ctor.ctor(dest).unwrap_or_else(|e| {
panic!(
"Construction of {type_name} failed: {e:?}",
type_name = core::any::type_name::<C::Output>(),
)
});
Ok(())
}
}
}
/// Return type of [`Ctor::ctor_unwrap_or_default`].
pub struct CtorUnwrapOrDefault<C>
where
C: Ctor,
C::Output: CtorNew<()>,
{
ctor: C,
}
impl<C> !SelfCtor for CtorUnwrapOrDefault<C>
where
C: Ctor,
C::Output: CtorNew<()>,
{
}
unsafe impl<C> Ctor for CtorUnwrapOrDefault<C>
where
C: Ctor,
C::Output: CtorNew<()>,
{
type Output = C::Output;
type Error = <C::Output as CtorNew<()>>::Error;
unsafe fn ctor(self, dest: *mut Self::Output) -> Result<(), Self::Error> {
unsafe {
if self.ctor.ctor(dest).is_err() {
<C::Output as CtorNew<()>>::ctor_new(()).ctor(dest)?;
}
Ok(())
}
}
}
/// The type of a value that will be constructed in-place.
///
/// This expands to `impl Ctor<...>`, and is used as a parameter or return type.
///
/// This exists for two reasons:
///
/// 1. To allow for changing the implementation over time.
/// 2. To make the spelling less overly verbose. Instead of `impl Ctor<Output = T, Error = E>`, you
/// can write `Ctor![T]`.
///
/// In codebases not yet migrated to the 2024 edition, if you need a `use<'a>` bound, you must
/// write the full `impl` syntax: `impl Ctor<Output=T, Error=Infallible> + use<'a, 'b>`.
///
/// (It is surprisingly difficult to write a macro that would allow the `use` parameters!)
#[macro_export]
macro_rules! Ctor {
( $T:ty $(,)? ) => {
impl $crate::Ctor<Output = $T, Error = $crate::macro_internal::Infallible>
};
( $T:ty, Error = $E:ty $(,)? ) => {
impl $crate::Ctor<Output = $T, Error = $E>
};
}
pub struct CtorError<T: ?Sized, E> {
e: E,
marker: PhantomData<fn() -> T>,
}
// SAFETY: unconditionally returns an error.
unsafe impl<T: ?Sized, E> Ctor for CtorError<T, E> {
type Output = T;
type Error = E;
unsafe fn ctor(self, _: *mut Self::Output) -> Result<(), Self::Error> {
Err(self.e)
}
}
impl<T: ?Sized, E> !SelfCtor for CtorError<T, E> {}
/// Returns a `Ctor` with error type `E` which always fails with the given error.
pub fn ctor_error<T: ?Sized, E>(e: E) -> CtorError<T, E> {
CtorError { e, marker: PhantomData }
}
/// Construct and return a Rust-movable value from a `Ctor`.
///
/// This is a safe, "by value" version of `Ctor::ctor`.
// TODO(jeanpierreda): Should this be a method on `Ctor`? Should it return `Result`?
pub fn construct<T: Unpin>(ctor: impl Ctor<Output = T, Error = Infallible>) -> T {
let mut value = MaybeUninit::uninit();
// SAFETY: `value` is valid for writes and uninitialized, and `T` is `Unpin`.
unsafe {
ctor.ctor(value.as_mut_ptr()).unwrap();
}
// SAFETY: `ctor.ctor()` initialized `value`.
unsafe { value.assume_init() }
}
/// Trait for smart pointer types which support in-place initialization via `Ctor`.
///
/// A typical example would be `Box<T>`, allows emplacing a `Ctor` into
/// a `Pin<Box<T>>` by calling `{Box, Rc, Arc}::emplace`.
pub trait Emplace<T>: Sized {
/// Materialize an infallible `Ctor`.
fn emplace<C: Ctor<Output = T, Error = Infallible>>(c: C) -> Pin<Self> {
Self::try_emplace(c).unwrap()
}
/// Materialize a `Ctor`, returning an error if initialization fails.
fn try_emplace<C: Ctor<Output = T>>(c: C) -> Result<Pin<Self>, C::Error>;
}
impl<T> Emplace<T> for Box<T> {
fn try_emplace<C: Ctor<Output = T>>(ctor: C) -> Result<Pin<Box<T>>, C::Error> {
let mut uninit = Box::new(MaybeUninit::<T>::uninit());
unsafe {
ctor.ctor(uninit.as_mut_ptr())?;
Ok(Pin::new_unchecked(uninit.assume_init()))
}
}
}
impl<T> Emplace<T> for Rc<T> {
fn try_emplace<C: Ctor<Output = T>>(ctor: C) -> Result<Pin<Rc<T>>, C::Error> {
let uninit = Rc::new(MaybeUninit::<T>::uninit());
unsafe {
// TODO: https://github.com/rust-lang/rust/issues/145036 - use cast_init when stable.
ctor.ctor(Rc::as_ptr(&uninit).cast_mut().cast::<T>())?;
Ok(Pin::new_unchecked(uninit.assume_init()))
}
}
}
impl<T> Emplace<T> for Arc<T> {
fn try_emplace<C: Ctor<Output = T>>(ctor: C) -> Result<Pin<Arc<T>>, C::Error> {
let uninit = Arc::new(MaybeUninit::<T>::uninit());
unsafe {
// TODO: https://github.com/rust-lang/rust/issues/145036 - use cast_init when stable.
ctor.ctor(Arc::as_ptr(&uninit).cast_mut().cast::<T>())?;
Ok(Pin::new_unchecked(uninit.assume_init()))
}
}
}
/// An auto trait for types that are values in their own right, rather than
/// dedicated constructors for some *other* type.
///
/// This trait is implemented for all types by default. Types like `FnCtor` that
/// exist only to construct other types should opt out via `impl !SelfCtor for ...`.
///
/// Do not use this trait as a trait bound. Instead, use `Ctor`. `SelfCtor` is a workaround to
/// implement specialization of `Ctor`, and will go away if we ever get a useful form of
/// specialization.
///
/// # Why is `SelfCtor` not implemented for my type?
///
/// `SelfCtor` is an auto trait, which means it is automatically implemented for a type if
/// it is implemented for all of its fields.
///
/// However, trait objects (`dyn Trait`) do not implement auto traits unless they are
/// explicitly listed in the trait bounds (e.g. `dyn Trait + SelfCtor`). Since `SelfCtor` is
/// a custom auto trait, it cannot be listed in trait bounds in general.
///
/// Consequently, any type containing a trait object (such as `Box<dyn Trait>`, `Rc<dyn Trait>`,
/// or a struct containing these) will also fail to implement `SelfCtor`.
///
/// If you encounter a compile error about `SelfCtor` not being implemented for a type `T`,
/// and you are trying to use a value of type `T` as a `Ctor` (for example, in a `ctor!` macro),
/// you can work around this by wrapping the value in `RustMoveCtor::new(value)`. This will
/// wrap the value in a constructor that constructs the type via a Rust move.
#[diagnostic::on_unimplemented(
message = "`{Self}` cannot be used as a direct initializer in `ctor!`",
label = "does not implement `SelfCtor` (often due to containing `dyn Trait`)",
note = "Types containing trait objects (like `dyn Trait`) do not implement `SelfCtor` by default.",
note = "To use this value in `ctor!`, wrap it in `RustMoveCtor::new(value)`."
)]
pub auto trait SelfCtor {}
#[must_use = must_use_ctor!()]
pub struct FnCtor<Output, F: FnOnce(*mut Output)>(F, PhantomData<fn(Output)>);
impl<Output, F: FnOnce(*mut Output)> FnCtor<Output, F> {
/// Create a new `Ctor` whose `ctor()` method invokes `f`.
///
/// # Safety
///
/// If `f` does not panic, then it must initialize its argument to a valid value.
///
/// `f` may rely on the same safety preconditions described by `Ctor::ctor`. In particular,
/// the pointer argument is guaranteed to be valid for writes.
pub unsafe fn new(f: F) -> Self {
Self(f, PhantomData)
}
}
// SAFETY: unconditionally initializes dest.
unsafe impl<Output, F: FnOnce(*mut Output)> Ctor for FnCtor<Output, F> {
type Output = Output;
type Error = Infallible;
unsafe fn ctor(self, dest: *mut Output) -> Result<(), Infallible> {
self.0(dest);
Ok(())
}
}
/// !SelfCtor to override the blanket Ctor impl.
impl<Output, F> !SelfCtor for FnCtor<Output, F> {}
/// A `Ctor` for copying the pointee.
///
/// When used as a `Ctor` or `Assign` source, this initializes a `P::Target` by copying the
/// underlying data, analogous to `Clone`.
///
/// Note: this does not actually copy `P` until it is used.
#[must_use = must_use_ctor_assign!("Copy")]
pub struct Copy<P: ?Sized + Deref>(P);
// SAFETY: unconditionally initializes dest.
unsafe impl<Output: ?Sized, Error, P: Deref<Target = Output>> Ctor for Copy<P>
where
Output: for<'a> CtorNew<&'a Output, Error = Error>,
{
type Output = Output;
type Error = Error;
unsafe fn ctor(self, dest: *mut Output) -> Result<(), Self::Error> {
unsafe { Output::ctor_new(&*self.0).ctor(dest) }
}
}
/// !SelfCtor to override the blanket Ctor impl.
impl<P: ?Sized> !SelfCtor for Copy<P> {}
/// Returns a `Copy` which can be used as a `CtorNew` or `Assign` source, or as
/// a `Ctor` directly.
///
/// Note: this does not actually copy the parameter until it is used.
pub fn copy<T: ?Sized + for<'a> CtorNew<&'a T>, P: Deref<Target = T>>(src: P) -> Copy<P> {
Copy(src)
}
// ================================
// DerefMut based move construction
// ================================
/// Rvalue Reference (move-reference) type.
///
/// When used as a `Ctor` or `Assign` source, this initializes a `T` by a mutating move operation.
///
/// All rvalue references are implicitly pinned, to avoid an explosion in the number of reference
/// types.
///
/// Note: this does not actually move until it is used.
#[must_use = must_use_ctor_assign!("RvalueReference")]
#[repr(transparent)]
#[cfg_attr(all(not(doc), feature = "same_abi"), doc = "CRUBIT_ANNOTATE: same_abi=")]
pub struct RvalueReference<'a, T: ?Sized>(pub Pin<&'a mut T>);
impl<T: ?Sized> RvalueReference<'_, T> {
/// Returns a const rvalue reference to the underlying data.
///
/// This is usually not useful, but some C++ APIs do have `const` rvalue references due to
/// templated code.
pub fn as_const(&self) -> ConstRvalueReference<'_, T> {
ConstRvalueReference(&*self.0)
}
/// Returns an ordinary pinned mutable reference to the underlying data.
pub fn as_mut(&mut self) -> Pin<&mut T> {
self.0.as_mut()
}
/// Returns an ordinary reference to the underlying data.
pub fn get_ref(&self) -> &T {
// It would be nice to return &'a T, but that would not be sound, and as a
// result Pin makes it impossible (in safe code). Consider:
//
// let my_pin: Pin<&mut T> = ...;
// let my_borrow = RvalueReference(my_pin.as_mut()).get_ref();
//
// The lifetime of my_borrow CANNOT be 'a, but instead MUST be scoped to the
// reborrowed lifetime of the pin, or else it would violate the aliasing
// rules by coexisting with my_pin. Thus, get_ref must return &T, not
// &'a T. (For the same reason, as_const returns a ConstRvalueReference
// whose lifetime is bound by self, not 'a.)
&self.0
}
}
impl<T: ?Sized> Deref for RvalueReference<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.get_ref()
}
}
// SAFETY: unconditionally initializes dest.
unsafe impl<'a, T: ?Sized> Ctor for RvalueReference<'a, T>
where
T: CtorNew<Self>,
{
type Output = T;
type Error = <T as CtorNew<Self>>::Error;
unsafe fn ctor(self, dest: *mut T) -> Result<(), Self::Error> {
unsafe { T::ctor_new(self).ctor(dest) }
}
}
/// Converts to an `RvalueReference`.
///
/// Do not use this trait directly, instead, cast to an `RvalueReference` using
/// the `mov!()` macro.
#[doc(hidden)]
pub trait DerefRvalueReference: Deref
where
Self::Target: Sized,
{
fn deref_rvalue_reference(&mut self) -> RvalueReference<'_, Self::Target>;
}
impl<T> DerefRvalueReference for Pin<T>
where
T: DerefMut,
Self::Target: Sized,
{
fn deref_rvalue_reference(&mut self) -> RvalueReference<'_, Self::Target> {
RvalueReference(self.as_mut())
}
}
impl<T> DerefRvalueReference for &mut T
where
T: Unpin,
{
fn deref_rvalue_reference(&mut self) -> RvalueReference<'_, Self::Target> {
RvalueReference(Pin::new(self))
}
}
/// !SelfCtor to override the blanket `Ctor` impl.
impl<'a, T: ?Sized> !SelfCtor for RvalueReference<'a, T> {}
/// Represents the type `T` by value, but is passed by rvalue reference.
///
/// This is currently an implementation detail of the `impl Ctor` bindings, but
/// it can also be used in trait implementations if `impl Ctor` is not available,
/// due to "overlapping" impls that Rust doesn't recognize as disjoint due to different
/// associated types. (Rust does not recognize `Ctor![i32]` and `Ctor![i64]` as disjoint,
/// even though no type can implement both.)
#[cfg_attr(all(not(doc), feature = "same_abi"), doc = "CRUBIT_ANNOTATE: same_abi=")]
#[repr(transparent)]
pub struct ByValue<'a, T: ?Sized>(pub RvalueReference<'a, T>);
impl<T: ?Sized> Deref for ByValue<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
// SAFETY: forwards to `RvalueReference`'s `Ctor` impl, meets all requirements.
unsafe impl<'a, T: ?Sized> Ctor for ByValue<'a, T>
where
T: CtorNew<RvalueReference<'a, T>>,
{
type Output = T;
type Error = <T as CtorNew<RvalueReference<'a, T>>>::Error;
unsafe fn ctor(self, dest: *mut T) -> Result<(), Self::Error> {
// SAFETY: forwards to `RvalueReference`'s `Ctor` impl, meets all requirements.
unsafe { T::ctor_new(self.0).ctor(dest) }
}
}
/// !SelfCtor to override the blanket `Ctor` impl.
impl<'a, T: ?Sized> !SelfCtor for ByValue<'a, T> {}
/// Const rvalue reference (move-reference) type. Usually not very helpful.
///
/// This implicitly converts to `T` by const-moving -- either
/// const-move-construction (construction from `ConstRvalueReference(&x)`), or
/// const-move-assignment (assignment from `ConstRvalueReference(&x)`).
#[must_use = must_use_ctor_assign!("ConstRvalueReference")]
#[repr(transparent)]
#[cfg_attr(all(not(doc), feature = "same_abi"), doc = "CRUBIT_ANNOTATE: same_abi=")]
pub struct ConstRvalueReference<'a, T: ?Sized>(pub &'a T);
impl<'a, T: ?Sized> ConstRvalueReference<'a, T> {
pub fn get_ref(&mut self) -> &'a T {
self.0
}
}
impl<T: ?Sized> Deref for ConstRvalueReference<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.0
}
}
// SAFETY: unconditionally initializes dest.
unsafe impl<'a, T: ?Sized> Ctor for ConstRvalueReference<'a, T>
where
T: CtorNew<Self>,
{
type Output = T;
type Error = <T as CtorNew<Self>>::Error;
unsafe fn ctor(self, dest: *mut T) -> Result<(), Self::Error> {
unsafe { T::ctor_new(self).ctor(dest) }
}
}
/// !SelfCtor to override the blanket `Ctor` impl.
impl<'a, T: ?Sized> !SelfCtor for ConstRvalueReference<'a, T> {}
/// Creates an `RvalueReference` from `p`, indicating that it is to be moved.
///
/// This is analogous to C++ `std::move`, except that this can directly create an
/// `RvalueReference<T>` out of e.g. a `Pin<Box<T>>`. The resulting `RvalueReference` has the
/// lifetime of a temporary, after which the parameter is destroyed.
///
/// The resulting `RvalueReference` can be used as a `CtorNew` or `Assign`
/// source, or as a `Ctor` directly.
///
/// Note: this does not actually move the parameter until it is used.
#[macro_export]
macro_rules! mov {
($p:expr) => {
$crate::DerefRvalueReference::deref_rvalue_reference(&mut ($p))
};
}
#[macro_export]
macro_rules! const_mov {
($p:expr) => {
$crate::ConstRvalueReference(&*{ $p })
};
}
// =============
// Blanket impls
// =============
//
// For interop with C++ templates that may need to take Rust types, we will want
// blanket impls for Rust types where it is safe to do so.
/// All Rust types are their own constructor (except those that implement `Ctor`
/// for another type, see `SelfCtor` above.)
///
/// This allows code to safely accept direct initialization of Rust-movable
/// values, while also accepting customized in-place pinned initialization for
/// non-Rust-movable values: use `Ctor`-based initialization for both.
//
// SAFETY: unconditionally initializes dest. Note that while it is pinned after construction,
// it is not pinned beforehand, as we accept it by value. (If it was meant to be pinned, the UB
// already happened as part of passing self by value, and nothing we do here adds additional UB.)
unsafe impl<T: SelfCtor> Ctor for T {
type Output = T;
type Error = Infallible;
unsafe fn ctor(self, dest: *mut Self) -> Result<(), Infallible> {
// SAFETY: dest is valid for writes and uninitialized.
unsafe {
dest.write(self);
}
Ok(())
}
}
/// Constructs via a Rust move.
#[must_use = must_use_ctor!()]
pub struct RustMoveCtor<T, E = Infallible>(T, PhantomData<fn() -> E>);
impl<T, E> !SelfCtor for RustMoveCtor<T, E> {}
impl<T, E> RustMoveCtor<T, E> {
pub fn new(x: T) -> Self {
RustMoveCtor(x, PhantomData)
}
}
// SAFETY: unconditionally initializes dest.
unsafe impl<T, E> Ctor for RustMoveCtor<T, E> {
type Output = T;
type Error = E;
unsafe fn ctor(self, dest: *mut T) -> Result<(), E> {
// SAFETY: dest is valid for writes and uninitialized.
unsafe {
dest.write(self.0);
}
Ok(())
}
}
/// A `Ctor` which represents unreachable control flow.
///
/// This can be used instead of `!`, when an `impl Ctor` is needed:
///
/// ```
/// pub fn foo() -> impl Ctor<Output=Bar, Error=Infallible> {
/// todo!("TODO: implement foo");
/// #[allow(unreachable_code)]
/// UnreachableCtor::new()
/// }
/// ```
///
/// Unfortunately, it is not enough to have just a `todo!()`, because
/// `!` doesn't implement `Ctor<Output=Bar>`. (Or, if it did, it would
/// not implement `Ctor<Output=Baz>`.) `UnreachableCtor` implements
/// `Ctor<Output=T>` for any `T`, and can be used to satisfy the type
/// obligations.
#[must_use = must_use_ctor!()]
#[derive(Copy, Clone)]
pub struct UnreachableCtor<T: ?Sized, E = Infallible>(PhantomData<(fn() -> T, fn() -> E)>);
impl<T: ?Sized, E> UnreachableCtor<T, E> {
pub fn new() -> Self {
UnreachableCtor(PhantomData)
}
}
impl<T: ?Sized, E> !SelfCtor for UnreachableCtor<T, E> {}
// TODO(jeanpierreda): Might be more interesting to make this return `Result<!, ()>`,
// but that requires unstable features, and also means it can't be used in `emplace!`.
// SAFETY: always panics, so trivially satisfies postconditions.
unsafe impl<T: ?Sized, E> Ctor for UnreachableCtor<T, E> {
type Output = T;
type Error = E;
unsafe fn ctor(self, _: *mut T) -> Result<(), E> {
unreachable!();
}
}
/// All Rust types that implement `Default` are C++-default-constructible.
impl<T: Default> CtorNew<()> for T {
type CtorType = RustMoveCtor<Self>;
type Error = Infallible;
fn ctor_new(_: ()) -> Self::CtorType {
RustMoveCtor::new(Default::default())
}
}
/// All Rust types are C++-copyable if they are Rust-cloneable.
impl<T: Clone> CtorNew<&T> for T {
type CtorType = RustMoveCtor<Self>;
type Error = Infallible;
fn ctor_new(src: &Self) -> Self::CtorType {
RustMoveCtor::new(src.clone())
}
}
// ========
// emplace!
// ========
/// In-place construct a `Ctor`.
///
/// This is analoogus to the `pin!()` macro, except that it runs user-defined construction logic
/// via the `Ctor` trait.
///
/// Usage:
///
/// ```
/// /// If some_ctor is a `Ctor<Output=T, Error=Infallible>`, then:
/// let x: Pin<&mut T> = emplace!(some_ctor);
/// ```
///
/// `emplace!` only works with infallible `Ctor`s. See `try_emplace` for
/// initializing `Ctor` objects that can return an error.
#[macro_export]
#[allow_internal_unstable(super_let)]
// `super` gets removed by rustfmt, apparently.
#[rustfmt::skip]
macro_rules! emplace {
($expr:expr) => {
{
super let mut slot = $crate::Slot::unsafe_new();
// `$expr` is evaluated outside of the `unsafe` block below, so that the
// block doesn't cover user code. A `match` (rather than a `let`) keeps
// temporaries created by `$expr` alive until construction is done.
match $expr {
ctor => {
// SAFETY:
// - `unsafe_construct`: `slot` was just created by `Slot::unsafe_new`,
// so it is uninitialized. It is a `super let` local which this
// macro never moves, and which is only reachable through the
// returned `Pin<&mut T>`, so it stays in place until it is
// dropped, and dropping it drops the value (`Slot`'s `Drop`).
// - `unsafe_as_pin_unchecked`: `unsafe_construct` returned, so
// `slot` holds an initialized `T` (it panics otherwise), and
// `slot` is pinned as argued above.
unsafe { slot.unsafe_construct(ctor).unsafe_as_pin_unchecked() }
}
}
}
};
}
/// In-place construct a fallible `Ctor`.
///
/// The resulting value will be a `Result<Pin<&mut C::Output>, C::Error>` where `C` is the type of
/// the provided `Ctor`.
///
/// This is similar to `emplace!`, but can be used with fallible `Ctor`s (ones with an error type
/// that is not `Infallible`).
#[macro_export]
#[allow_internal_unstable(super_let)]
// `super` gets removed by rustfmt, apparently.
#[rustfmt::skip]
macro_rules! try_emplace {
($expr:expr) => {
{
super let mut slot = $crate::Slot::unsafe_new();
// See `emplace!` for why `$expr` is evaluated in a `match`.
match $expr {
ctor => {
// SAFETY: `slot` was just created by `Slot::unsafe_new`, so it is
// uninitialized. It is a `super let` local which this macro never
// moves, and which is only reachable through the returned
// `Pin<&mut T>`, so it stays in place until it is dropped, and
// dropping it drops the value, if any (`Slot`'s `Drop`).
unsafe { slot.try_unsafe_construct(ctor) }
}
}
}
};
}
// ====
// Slot
// ====
//
// Alternate design: we could expose without the is_initialized flag, which
// would require that all users initialize the type before drop. We may still
// need such a type for interop, since that can be repr(transparent). But it is
// *exceptionally* dangerous, as it requires that all code paths will initialize
// before drop. For example, it means that Ctor is not allowed to panic.
//
// Hypothesis: at least for local variables and reasoning, rustc will be able to
// elide the bool and be equally performant, while also being substantially
// safer.
/// A pinned optional type, which can store in-place constructed objects.
///
/// To create a slot safely, it must be constructed in place, using (for
/// example) the `emplace!` macro. It then can operate as a structurally pinned
/// variant of `Option`, allowing for pinned access to the interior.
///
/// Examples:
///
/// ```
/// // Slots can be used to implement a "slotted return value".
/// fn slotted_return(slot: Pin<&mut Slot<u32>>) -> Pin<&mut u32> {
/// slot.replace(42)
/// }
///
/// let slot = emplace! (Slot::uninit());
/// let rv = slotted_return(slot);
/// assert_eq!(*rv, 42);
/// ```
///
/// ```
/// // Slots can also be used for plain output parameters.
/// fn slotted_out_param(slot: Pin<&mut Slot<u32>>) {
/// slot.replace(42);
/// }
///
/// let mut slot = emplace!(Slot::uninit());
/// slotted_out_param(slot.as_mut());
/// assert_eq!(*slot.as_opt().unwrap(), 42);
/// ```
pub struct Slot<T> {
is_initialized: bool,
maybe_uninit: MaybeUninit<T>,
}
impl<T> Drop for Slot<T> {
fn drop(&mut self) {
unsafe { Pin::new_unchecked(self) }.clear()
}
}
impl<T> !Unpin for Slot<T> {}
impl<T> Slot<T> {
pub fn uninit() -> impl Ctor<Output = Self, Error = Infallible> {
RustMoveCtor::new(Self::unsafe_new())
}
pub fn new<C: Ctor<Output = T>>(value: C) -> impl Ctor<Output = Self, Error = C::Error> {
RustMoveCtor::new(Self::unsafe_new()).ctor_then(|slot| {
slot.try_replace(value)?;
Ok(())
})
}
pub fn clear(self: Pin<&mut Self>) {
if self.is_initialized {
let Self { is_initialized, maybe_uninit } = unsafe { Pin::into_inner_unchecked(self) };
// Mark the slot as uninitialized *before* dropping the value. If `T::drop` panics,
// the value is still considered dropped, and `Slot::drop` (which runs during
// unwinding) must not drop it a second time.
*is_initialized = false;
// SAFETY: `is_initialized` was true, so `maybe_uninit` holds a valid, pinned `T`,
// which is dropped in place exactly once.
unsafe {
core::ptr::drop_in_place(maybe_uninit.as_mut_ptr());
}
}
}
/// Replace the value in the slot, and return a pinned reference to the
/// result.
///
/// Requires that the `Ctor` is infallible.
pub fn replace<C: Ctor<Output = T, Error = Infallible>>(
self: Pin<&mut Self>,
value: C,
) -> Pin<&mut T> {
self.try_replace(value).unwrap()
}
/// Replace the value in the slot, and return a pinned reference to the
/// result. Returns an error if the `Ctor` returns an error.
pub fn try_replace<C: Ctor<Output = T>>(
mut self: Pin<&mut Self>,
value: C,
) -> Result<Pin<&mut T>, C::Error> {
self.as_mut().clear();
{
let Self { is_initialized, maybe_uninit } =
unsafe { Pin::into_inner_unchecked(self.as_mut()) };
// SAFETY: the memory is struturally pinned and valid for writes,
// and it's uninitialized because of the .clear() call above.
unsafe {
value.ctor(maybe_uninit.as_mut_ptr())?;
}
*is_initialized = true;
}
Ok(self.as_opt_mut().unwrap())
}
pub fn as_opt_mut(self: Pin<&mut Self>) -> Option<Pin<&mut T>> {
if self.is_initialized {
// SAFETY: `self` is pinned, so we don't move out of the result of
// `into_inner_unchecked`. `unsafe_as_pin_unchecked`: `self` was just checked
// to be initialized, and it is pinned because we have a `Pin<&mut Self>`
// (`maybe_uninit` is structurally pinned).
Some(unsafe { Pin::into_inner_unchecked(self).unsafe_as_pin_unchecked() })
} else {
None
}
}
pub fn as_opt(&self) -> Option<&T> {
if self.is_initialized {
Some(unsafe { self.maybe_uninit.assume_init_ref() })
} else {
None
}
}
}
// Hidden: these are only for use by safety macros.
#[doc(hidden)]
impl<T> Slot<T> {
pub fn unsafe_new() -> Self {
Slot { is_initialized: false, maybe_uninit: MaybeUninit::uninit() }
}
/// Constructs a value in this (uninitialized) slot, in place.
///
/// Panics if `ctor` panics, in which case the slot is left uninitialized.
///
/// # Safety
///
/// The caller must ensure that:
///
/// 1. `self` is uninitialized: it was created by `Slot::unsafe_new`, and no value has been
/// constructed in it since. (Otherwise, the existing value would be overwritten without
/// being dropped, which violates the drop guarantee of `Pin` if it has been pinned.)
/// 2. From this call on, `*self` is pinned: unless `T: Unpin`, it is never moved, and its
/// memory is never deallocated or reused without first dropping `*self` (which drops the
/// constructed value) or otherwise dropping the constructed value in place.
///
/// If these hold and this function returns, `self` holds an initialized `T`,
/// and `self.unsafe_as_pin_unchecked()` may be called on the result.
pub unsafe fn unsafe_construct(
&mut self,
ctor: impl Ctor<Output = T, Error = Infallible>,
) -> &mut Self {
// SAFETY: `self.maybe_uninit.as_mut_ptr()` comes from a live `&mut`, so it is
// valid for writes of a `T`. It is uninitialized by precondition 1, and the
// pointee stays pinned by precondition 2, as `Ctor::ctor` requires.
unsafe { ctor.ctor(self.maybe_uninit.as_mut_ptr()).unwrap() };
// `ctor` returned (an `Infallible` error can't be returned), so per the
// `Ctor::ctor` contract `maybe_uninit` is now initialized.
self.is_initialized = true;
self
}
/// Constructs a value in this (uninitialized) slot, in place, and returns a
/// pinned reference to it.
///
/// If `ctor` returns an error (or panics), the slot is left uninitialized.
///
/// # Safety
///
/// Same as [`Slot::unsafe_construct`]: the caller must ensure that `self` is
/// uninitialized (created by `Slot::unsafe_new`, with no value constructed in
/// it since), and that from this call on, `*self` is pinned.
pub unsafe fn try_unsafe_construct<C: Ctor<Output = T>>(
&mut self,
ctor: C,
) -> Result<Pin<&mut T>, C::Error> {
// SAFETY: `self.maybe_uninit.as_mut_ptr()` comes from a live `&mut`, so it is
// valid for writes of a `T`. It is uninitialized and stays pinned by this
// function's preconditions, as `Ctor::ctor` requires.
unsafe { ctor.ctor(self.maybe_uninit.as_mut_ptr())? };
// `ctor` returned `Ok`, so per the `Ctor::ctor` contract `maybe_uninit` is
// now initialized.
self.is_initialized = true;
// SAFETY: `self` was just initialized above, and it is pinned by this
// function's precondition.
Ok(unsafe { self.unsafe_as_pin_unchecked() })
}
/// Returns a pinned reference to the value in this slot, without checking
/// whether the slot is initialized.
///
/// # Safety
///
/// The caller must ensure that:
///
/// 1. `self` is initialized (`self.is_initialized` is true), e.g. because `unsafe_construct` or
/// `try_unsafe_construct` returned successfully on it and the value hasn't been cleared
/// since.
/// 2. `*self` is pinned: unless `T: Unpin`, it is never moved, and its memory is never
/// deallocated or reused without first dropping the value in place (e.g. by dropping
/// `*self`).
pub unsafe fn unsafe_as_pin_unchecked(&mut self) -> Pin<&mut T> {
// SAFETY:
// - `assume_init_mut`: `maybe_uninit` is initialized by precondition 1.
// - `Pin::new_unchecked`: the pointee is pinned by precondition 2, and `&mut T` has no
// custom `Deref`/`DerefMut` that could move it.
unsafe { Pin::new_unchecked(self.maybe_uninit.assume_init_mut()) }
}
}
#[doc(hidden)]
pub mod macro_internal {
use super::*;
pub use crate::Infallible;
pub use core::mem::MaybeUninit;
pub use core::pin::Pin;
/// A helpfully named type alias that tells users to not directly initialize fields of this type
pub type MustUseCtorToInitialize = [u8; 0];
/// Workaround for more_qualified_paths.
/// Instead of `<Foo as Bar>::Assoc { ... }`, which requires that feature,
/// we can use `Identity<<Foo as Bar>::Assoc> { ... }`.
///
/// See https://github.com/rust-lang/rust/issues/86935#issuecomment-1146670057
///
/// TODO(jeanpierreda): Delete this when the feature is stabilized.
pub type Identity<T> = T;
/// Trait which causes compilation error if a `#[recursively_pinned]` struct
/// impls `Drop`.
///
/// Idea from https://docs.rs/pin-project/latest/pin_project/attr.pin_project.html#safety
pub trait DoNotImplDrop {}
#[allow(drop_bounds)]
impl<T: Drop> DoNotImplDrop for T {}
/// Drops a pointer when dropped.
///
/// Safety: this will drop the pointer, so this is only safe if no other
/// code will access the pointer afterwards. This includes drop: the
/// pointer must itself be in a ManuallyDrop.
pub struct UnsafeDropGuard<T>(*mut T);
impl<T> Drop for UnsafeDropGuard<T> {
fn drop(&mut self) {
unsafe { core::ptr::drop_in_place(self.0) };
}
}
/// Initializes a field, and returns a drop guard which will drop that
/// field.
///
/// Intended use: when initializing a struct field-by-field, each
/// initialized field should be guarded in case of panic. Once the
/// struct is completely initialized, the drop guards can be forgotten
/// with `std::mem::forget()`. See the `ctor!` macro, where this is used.
///
/// Safety: the field must satisfy the Pin guarantee.
pub unsafe fn init_field<T>(
field: *mut T,
ctor: impl Ctor<Output = T, Error = Infallible>,
) -> impl Drop {
// safety: the field is not yet initialized, the caller guarantees it's
// pinned.
unsafe {
Ctor::ctor(ctor, field).unwrap();
}
UnsafeDropGuard(field)
}
pub fn require_recursively_pinned<_T: RecursivelyPinned>() {}
/// Function which requires `unsafe` and is called by `raw_ctor!()`.
///
/// This gives a pleasing error message, as they have the same name.
pub unsafe fn raw_ctor() {}
/// Create an `FnOnce`. This works around Rust trying to infer that a closure is
/// `Fn`.
pub fn make_fn_once<Output, F: FnOnce(*mut Output)>(f: F) -> impl FnOnce(*mut Output) {
f
}
}
// =====================
// #[recursively_pinned]
// =====================
/// The `RecursivelyPinned` trait asserts that when the struct is pinned, every
/// (non-Unpin) field is also pinned.
///
/// This trait is automatically implemented for any `#[recursively_pinned]`
/// struct.
///
/// ## Safety
///
/// * All fields of the struct are pinned in all code paths that access them.
/// * The `CtorInitializedFields` type has the same fields as `Self`, except for any fields that do
/// not need initialization. (For instance, ZST fields or fields of type `MaybeUninit`.)
pub unsafe trait RecursivelyPinned {
/// An associated type with the same fields as `Self`, minus any ZST
/// fields hich are not initialized by the `ctor!()` macro.
///
/// The intended use of this is to help disable direct initialization of
/// the type and *require* the use of `ctor!()`. This forces the struct
/// to only ever exist in a pinned state.
///
/// ```
/// // (Alternatively, `#[non_exhaustive]` may be used instead of the private field.)
/// pub struct CtorOnly {
/// pub field: i32,
/// _must_construct_using_ctor: [(); 0],
/// }
///
/// // The same struct, but without the private field.
/// // (Alternatively, without `#[non_exhaustive]`.)
/// pub struct CtorOnlyFields {
/// pub field: i32,
/// }
///
/// unsafe impl RecursivelyPinned for CtorOnly {
/// type CtorInitializedFields = CtorOnlyFields;
/// }
/// ```
///
/// By using `CtorInitializedFields` paired with a private field (or
/// `#[non_exhaustive]`), the following code is now invalid:
///
/// ```ignore
/// # // TODO(jeanpierreda): make this tested, somehow.
/// // Fails to compile: did not specify _must_construct_using_ctor, and cannot,
/// // because it is private
/// let x = CtorOnly {field: 3};
/// ```
///
/// While construction using `ctor!()` works fine:
///
/// ```ignore
/// let x = emplace!(ctor!(CtorOnly {field: 3}));
/// ```
///
/// The size and layout of `CtorInitializedFields` is ignored; it only
/// affects which field names are required for complete `ctor!()`
/// initialization. Any fields left out of the `CtorInitializedFields` type
/// will not be initialized, so they must permit uninitialized memory.
/// (For example, ZST or MaybeUninit.)
type CtorInitializedFields: ?Sized;
}
/// The drop trait for `#[recursively_pinned(PinnedDrop)]` types.
///
/// It is not safe to implement `Drop` for a recursively-pinned type, as this
/// would be unsound: the `&mut self` in `drop` would allow the pin guarantee to
/// be violated.
///
/// Instead, to implement `Drop`, users of `#[recursively_pinned]` must pass `PinnedDrop` to
/// `recursively_pinned`, and implement the `PinnedDrop` trait.
///
/// See also the [analogous `pin_project` feature](https://docs.rs/pin-project/latest/pin_project/attr.pinned_drop.html)
pub trait PinnedDrop {
/// Run the drop logic for self.
///
/// ## Safety
///
/// If called from anywhere other than the automatically-generated
/// `Drop::drop`, the behavior is undefined.
///
/// To manually drop the value, use `ManuallyDrop` or use
/// `std::ptr::drop_in_place` (etc.) instead.
unsafe fn pinned_drop(self: Pin<&mut Self>);
}
// =====
// ctor!
// =====
/// Evaluates to a `Ctor` which initializes a struct in-place, field-by-field.
///
/// The `ctor!` macro evaluates to a `Ctor` for a Rust struct. Each field has its value provided
/// using a `Ctor`, so that each is initialized in-place.
///
/// Example use:
///
/// ```
/// fn new() -> impl Ctor<Output=MyStruct> {
/// ctor!(MyStruct {field_1: MyType::ctor_new(()), field_2: 42})
/// }
///
/// // Actually invoke the Ctor to create a new MyStruct:
/// let mut my_struct = emplace!(MyStruct::new());
///
/// The type must implement `RecursivelyPinned`, so that `ctor!()` can
/// safely construct the struct pinned in place.
/// ```
#[macro_export]
macro_rules! ctor {
// Struct {} ctor.
( $t:ident $(:: $ts:ident)* $(:: < $($gp:tt),+ >)? {$($body:tt)*} ) => {
{
use $t $(:: $ts)* as Type;
$crate::unsafe_ctor_impl!(
#[fields =
<Type $(< $( $gp ),+ >)? as $crate::RecursivelyPinned>::CtorInitializedFields]
#[unsafe_assert = $crate::macro_internal::require_recursively_pinned::<Type $(< $( $gp ),+ >)?>();]
Type $(:: < $($gp),+ >)? {$($body)*}
)
}
};
// Unit struct ctor.
($t:ident $(:: $ts:ident)* $(:: < $($gp:tt),+ >)? ) => {$crate::ctor!($t $(:: $ts)* $(:: < $($gp),+ >)? { })};
// Conventional tuple struct syntax (with parens, no integer names) supported for < 8 fields.
// Otherwise, use MyTupleStruct{0: ..., 1: ...} syntax, which works for any number of fields.
// Generated as so:
/* python3 -c 'for i in range(8):
ctor_ins = ", ".join(f"$ctor_{j}:expr" for j in range(i))
ctor_outs = ", ".join(f"{j}: $ctor_{j}" for j in range(i))
print(f" ($t:ident $(:: $ts:ident)* $(:: < $($gp:tt),+ >)? ({ctor_ins})) => {{$crate::ctor!($t $(:: $ts)* $(:: < $($gp),+ >)? {{ {ctor_outs} }})}};")' */
($t:ident $(:: $ts:ident)* $(:: < $($gp:tt),+ >)? ()) => {$crate::ctor!($t $(:: $ts)* $(:: < $($gp),+ >)? { })};
($t:ident $(:: $ts:ident)* $(:: < $($gp:tt),+ >)? ($ctor_0:expr)) => {$crate::ctor!($t $(:: $ts)* $(:: < $($gp),+ >)? { 0: $ctor_0 })};
($t:ident $(:: $ts:ident)* $(:: < $($gp:tt),+ >)? ($ctor_0:expr, $ctor_1:expr)) => {$crate::ctor!($t $(:: $ts)* $(:: < $($gp),+ >)? { 0: $ctor_0, 1: $ctor_1 })};
($t:ident $(:: $ts:ident)* $(:: < $($gp:tt),+ >)? ($ctor_0:expr, $ctor_1:expr, $ctor_2:expr)) => {$crate::ctor!($t $(:: $ts)* $(:: < $($gp),+ >)? { 0: $ctor_0, 1: $ctor_1, 2: $ctor_2 })};
($t:ident $(:: $ts:ident)* $(:: < $($gp:tt),+ >)? ($ctor_0:expr, $ctor_1:expr, $ctor_2:expr, $ctor_3:expr)) => {$crate::ctor!($t $(:: $ts)* $(:: < $($gp),+ >)? { 0: $ctor_0, 1: $ctor_1, 2: $ctor_2, 3: $ctor_3 })};
($t:ident $(:: $ts:ident)* $(:: < $($gp:tt),+ >)? ($ctor_0:expr, $ctor_1:expr, $ctor_2:expr, $ctor_3:expr, $ctor_4:expr)) => {$crate::ctor!($t $(:: $ts)* $(:: < $($gp),+ >)? { 0: $ctor_0, 1: $ctor_1, 2: $ctor_2, 3: $ctor_3, 4: $ctor_4 })};
($t:ident $(:: $ts:ident)* $(:: < $($gp:tt),+ >)? ($ctor_0:expr, $ctor_1:expr, $ctor_2:expr, $ctor_3:expr, $ctor_4:expr, $ctor_5:expr)) => {$crate::ctor!($t $(:: $ts)* $(:: < $($gp),+ >)? { 0: $ctor_0, 1: $ctor_1, 2: $ctor_2, 3: $ctor_3, 4: $ctor_4, 5: $ctor_5 })};
($t:ident $(:: $ts:ident)* $(:: < $($gp:tt),+ >)? ($ctor_0:expr, $ctor_1:expr, $ctor_2:expr, $ctor_3:expr, $ctor_4:expr, $ctor_5:expr, $ctor_6:expr)) => {$crate::ctor!($t $(:: $ts)* $(:: < $($gp),+ >)? { 0: $ctor_0, 1: $ctor_1, 2: $ctor_2, 3: $ctor_3, 4: $ctor_4, 5: $ctor_5, 6: $ctor_6 })};
}
/// Unsafe in-place construction of a struct, field by field.
///
/// The `raw_ctor!` macro evaluates to a `Ctor` for a Rust struct, with
/// user-specified values for the fields, each also initialized in-place.
///
/// This is identical in use to `ctor!`, but it does not enforce that the
/// struct is `RecursivelyPinned`.
///
/// The caller must ensure that the struct meets the safety criteria of
/// `RecursivelyPinned`.
///
/// If the struct would have used a different `CtorInitializedFields` type,
/// this can be specified using `#[fields = ...]`, as so:
///
/// ```
/// raw_ctor!(#[fields = Mystruct2] MyStruct { field: 42 })
/// ```
///
/// NOTE: `raw_ctor` only supports `struct {}` syntax.
#[macro_export]
macro_rules! raw_ctor {
( $t:ident $(:: $ts:ident)* $(:: < $($gp:tt),+ >)? {$($body:tt)*} ) => {
{
use $t $(:: $ts)* as Type;
$crate::unsafe_ctor_impl!(
#[fields = Type $(< $( $gp ),+ >)?]
#[unsafe_assert = $crate::macro_internal::raw_ctor();]
Type $(:: < $($gp),+ >)? {$($body)*}
)
}
};
( #[fields = $($fields_ty:tt)*] $t:ident $(:: $ts:ident)* $(:: < $($gp:tt),+ >)? {$($body:tt)*} ) => {
{
use $t $(:: $ts)* as Type;
$crate::unsafe_ctor_impl!(
#[fields = $($fields_ty)*]
#[unsafe_assert = $crate::macro_internal::raw_ctor();]
Type $(:: < $($gp),+ >)? {$($body)*}
)
}
};
}
/// Implementation of the ctor! macro.
///
/// # Safety
///
/// * fields_ty must have every field that `$Type` does.
// Note: we're using `ident (::ident)*` for the type names because neither `ident` nor `path`
// really work perfectly -- `ident` is great, except that `foo::bar` isn't an ident. `path` is
// great, except that e.g. parentheses can't follow a path. (This is not fixable: FnOnce(T) is
// also a path, so parens can't follow paths due to the ambiguous parse). Thus... we use ident,
// and manually reconstruct the path.
//
// TODO(jeanpierreda): support <X as Y> and foo<Z> in paths.
//
// tt is used for the field names, because this allows for both integer fields for tuple
// structs, and named fields for non-tuple structs.
#[doc(hidden)]
#[macro_export]
macro_rules! unsafe_ctor_impl {
( #[fields = $($fields_ty:tt)*]
#[unsafe_assert = $($unsafe_assert:tt)*]
$Type:ident $(:: < $($gp:tt),+ >)? {$( $name:tt: $sub_ctor:expr ),* $(,)?}
) => {{
// We need to capture all the sub_ctor values in advance (in case they are Copy and thus
// borrowed by reference).
//
// Note that we can't just do `move ||` without pre-binding them, in case
// they want to borrow something. Consider: `ctor!(Foo(f(&x))`. A move closure
// will capture `x` by value, but in fact we only want to capture `&x` by value.
//
// Ordinarily, we'd do something like `$(let $name = $sub_ctor;)*`, but `$name`
// can be an integer for tuple-structs. So, instead, we build everything up into a tuple
// that we can progressively unpack.
let capture = $crate::internal_hlist!($($sub_ctor,)*);
let _ = &capture; // silence unused_variables warning if Type is fieldless.
let init = $crate::macro_internal::make_fn_once(move |x: *mut $Type $(< $( $gp ),+ >)?| {
struct DropGuard;
let drop_guard = DropGuard;
let _ = &x; // silence unused_variables warning if Type is fieldless.
// Enforce that the ctor!()/etc. expression resembles a valid direct initialization
// expression, by using the names in a conventional literal.
// For structs, this fails to compile unless the names are fully exhaustive.
// For unions, it fails to compile unless precisely one name is used.
// In both cases, this ensures that we only compile when expressions corresponding
// to normal init are used, with unsurprising semantics.
let _ = |x: $Type $(< $( $gp ),+ >)?| {
let _ = &x; // silence unused_variables warning if Type is fieldless.
// If this fails to compile, not every field was specified in the ctor! invocation.
// The `panic!(...)` allows us to avoid moving out of x, while still pretending to
// fill in each field.
#[allow(unreachable_code, unused_unsafe)] $crate::macro_internal::Identity::<
$($fields_ty)*> {
// SAFETY: this code is not executed.
// The unsafe {} block is in case this is a *union* literal, rather than
// a struct literal.
$($name: panic!("{}", unsafe {&x.$name} as *const _ as usize),)*
};
};
$($unsafe_assert)*
$(
let (sub_ctor, capture) = capture;
let field_drop = unsafe {
// SAFETY: the place is in bounds, just uninitialized. See e.g. second
// example: https://doc.rust-lang.org/nightly/std/ptr/macro.addr_of_mut.html
$crate::macro_internal::init_field(
&raw mut (*x).$name,
sub_ctor)
};
let drop_guard = (drop_guard, field_drop);
)*
#[allow(clippy::forget_non_drop)] // if fieldless
::core::mem::forget(drop_guard);
});
// SAFETY: In the non-panicking case, we initialize each field using `Ctor::ctor`, which
// guarantees initialization.
//
// We guarantee that no fields are missed by pretending to construct using ordinary Rust
// struct syntax in a never-executed code path. If the user failed to
// mention initialization of a field, then this will fail with a compilation error.
// The type used is specified by $fields_ty, which must be correct for this to be
// safe to call. (In practice, it's either unsafely passed by the user, or
// automatically generated to match by `#[recursively_pinned]`).
unsafe {$crate::FnCtor::new(init)}
}};
}
/// Creates a linked list. `internal_hlist!(a, b, c)` -> `(a, (b, (c, ()))`
#[doc(hidden)]
#[macro_export]
macro_rules! internal_hlist {
($(,)?) => {
()
};
($a:expr, $($rest:tt)*) => {
($a, $crate::internal_hlist!($($rest)*))
};
}
// ==========
// Assignment
// ==========
/// Destroy-then-reconstruct. Sidesteps `operator=`, instead reconstructing
/// in-place.
///
/// For Rust-movable types, this is equivalent to `*p.as_mut().into_inner() = construct(ctor)`.
///
/// If the object cannot be destroyed/reconstructed in place (e.g. it is a base
/// class subobject), the behavior is undefined.
///
/// If `ctor` unwinds, the process will crash.
///
/// This is a bit more fragile than, and a lot less common than, `operator=`,
/// but allows for taking advantage of copy/move elision more aggressively,
/// rather than requiring materialization into a temporary before triggering
/// assignment.
///
/// That means that e.g. instead of calling `x.assign(&*emplace!(foo))`, you can
/// directly call `reconstruct(x, foo)` -- provided you are OK with the
/// differing constructor/destructor ordering, and satisfy safety criteria.
///
/// # Safety
///
/// The behavior is only undefined if `p` refers to C++ object storage, and is a
/// base class subobject or `[[no_unique_address]]` member.
/// See: http://eel.is/c++draft/basic.life#8.
///
/// If `p` refers to an object stored anywhere else, such as a (non-`no_unique_address`)
/// field of a struct, or a local variable, then this is safe. In particular, if the caller is
/// pure Rust code, and uses ordinary Rust storage, then this is safe.
///
/// (Note that since this calls `drop()` on the pinned pointer, it satisfies the pin
/// guarantee, and is allowed to then re-init it with something else. In effect, this
/// is just the in-place Ctor version of the existing method `Pin<T>::set(T)`.)
pub unsafe fn reconstruct<T>(p: Pin<&mut T>, ctor: impl Ctor<Output = T, Error = Infallible>) {
let raw_ptr = unsafe { Pin::into_inner_unchecked(p) } as *mut _;
unsafe {
core::ptr::drop_in_place(raw_ptr);
}
abort_on_unwind(move || {
unsafe { ctor.ctor(raw_ptr) }.unwrap();
});
}
/// Run f, aborting if it unwinds.
///
/// Because this aborts on unwind, f is not required to be unwind-safe.
#[inline]
fn abort_on_unwind<T, F: FnOnce() -> T>(f: F) -> T {
// Here is another way we COULD implement abort_on_panic:
// let f = std::panic::AssertUnwindSafe(f);
// let result = std::panic::catch_unwind(move || f.0());
// if result.is_err() {
// std::process::abort();
// }
// This would work, even for `extern "C-unwind"`, but that wasn't
// always the case. See https://doc.rust-lang.org/std/panic/fn.catch_unwind.html#notes
// and compare with https://rust-lang.github.io/rfcs/2945-c-unwind-abi.html
/// A safety guard which panics if dropped, converting unwinds into aborts.
///
/// In general, you can't, as the *author* of drop(), assume that it will be
/// called: callers can just call std::mem::forget(), among other
/// things. However, as the *user*, you can know that drop is called for
/// unmoved values at the end of a drop scope. Drop is a defined behavior.
/// So while there is ordinarily a prohibition on relying on drop for
/// safety, that only occurs for API owners that are allowing values to
/// be used in arbitrary ways (including forget). Here, we are API
/// *users* as well, and specifically using the Bomb in a way that
/// guarantees its drop will be called in a particular circumstance.
///
/// See https://doc.rust-lang.org/reference/destructors.html, specifically this: "When control
/// flow leaves a drop scope all variables associated to that scope are
/// dropped in reverse order of declaration (for variables) or creation
/// (for temporaries)."
struct Bomb;
impl Drop for Bomb {
fn drop(&mut self) {
panic!("Unwinding occurred when no safe recovery is possible.");
}
}
let bomb = Bomb;
let rv = f();
core::mem::forget(bomb);
rv
}
/// Overloaded assignment operator.
///
/// Conventionally, C++ copy-assignment is Assign<&T>, and C++ move-assignment
/// is Assign<RvalueReference<'_, T>>.
pub trait Assign<From> {
fn assign(self: Pin<&mut Self>, src: From);
}
/// Assignment from a Copy desugars to an assignment from a &T.
impl<T: for<'a> Assign<&'a T>, P: Deref<Target = T>> Assign<Copy<P>> for T {
fn assign(self: Pin<&mut Self>, src: Copy<P>) {
self.assign(&*src.0);
}
}
// TODO(jeanpierreda): Make these less repetitive.
impl<'a, T> Assign<&'a T> for T
where
T: Unpin + CtorNew<&'a T, Error = Infallible>,
{
fn assign(mut self: Pin<&mut Self>, src: &'a Self) {
*self = construct(T::ctor_new(src));
}
}
impl<'a, T> Assign<RvalueReference<'a, T>> for T
where
T: Unpin + CtorNew<RvalueReference<'a, T>, Error = Infallible>,
{
fn assign(mut self: Pin<&mut Self>, src: RvalueReference<'a, Self>) {
*self = construct(T::ctor_new(src));
}
}
impl<'a, T> Assign<ConstRvalueReference<'a, T>> for T
where
T: Unpin + CtorNew<ConstRvalueReference<'a, T>, Error = Infallible>,
{
fn assign(mut self: Pin<&mut Self>, src: ConstRvalueReference<'a, Self>) {
*self = construct(T::ctor_new(src));
}
}
/// Overloaded assignment operator, but for Unpin types
/// TODO(b/219963671): use specialization instead of a distinct trait
pub trait UnpinAssign<From> {
fn unpin_assign(&mut self, src: From);
}
/// A conversion trait that is considered unsafe.
///
/// This is used for `Unpin` types when the conversion involves unsafe operations
/// or types.
pub trait UnsafeFrom<From> {
/// Performs the conversion.
///
/// # Safety
///
/// The caller must ensure that the conversion is safe.
unsafe fn unsafe_from(src: From) -> Self;
}
// =======================
// Constructor overloading
// =======================
/// Overloadable constructor trait.
///
/// This is analogous to `From<A>`, but it returns a `Ctor` instead of `Self` by value.
pub trait CtorNew<ConstructorArgs> {
type CtorType: Ctor<Output = Self, Error = Self::Error>;
type Error;
/// Returns the `Ctor` for a new instance.
fn ctor_new(args: ConstructorArgs) -> Self::CtorType;
}
/// Overloaded constructor trait for constructors that are considered unsafe.
///
/// This is used when the constructor accepts arguments that are unsafe to use,
/// or when the constructor itself is marked unsafe in C++.
///
/// The safety conditions are documented on the `UnsafeCtorNew` implementation.
pub trait UnsafeCtorNew<ConstructorArgs> {
type CtorType: Ctor<Output = Self, Error = Self::Error>;
type Error;
/// Creates a new constructor.
///
/// # Safety
///
/// The caller must ensure that the arguments are safe to use for construction, as
/// documented by the implementation.
unsafe fn ctor_new(args: ConstructorArgs) -> Self::CtorType;
}
// ====
// Misc
// ====
/// A constructor for ManuallyDrop<T>, given a constructor for T.
#[must_use = must_use_ctor!()]
pub struct ManuallyDropCtor<T: Ctor>(T);
impl<T: Ctor> ManuallyDropCtor<T> {
pub fn new(x: T) -> Self {
ManuallyDropCtor(x)
}
}
// SAFETY: unconditionally initializes dest.
unsafe impl<T: Ctor> Ctor for ManuallyDropCtor<T> {
type Output = ManuallyDrop<T::Output>;
type Error = T::Error;
unsafe fn ctor(self, dest: *mut Self::Output) -> Result<(), Self::Error> {
// Safety: ManuallyDrop<T> and T have the same layout.
// All other preconditions are satisfied by the caller.
unsafe { self.0.ctor(dest as *mut _) }
}
}
impl<T: Ctor> !SelfCtor for ManuallyDropCtor<T> {}