#![no_std]
#![cfg_attr(doc_cfg, feature(doc_cfg))]
#![cfg_attr(feature = "alloc_try_pin_with", feature(allocator_api))]
#![warn(unsafe_op_in_unsafe_fn)]
#![allow(clippy::new_without_default)]
#![allow(clippy::should_implement_trait)]
#![allow(clippy::needless_lifetimes)]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
mod unique;
pub use pin_init_internal::pin_init;
pub use pin_init_internal::init_pin;
#[cfg(feature = "alloc")]
pub use unique::{UniqueArc, UniqueRc};
use core::marker::PhantomData;
use core::mem;
use core::mem::MaybeUninit;
use core::pin::Pin;
#[cfg(feature = "alloc")]
use alloc::{boxed::Box, rc::Rc, sync::Arc};
#[cfg(feature = "alloc_try_pin_with")]
use core::alloc::AllocError;
#[cfg(feature = "alloc")]
use core::{mem::ManuallyDrop, ops::Deref};
pub struct PinUninit<'a, T> {
ptr: *mut MaybeUninit<T>,
_marker: PhantomData<&'a mut ()>,
}
impl<'a, T> PinUninit<'a, T> {
#[inline]
pub unsafe fn new(ptr: &'a mut MaybeUninit<T>) -> Self {
PinUninit {
ptr,
_marker: PhantomData,
}
}
#[inline]
pub fn get_mut(&mut self) -> &mut MaybeUninit<T> {
unsafe { &mut *self.ptr }
}
#[inline]
pub unsafe fn init_ok(self) -> InitOk<'a, T> {
InitOk {
ptr: self.ptr as *mut T,
marker: PhantomData,
}
}
#[inline]
pub fn init_err<E>(self, err: E) -> InitErr<'a, E> {
InitErr {
inner: err,
marker: PhantomData,
}
}
#[inline]
pub fn init<E, F>(self, value: F) -> InitResult<'a, T, E>
where
F: Init<T, E>,
{
value.__init(self)
}
#[inline]
pub fn init_with_value(mut self, value: T) -> InitOk<'a, T> {
unsafe { self.get_mut().as_mut_ptr().write(value) };
unsafe { self.init_ok() }
}
}
pub struct InitOk<'a, T> {
ptr: *mut T,
marker: PhantomData<&'a mut ()>,
}
impl<'a, T> InitOk<'a, T> {
#[inline]
pub fn as_ref(&self) -> Pin<&T> {
unsafe { Pin::new_unchecked(&*self.ptr) }
}
#[inline]
pub fn as_mut(&mut self) -> Pin<&mut T> {
unsafe { Pin::new_unchecked(&mut *self.ptr) }
}
#[inline]
pub fn into_inner(self) -> Pin<&'a mut T> {
unsafe { Pin::new_unchecked(&mut *self.ptr) }
}
}
pub struct InitErr<'a, E> {
inner: E,
marker: PhantomData<&'a mut ()>,
}
impl<'a, E> InitErr<'a, E> {
#[inline]
pub fn as_ref(&self) -> &E {
&self.inner
}
#[inline]
pub fn as_mut(&mut self) -> &mut E {
&mut self.inner
}
#[inline]
pub fn into_inner(self) -> E {
self.inner
}
#[inline]
pub fn map<T, F>(self, f: F) -> InitErr<'a, T>
where
F: FnOnce(E) -> T,
{
InitErr {
inner: f(self.inner),
marker: PhantomData,
}
}
}
pub type InitResult<'a, T, E> = Result<InitOk<'a, T>, InitErr<'a, E>>;
pub trait Init<T, E>: Sized {
fn __init<'a>(self, this: PinUninit<'a, T>) -> InitResult<'a, T, E>;
fn map_err<E2, F>(self, f: F) -> MapErr<T, E, E2, Self, F>
where
F: FnOnce(E) -> E2,
{
MapErr {
init: self,
map: f,
marker: PhantomData,
}
}
}
impl<T, E> Init<T, E> for T {
fn __init<'a>(self, this: PinUninit<'a, T>) -> InitResult<'a, T, E> {
Ok(this.init_with_value(self))
}
}
#[doc(hidden)]
pub struct MapErr<T, E, E2, I, F> {
init: I,
map: F,
#[allow(clippy::type_complexity)]
marker: PhantomData<(fn(T) -> E, fn(E) -> E2)>,
}
impl<T, E, E2, I, F> Init<T, E2> for MapErr<T, E, E2, I, F>
where
I: Init<T, E>,
F: FnOnce(E) -> E2,
{
fn __init<'a>(self, this: PinUninit<'a, T>) -> InitResult<'a, T, E2> {
match self.init.__init(this) {
Ok(v) => Ok(v),
Err(v) => Err(v.map(self.map)),
}
}
}
pub fn specify_err<T, E, I>(init: I) -> impl Init<T, E>
where
I: Init<T, E>,
{
init
}
pub fn init_from_closure<T, E, F>(f: F) -> impl Init<T, E>
where
F: for<'a> FnOnce(PinUninit<'a, T>) -> InitResult<'a, T, E>,
{
struct ClosureInit<T, E, F>(F, PhantomData<fn(T) -> E>)
where
F: for<'a> FnOnce(PinUninit<'a, T>) -> InitResult<'a, T, E>;
impl<T, E, F> Init<T, E> for ClosureInit<T, E, F>
where
F: for<'a> FnOnce(PinUninit<'a, T>) -> InitResult<'a, T, E>,
{
fn __init<'a>(self, this: PinUninit<'a, T>) -> InitResult<'a, T, E> {
(self.0)(this)
}
}
ClosureInit(f, PhantomData)
}
pub trait PtrInit<T>: Deref<Target = T> + Sized {
type Uninit: Deref<Target = MaybeUninit<T>>;
fn init<E, I>(uninit: Pin<Self::Uninit>, init: I) -> Result<Pin<Self>, E>
where
I: Init<T, E>;
}
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
impl<T> PtrInit<T> for Box<T> {
type Uninit = Box<MaybeUninit<T>>;
#[inline]
fn init<E, I>(uninit: Pin<Box<MaybeUninit<T>>>, init: I) -> Result<Pin<Box<T>>, E>
where
I: Init<T, E>,
{
let mut ptr = ManuallyDrop::new(unsafe { Pin::into_inner_unchecked(uninit) });
match init.__init(unsafe { PinUninit::new(&mut ptr) }) {
Ok(_) => {
Ok(unsafe { mem::transmute(ptr) })
}
Err(err) => {
let err = err.into_inner();
drop(ManuallyDrop::into_inner(ptr));
Err(err)
}
}
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
impl<T> PtrInit<T> for UniqueRc<T> {
type Uninit = UniqueRc<MaybeUninit<T>>;
#[inline]
fn init<E, I>(uninit: Pin<UniqueRc<MaybeUninit<T>>>, init: I) -> Result<Pin<UniqueRc<T>>, E>
where
I: Init<T, E>,
{
let mut ptr = ManuallyDrop::new(unsafe { Pin::into_inner_unchecked(uninit) });
match init.__init(unsafe { PinUninit::new(&mut ptr) }) {
Ok(_) => Ok(unsafe { mem::transmute(ptr) }),
Err(err) => {
let err = err.into_inner();
drop(ManuallyDrop::into_inner(ptr));
Err(err)
}
}
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
impl<T> PtrInit<T> for UniqueArc<T> {
type Uninit = UniqueArc<MaybeUninit<T>>;
#[inline]
fn init<E, I>(uninit: Pin<UniqueArc<MaybeUninit<T>>>, init: I) -> Result<Pin<UniqueArc<T>>, E>
where
I: Init<T, E>,
{
let mut ptr = ManuallyDrop::new(unsafe { Pin::into_inner_unchecked(uninit) });
match init.__init(unsafe { PinUninit::new(&mut ptr) }) {
Ok(_) => Ok(unsafe { mem::transmute(ptr) }),
Err(err) => {
let err = err.into_inner();
drop(ManuallyDrop::into_inner(ptr));
Err(err)
}
}
}
}
#[cfg(feature = "alloc_pin_with")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc_pin_with")))]
pub trait PtrPinWith<T>: Deref<Target = T> + Sized {
fn pin_with<E, I>(init: I) -> Result<Pin<Self>, E>
where
I: Init<T, E>;
}
#[cfg(feature = "alloc_pin_with")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc_pin_with")))]
impl<T> PtrPinWith<T> for Box<T> {
#[inline]
fn pin_with<E, I>(init: I) -> Result<Pin<Self>, E>
where
I: Init<T, E>,
{
PtrInit::init(Box::new(MaybeUninit::uninit()).into(), init)
}
}
#[cfg(feature = "alloc_pin_with")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc_pin_with")))]
impl<T> PtrPinWith<T> for UniqueRc<T> {
#[inline]
fn pin_with<E, I>(init: I) -> Result<Pin<Self>, E>
where
I: Init<T, E>,
{
PtrInit::init(UniqueRc::new(MaybeUninit::uninit()).into(), init)
}
}
#[cfg(feature = "alloc_pin_with")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc_pin_with")))]
impl<T> PtrPinWith<T> for UniqueArc<T> {
#[inline]
fn pin_with<E, I>(init: I) -> Result<Pin<Self>, E>
where
I: Init<T, E>,
{
PtrInit::init(UniqueArc::new(MaybeUninit::uninit()).into(), init)
}
}
#[cfg(feature = "alloc_pin_with")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc_pin_with")))]
impl<T> PtrPinWith<T> for Rc<T> {
#[inline]
fn pin_with<E, I>(init: I) -> Result<Pin<Self>, E>
where
I: Init<T, E>,
{
Ok(UniqueRc::shareable_pin(UniqueRc::pin_with(init)?))
}
}
#[cfg(feature = "alloc_pin_with")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc_pin_with")))]
impl<T> PtrPinWith<T> for Arc<T> {
#[inline]
fn pin_with<E, I>(init: I) -> Result<Pin<Self>, E>
where
I: Init<T, E>,
{
Ok(UniqueArc::shareable_pin(UniqueArc::pin_with(init)?))
}
}
#[cfg(feature = "alloc_try_pin_with")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc_try_pin_with")))]
pub trait PtrTryPinWith<T>: Deref<Target = T> + Sized {
fn try_pin_with<E, I>(init: I) -> Result<Pin<Self>, E>
where
I: Init<T, E>,
E: From<AllocError>;
}
#[cfg(feature = "alloc_try_pin_with")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc_try_pin_with")))]
impl<T> PtrTryPinWith<T> for Box<T> {
#[inline]
fn try_pin_with<E, I>(init: I) -> Result<Pin<Self>, E>
where
I: Init<T, E>,
E: From<AllocError>,
{
PtrInit::init(Box::try_new(MaybeUninit::uninit())?.into(), init)
}
}
#[cfg(feature = "alloc_try_pin_with")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc_try_pin_with")))]
impl<T> PtrTryPinWith<T> for UniqueRc<T> {
#[inline]
fn try_pin_with<E, I>(init: I) -> Result<Pin<Self>, E>
where
I: Init<T, E>,
E: From<AllocError>,
{
PtrInit::init(UniqueRc::try_new(MaybeUninit::uninit())?.into(), init)
}
}
#[cfg(feature = "alloc_try_pin_with")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc_try_pin_with")))]
impl<T> PtrTryPinWith<T> for UniqueArc<T> {
#[inline]
fn try_pin_with<E, I>(init: I) -> Result<Pin<Self>, E>
where
I: Init<T, E>,
E: From<AllocError>,
{
PtrInit::init(UniqueArc::try_new(MaybeUninit::uninit())?.into(), init)
}
}
#[cfg(feature = "alloc_try_pin_with")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc_try_pin_with")))]
impl<T> PtrTryPinWith<T> for Rc<T> {
#[inline]
fn try_pin_with<E, I>(init: I) -> Result<Pin<Self>, E>
where
I: Init<T, E>,
E: From<AllocError>,
{
Ok(UniqueRc::shareable_pin(UniqueRc::try_pin_with(init)?))
}
}
#[cfg(feature = "alloc_try_pin_with")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc_try_pin_with")))]
impl<T> PtrTryPinWith<T> for Arc<T> {
#[inline]
fn try_pin_with<E, I>(init: I) -> Result<Pin<Self>, E>
where
I: Init<T, E>,
E: From<AllocError>,
{
Ok(UniqueArc::shareable_pin(UniqueArc::try_pin_with(init)?))
}
}
pub trait Initable<'this>: Sized {
#[doc(hidden)]
type __PinInitBuilder;
#[doc(hidden)]
fn __pin_init_builder(init: PinUninit<'this, Self>) -> Self::__PinInitBuilder;
}
#[doc(hidden)]
pub mod __private {
use super::*;
pub use pin_init_internal::PinInit;
pub struct StackWrapper<T>(MaybeUninit<T>, bool);
impl<T> StackWrapper<T> {
#[inline]
pub fn new() -> Self {
StackWrapper(MaybeUninit::uninit(), false)
}
#[inline]
pub fn init<F, E>(self: Pin<&mut Self>, f: F) -> Result<Pin<&mut T>, E>
where
F: Init<T, E>,
{
struct PanicGuard;
impl Drop for PanicGuard {
#[inline]
fn drop(&mut self) {
panic!("panicked while pin-initing variable on stack");
}
}
assert!(!self.1);
let this = unsafe { self.get_unchecked_mut() };
let g = PanicGuard;
let res = f.__init(unsafe { PinUninit::new(&mut this.0) });
mem::forget(g);
match res {
Ok(ok) => {
this.1 = true;
Ok(ok.into_inner())
}
Err(err) => Err(err.into_inner()),
}
}
}
impl<T> Drop for StackWrapper<T> {
#[inline]
fn drop(&mut self) {
if self.1 {
unsafe {
self.0.as_mut_ptr().drop_in_place();
}
}
}
}
pub struct ValueBuilder<'this, T>(InitOk<'this, T>);
impl<'this, T> ValueBuilder<'this, T> {
#[inline]
pub fn __init_ok(self) -> InitOk<'this, T> {
self.0
}
}
impl<'this> Initable<'this> for core::marker::PhantomPinned {
#[doc(hidden)]
type __PinInitBuilder = ValueBuilder<'this, Self>;
#[doc(hidden)]
#[inline]
fn __pin_init_builder(init: PinUninit<'this, Self>) -> Self::__PinInitBuilder {
ValueBuilder(init.init_with_value(Self))
}
}
pub struct TransparentBuilder<'this, T, W>(
PinUninit<'this, W>,
PhantomData<PinUninit<'this, T>>,
);
impl<'this, T> Initable<'this> for core::cell::UnsafeCell<T> {
#[doc(hidden)]
type __PinInitBuilder = TransparentBuilder<'this, T, core::cell::UnsafeCell<T>>;
#[doc(hidden)]
#[inline]
fn __pin_init_builder(init: PinUninit<'this, Self>) -> Self::__PinInitBuilder {
TransparentBuilder(init, PhantomData)
}
}
impl<'this, T> Initable<'this> for core::cell::Cell<T> {
#[doc(hidden)]
type __PinInitBuilder = TransparentBuilder<'this, T, core::cell::Cell<T>>;
#[doc(hidden)]
#[inline]
fn __pin_init_builder(init: PinUninit<'this, Self>) -> Self::__PinInitBuilder {
TransparentBuilder(init, PhantomData)
}
}
impl<'this, T, W> TransparentBuilder<'this, T, W> {
#[inline]
pub fn __next<E, F>(mut self, f: F) -> Result<ValueBuilder<'this, W>, InitErr<'this, E>>
where
F: Init<T, E>,
{
let ptr = self.0.get_mut().as_mut_ptr() as *mut MaybeUninit<T>;
match f.__init(unsafe { PinUninit::new(&mut *ptr) }) {
Ok(_) => Ok(ValueBuilder(unsafe { self.0.init_ok() })),
Err(err) => Err(self.0.init_err(err.into_inner())),
}
}
}
}
#[macro_export]
macro_rules! init_stack {
($var:ident = $init:expr) => {
let mut storage = $crate::__private::StackWrapper::new();
let $var =
unsafe { ::core::pin::Pin::new_unchecked(&mut storage) }.init($crate::init_pin!($init));
};
}