use core::{
fmt,
mem::{self, ManuallyDrop, MaybeUninit},
pin::Pin,
};
use crate::{
init::{Init, InitPin, IntoInit, IntoInitPin},
owned::Own,
pin::{DropSlot, DroppingSlot, POwn},
uninit::Uninit,
};
pub struct DynPlace<T> {
init: bool,
data: MaybeUninit<T>,
}
impl<T: fmt::Debug> fmt::Debug for DynPlace<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.as_ref() {
Some(value) => f.debug_tuple("DynPlace").field(value).finish(),
None => write!(f, "DynPlace(<uninit>)"),
}
}
}
impl<T> Default for DynPlace<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> DynPlace<T> {
#[inline]
pub const fn new() -> Self {
Self {
init: false,
data: MaybeUninit::uninit(),
}
}
#[inline]
pub const fn is_init(&self) -> bool {
self.init
}
#[inline]
pub const fn as_ptr(&self) -> *const T {
self.data.as_ptr()
}
#[inline]
pub const fn as_mut_ptr(&mut self) -> *mut T {
self.data.as_mut_ptr()
}
#[inline]
pub const fn as_ref(&self) -> Option<&T> {
if self.init {
Some(unsafe { self.data.assume_init_ref() })
} else {
None
}
}
#[inline]
pub const fn as_mut(&mut self) -> Option<&mut T> {
if self.init {
Some(unsafe { self.data.assume_init_mut() })
} else {
None
}
}
#[inline]
pub const fn as_own(&mut self) -> Option<Own<'_, T>> {
if self.init {
self.init = false;
Some(unsafe { Own::from_raw(self.data.as_mut_ptr()) })
} else {
None
}
}
#[inline]
pub const fn as_pin_ref(self: Pin<&Self>) -> Option<Pin<&T>> {
unsafe {
let this = self.get_ref();
if this.init {
Some(Pin::new_unchecked(this.data.assume_init_ref()))
} else {
None
}
}
}
#[inline]
pub const fn as_pin_mut(self: Pin<&mut Self>) -> Option<Pin<&mut T>> {
unsafe {
let this = self.get_unchecked_mut();
if this.init {
Some(Pin::new_unchecked(this.data.assume_init_mut()))
} else {
None
}
}
}
#[inline]
pub fn as_pin_own<'b>(self: Pin<&mut Self>, slot: DropSlot<'_, 'b, T>) -> Option<POwn<'b, T>> {
let this = unsafe { self.get_unchecked_mut() };
if this.init {
this.init = false;
Some(unsafe { POwn::new(Own::from_raw(this.data.as_mut_ptr()), slot) })
} else {
None
}
}
#[inline]
pub fn as_deref(&self) -> Option<&T::Target>
where
T: core::ops::Deref,
{
self.as_ref().map(|r| r.deref())
}
#[inline]
pub fn as_deref_mut(&mut self) -> Option<&mut T::Target>
where
T: core::ops::DerefMut,
{
self.as_mut().map(|r| r.deref_mut())
}
#[inline]
pub fn cloned(&self) -> Option<T>
where
T: Clone,
{
self.as_ref().cloned()
}
#[inline]
pub fn copied(&self) -> Option<T>
where
T: Copy,
{
self.as_ref().copied()
}
#[inline]
pub const fn take(&mut self) -> Option<T> {
if self.init {
let value = unsafe { self.data.assume_init_read() };
self.init = false;
Some(value)
} else {
None
}
}
}
impl<T> DynPlace<T> {
pub fn drop_in_place(&mut self) {
if self.init {
unsafe { self.data.assume_init_drop() };
self.init = false;
}
}
pub fn drop_in_place_pin(self: Pin<&mut Self>) {
unsafe { self.get_unchecked_mut().drop_in_place() }
}
#[inline]
pub fn init<I, M>(&mut self, init: I) -> Own<'_, T>
where
I: IntoInit<T, M>,
{
self.try_init(init).unwrap()
}
pub fn try_init<I, M>(&mut self, init: I) -> Result<Own<'_, T>, I::Error>
where
I: IntoInit<T, M>,
{
self.drop_in_place();
unsafe {
let uninit = Uninit::from_raw(self.data.as_mut_ptr());
init.into_init().init(uninit).map_err(|e| e.error)
}
}
#[inline]
pub fn get_or_init<I, M>(&mut self, init: I) -> Own<'_, T>
where
I: IntoInit<T, M>,
{
if self.is_init() {
self.init = false;
unsafe { Own::from_raw(self.data.as_mut_ptr()) }
} else {
self.init(init)
}
}
#[inline]
pub fn init_pin<'b, I, M>(
self: Pin<&mut Self>,
init: I,
slot: DropSlot<'_, 'b, T>,
) -> POwn<'b, T>
where
I: IntoInitPin<T, M>,
{
self.try_init_pin(init, slot).unwrap()
}
pub fn try_init_pin<'b, I, M>(
mut self: Pin<&mut Self>,
init: I,
slot: DropSlot<'_, 'b, T>,
) -> Result<POwn<'b, T>, I::Error>
where
I: IntoInitPin<T, M>,
{
self.as_mut().drop_in_place_pin();
unsafe {
let this = self.get_unchecked_mut();
let uninit = Uninit::from_raw(this.data.as_mut_ptr());
init.into_init().init_pin(uninit, slot).map_err(|e| e.error)
}
}
#[inline]
pub fn get_or_init_pin<'b, I, M>(
self: Pin<&mut Self>,
init: I,
slot: DropSlot<'_, 'b, T>,
) -> POwn<'b, T>
where
I: IntoInitPin<T, M>,
{
if self.is_init() {
let this = unsafe { self.get_unchecked_mut() };
this.init = false;
unsafe { POwn::new(Own::from_raw(this.data.as_mut_ptr()), slot) }
} else {
self.init_pin(init, slot)
}
}
}
impl<T> DynPlace<T> {
#[inline]
pub fn insert<I, M>(&mut self, init: I) -> &mut T
where
I: IntoInit<T, M>,
{
self.try_insert(init).unwrap()
}
pub fn try_insert<I, M>(&mut self, init: I) -> Result<&mut T, I::Error>
where
I: IntoInit<T, M>,
{
mem::forget(self.try_init(init)?);
self.init = true;
Ok(unsafe { self.data.assume_init_mut() })
}
#[inline]
pub fn get_or_insert<I, M>(&mut self, init: I) -> &mut T
where
I: IntoInit<T, M>,
{
if self.is_init() {
unsafe { self.data.assume_init_mut() }
} else {
self.insert(init)
}
}
#[inline]
pub fn replace<I, M>(&mut self, init: I) -> Option<T>
where
I: IntoInit<T, M>,
{
self.try_replace(init).unwrap()
}
#[inline]
pub fn try_replace<I, M>(&mut self, init: I) -> Result<Option<T>, I::Error>
where
I: IntoInit<T, M>,
{
let old = self.take();
self.try_insert(init)?;
Ok(old)
}
#[inline]
pub fn insert_pin<I, M>(self: Pin<&mut Self>, init: I) -> Pin<&mut T>
where
I: IntoInitPin<T, M>,
{
self.try_insert_pin(init).unwrap()
}
pub fn try_insert_pin<I, M>(mut self: Pin<&mut Self>, init: I) -> Result<Pin<&mut T>, I::Error>
where
I: IntoInitPin<T, M>,
{
let mut slot = ManuallyDrop::new(DroppingSlot::new());
let slot_ref = unsafe { DropSlot::new_unchecked(&mut slot) };
mem::forget(self.as_mut().try_init_pin(init, slot_ref)?);
let this = unsafe { self.get_unchecked_mut() };
this.init = true;
Ok(unsafe { Pin::new_unchecked(this.data.assume_init_mut()) })
}
#[inline]
pub fn get_or_insert_pin<I, M>(self: Pin<&mut Self>, init: I) -> Pin<&mut T>
where
I: IntoInitPin<T, M>,
{
if self.is_init() {
unsafe { Pin::new_unchecked(self.get_unchecked_mut().data.assume_init_mut()) }
} else {
self.insert_pin(init)
}
}
}
impl<T> Drop for DynPlace<T> {
fn drop(&mut self) {
self.drop_in_place();
}
}