use core::{
cell::Cell,
error::Error,
fmt,
hash::{Hash, Hasher},
mem::{self, MaybeUninit},
ops::{Deref, DerefMut},
pin::Pin,
ptr::NonNull,
task::{Context, Poll},
};
use crate::{owned::Own, place::Place, uninit::Uninit};
pub struct DroppingSlot<'a, T: ?Sized> {
drop_flag: Cell<bool>,
inner: MaybeUninit<Own<'a, T>>,
}
impl<'a, T: ?Sized> DroppingSlot<'a, T> {
#[inline]
pub const fn new() -> Self {
DroppingSlot {
drop_flag: Cell::new(true),
inner: MaybeUninit::uninit(),
}
}
fn assign(&mut self, own: Own<'a, T>) -> &Cell<bool> {
if !self.drop_flag.replace(false) {
unsafe { self.inner.assume_init_drop() };
}
self.inner.write(own);
&self.drop_flag
}
}
impl<'a, T: ?Sized> Default for DroppingSlot<'a, T> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<'a, T: ?Sized> Drop for DroppingSlot<'a, T> {
fn drop(&mut self) {
if !self.drop_flag.get() {
unsafe { self.inner.assume_init_drop() }
}
}
}
pub struct DropSlot<'a, 'b, T: ?Sized>(&'b mut DroppingSlot<'a, T>);
impl<'a, 'b, T: ?Sized> fmt::Debug for DropSlot<'a, 'b, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("DropSlot").finish()
}
}
impl<'a, 'b, T: ?Sized> DropSlot<'a, 'b, T> {
#[inline]
pub unsafe fn new_unchecked(slot: &'b mut DroppingSlot<'a, T>) -> Self {
DropSlot(slot)
}
}
#[macro_export]
#[allow_internal_unstable(super_let)]
macro_rules! drop_slot {
() => {{
super let mut slot = $crate::pin::DroppingSlot::new();
unsafe { $crate::pin::DropSlot::new_unchecked(&mut slot) }
}};
}
pub struct POwn<'b, T: ?Sized> {
drop_flag: &'b Cell<bool>,
inner: NonNull<T>,
}
impl<'b, T: ?Sized> Unpin for POwn<'b, T> {}
impl<'b, T: ?Sized> Drop for POwn<'b, T> {
fn drop(&mut self) {
self.drop_flag.set(true);
unsafe { self.inner.drop_in_place() }
}
}
#[macro_export]
#[allow_internal_unstable(super_let)]
macro_rules! pown {
($e:expr) => {{
super let mut place = ::core::mem::MaybeUninit::uninit();
super let mut slot = $crate::pin::DroppingSlot::new();
let drop_slot = unsafe { $crate::pin::DropSlot::new_unchecked(&mut slot) };
$crate::place::Place::write_pin(&mut place, $e, drop_slot)
}};
}
impl<'b, T: ?Sized> POwn<'b, T> {
pub fn new<'a>(own: Own<'a, T>, slot: DropSlot<'a, 'b, T>) -> Self {
let inner = own.inner;
let drop_flag = slot.0.assign(own);
POwn { drop_flag, inner }
}
#[inline]
pub const fn as_ref(&self) -> Pin<&T> {
unsafe { Pin::new_unchecked(self.inner.as_ref()) }
}
#[inline]
pub const fn as_mut(&mut self) -> Pin<&mut T> {
unsafe { Pin::new_unchecked(self.inner.as_mut()) }
}
#[inline]
pub const fn as_deref_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
unsafe { Pin::new_unchecked(Pin::into_inner_unchecked(self).inner.as_mut()) }
}
#[inline]
pub fn set(&mut self, value: T)
where
T: Sized,
{
unsafe { *self.inner.as_ptr() = value }
}
#[inline]
pub fn drop(this: Self) -> Uninit<'b, T> {
let inner = this.inner;
drop(this);
unsafe { Uninit::from_inner(inner) }
}
#[inline]
pub fn into_inner(this: Self) -> Own<'b, T>
where
T: Unpin,
{
let inner = this.inner;
this.drop_flag.set(true);
mem::forget(this);
unsafe { Own::from_inner(inner) }
}
}
impl<'b, T: ?Sized> Deref for POwn<'b, T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
unsafe { self.inner.as_ref() }
}
}
impl<'b, T: ?Sized + Unpin> DerefMut for POwn<'b, T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.inner.as_mut() }
}
}
impl<'b, T: ?Sized + fmt::Debug> fmt::Debug for POwn<'b, T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<'b, T: ?Sized + fmt::Display> fmt::Display for POwn<'b, T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&**self, f)
}
}
impl<'a, T: ?Sized> fmt::Pointer for POwn<'a, T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Pointer::fmt(&self.inner, f)
}
}
impl<'a, T: Clone> POwn<'a, T> {
#[inline]
pub fn clone<'p>(&self, to: &'p mut impl Place<T>) -> Own<'p, T> {
to.write(|| (**self).clone())
}
}
impl<'b, T: Default> POwn<'b, T> {
#[inline]
pub fn default<'a>(place: &'a mut impl Place<T>, slot: DropSlot<'a, 'b, T>) -> Self {
place.write_pin(T::default, slot)
}
}
impl<'a, 'b, T: ?Sized + PartialEq<U>, U: ?Sized> PartialEq<POwn<'b, U>> for POwn<'a, T> {
#[inline]
fn eq(&self, other: &POwn<'b, U>) -> bool {
**self == **other
}
}
impl<'a, T: ?Sized + Eq> Eq for POwn<'a, T> {}
impl<'a, 'b, T: ?Sized + PartialOrd<U>, U: ?Sized> PartialOrd<POwn<'b, U>> for POwn<'a, T> {
#[inline]
fn partial_cmp(&self, other: &POwn<'b, U>) -> Option<core::cmp::Ordering> {
(**self).partial_cmp(&**other)
}
}
impl<'a, T: ?Sized + Ord> Ord for POwn<'a, T> {
#[inline]
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
(**self).cmp(&**other)
}
}
impl<'a, T: ?Sized + Hash> Hash for POwn<'a, T> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
(**self).hash(state)
}
}
impl<'a, T: ?Sized + Hasher + Unpin> Hasher for POwn<'a, T> {
#[inline]
fn finish(&self) -> u64 {
(**self).finish()
}
#[inline]
fn write(&mut self, bytes: &[u8]) {
(**self).write(bytes);
}
}
impl<'a, T: ?Sized + Error> Error for POwn<'a, T> {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
(**self).source()
}
}
impl<'a, F: ?Sized + Future> Future for POwn<'a, F> {
type Output = F::Output;
#[inline]
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.as_deref_mut().poll(cx)
}
}
#[macro_export]
#[allow_internal_unstable(super_let)]
macro_rules! into_pown {
($p:ident, $slot:ident <- $e:expr) => {{
use ::core::pin::Pin;
let pinned = $e;
let init = unsafe { Pin::into_inner_unchecked(pinned) };
$p = $crate::owned::IntoOwn::into_own_place(init);
unsafe { $crate::owned::Own::into_pin($crate::owned::Own::from_mut(&mut $p), $slot) }
}};
($p:ident <- $e:expr) => {{
use ::core::pin::Pin;
super let mut slot = $crate::pin::DroppingSlot::new();
let slot = unsafe { $crate::pin::DropSlot::new_unchecked(&mut slot) };
let pinned = $e;
let init = unsafe { Pin::into_inner_unchecked(pinned) };
$p = $crate::owned::IntoOwn::into_own_place(init);
unsafe { $crate::owned::Own::into_pin($crate::owned::Own::from_mut(&mut $p), slot) }
}};
($e:expr) => {{
super let mut p;
$crate::into_pown!(p <- $e)
}};
}
#[cfg(test)]
#[cfg(feature = "alloc")]
mod tests {
use alloc::boxed::Box;
use super::*;
#[test]
fn test_into_pown() {
let mut my_place;
{
let owned = into_pown!(my_place <- Box::pin(55));
assert_eq!(*owned, 55);
}
my_place.write(123);
let owned2 = into_pown!(Box::pin(77));
assert_eq!(*owned2, 77);
}
}