#[cfg(feature = "alloc")]
use alloc::boxed::Box;
use core::{mem::MaybeUninit, ops::Deref, pin::Pin};
pub unsafe trait Moveable {
unsafe fn mv(dst: *mut Self, src: *mut Self);
}
unsafe impl<T: Copy> Moveable for T {
unsafe fn mv(dst: *mut Self, src: *mut Self) {
unsafe { core::ptr::copy(src, dst, 1) };
}
}
pub unsafe trait Container:
Deref<Target = Self::Inner> + AsRef<Self::Inner> + Sized
{
type Allocator;
type Inner;
type Uninit;
fn uninit(allocator: Self::Allocator) -> Self::Uninit;
fn uninit_inner_ptr(uninit: &mut Self::Uninit) -> *mut Self::Inner;
unsafe fn init(uninit: Self::Uninit) -> Self;
fn try_inner(&mut self) -> Option<Pin<&mut Self::Inner>>;
fn try_move_out<O>(self, action: impl FnOnce(*mut Self::Inner) -> O) -> Option<O>;
#[inline]
unsafe fn init_ptr(
allocator: Self::Allocator,
initializer: impl FnOnce(*mut Self::Inner),
) -> Self {
let mut uninit = Self::uninit(allocator);
let ptr = Self::uninit_inner_ptr(&mut uninit);
initializer(ptr);
unsafe { Self::init(uninit) }
}
#[inline]
fn try_mv<C: Container<Inner = Self::Inner>>(self, allocator: C::Allocator) -> Option<C>
where
Self::Inner: Moveable,
{
self.try_move_out(|src| {
let mv = move |dst: *mut Self::Inner| {
unsafe { C::Inner::mv(dst, src) }
};
unsafe { C::init_ptr(allocator, mv) }
})
}
#[inline]
fn init_value(allocator: Self::Allocator, value: Self::Inner) -> Self {
let w = |dst| {
unsafe {
core::ptr::write(dst, value);
}
};
unsafe { Self::init_ptr(allocator, w) }
}
}
pub trait ExclusiveContainer: Container {
fn inner(&mut self) -> Pin<&mut Self::Inner>;
fn move_out<O>(self, action: impl FnOnce(*mut Self::Inner) -> O) -> O;
fn mv<C: Container<Inner = Self::Inner>>(self, allocator: C::Allocator) -> C
where
Self::Inner: Moveable,
{
self.move_out(|src| {
let mv = move |dst: *mut Self::Inner| {
unsafe { C::Inner::mv(dst, src) }
};
unsafe { C::init_ptr(allocator, mv) }
})
}
}
macro_rules! impl_container_traits {
($c:ty $(| <$($args:tt),+> $(lt: <$($l:lifetime),+>)?)?) => {
impl $(<$($args),+>)? AsRef<<$c as Container>::Inner> for $c {
#[inline]
fn as_ref(&self) -> &<$c as Container>::Inner {
&*self
}
}
impl $(<$($args),+>)? $c {
#[doc = concat!("Same as `<&Self as IntoIterator>::into_iter(self)`")]
#[inline]
pub fn iter<'r0>(&'r0 self) -> <&'r0 Self as IntoIterator>::IntoIter
where
$($($($l : 'r0,)+)?)?
for<'r1> &'r1 T: IntoIterator,
{
self.into_iter()
}
}
impl <'r0 $(,$($args),+)?> IntoIterator for & 'r0 $c
where
$($($($l : 'r0,)+)?)?
for<'r1> &'r1 T: IntoIterator,
{
type Item = <&'r0 T as IntoIterator>::Item;
type IntoIter = <&'r0 T as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
<&'r0 T as IntoIterator>::into_iter(&*self)
}
}
};
}
#[derive(Debug)]
#[doc(hidden)]
#[cfg(feature = "alloc")]
pub struct UninitBoxContainer<T>(Box<MaybeUninit<T>>);
#[derive(Debug)]
#[cfg(feature = "alloc")]
pub struct BoxContainer<T>(Pin<Box<T>>);
#[cfg(feature = "alloc")]
impl<T> Deref for BoxContainer<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(feature = "alloc")]
impl<T: core::fmt::Display> core::fmt::Display for BoxContainer<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
T::fmt(&self.0, f)
}
}
#[cfg(feature = "alloc")]
unsafe impl<T> Container for BoxContainer<T> {
type Allocator = ();
type Inner = T;
type Uninit = UninitBoxContainer<T>;
#[inline]
fn uninit(_allocator: ()) -> Self::Uninit {
UninitBoxContainer(Box::new_uninit())
}
#[inline]
fn uninit_inner_ptr(uninit: &mut Self::Uninit) -> *mut Self::Inner {
uninit.0.as_mut_ptr()
}
#[inline]
unsafe fn init(uninit: Self::Uninit) -> Self {
let init_ptr = unsafe { uninit.0.assume_init() };
let pin = unsafe { Pin::new_unchecked(init_ptr) };
Self(pin)
}
#[inline]
fn try_inner(&mut self) -> Option<Pin<&mut Self::Inner>> {
Some(self.inner())
}
#[inline]
fn try_move_out<O>(self, action: impl FnOnce(*mut Self::Inner) -> O) -> Option<O> {
Some(self.move_out(action))
}
}
#[cfg(feature = "alloc")]
impl<T> ExclusiveContainer for BoxContainer<T> {
#[inline]
fn inner(&mut self) -> Pin<&mut Self::Inner> {
self.0.as_mut()
}
#[inline]
fn move_out<O>(self, action: impl FnOnce(*mut Self::Inner) -> O) -> O {
let bx = unsafe { Pin::into_inner_unchecked(self.0) };
let ptr = Box::into_raw(bx);
let res = action(ptr);
let uptr = ptr.cast::<MaybeUninit<T>>(); let ubx = unsafe { Box::from_raw(uptr) };
core::mem::drop(ubx);
res
}
}
#[cfg(feature = "alloc")]
impl_container_traits!(BoxContainer<T> | <T>);
#[cfg(feature = "alloc")]
unsafe fn pin_inner_mut<Ptr>(pin: &mut Pin<Ptr>) -> &mut Ptr {
let ptr = core::ptr::from_mut(pin).cast();
unsafe { &mut *ptr }
}
#[cfg(feature = "alloc")]
mod simple_arc;
#[cfg(feature = "alloc")]
use simple_arc::Arc;
#[doc(hidden)]
#[cfg(feature = "alloc")]
pub struct UninitArcContainer<T>(Arc<MaybeUninit<T>>);
#[cfg(feature = "alloc")]
impl<T> core::fmt::Debug for UninitArcContainer<T> {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("UninitArcContainer").field(&*self.0).finish()
}
}
#[derive(Debug)]
#[cfg(feature = "alloc")]
pub struct ArcContainer<T>(Pin<Arc<T>>);
#[cfg(feature = "alloc")]
impl<T> Clone for ArcContainer<T> {
#[inline]
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
#[cfg(feature = "alloc")]
impl<T> Deref for ArcContainer<T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(feature = "alloc")]
impl<T: core::fmt::Display> core::fmt::Display for ArcContainer<T> {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
T::fmt(&self.0, f)
}
}
#[cfg(feature = "alloc")]
unsafe impl<T> Container for ArcContainer<T> {
type Allocator = ();
type Inner = T;
type Uninit = UninitArcContainer<T>;
#[inline]
fn uninit(_allocator: ()) -> Self::Uninit {
UninitArcContainer(Arc::uninit())
}
#[inline]
fn uninit_inner_ptr(uninit: &mut Self::Uninit) -> *mut Self::Inner {
let rf = unsafe { uninit.0.get_mut_unchecked() };
rf.as_mut_ptr()
}
#[inline]
unsafe fn init(uninit: Self::Uninit) -> Self {
let init_ptr: Arc<_> = unsafe { uninit.0.assume_init() };
let pin = unsafe { Pin::new_unchecked(init_ptr) };
Self(pin)
}
#[inline]
fn try_inner(&mut self) -> Option<Pin<&mut Self::Inner>> {
let arc = unsafe { pin_inner_mut(&mut self.0) };
if let Some(refm) = Arc::get_mut(arc) {
Some(unsafe { Pin::new_unchecked(refm) })
} else {
None
}
}
#[inline]
fn try_move_out<O>(self, action: impl FnOnce(*mut Self::Inner) -> O) -> Option<O> {
let arc = unsafe { Pin::into_inner_unchecked(self.0) };
arc.try_move_out(action)
}
}
#[cfg(feature = "alloc")]
impl_container_traits!(ArcContainer<T> | <T>);
#[derive(Debug)]
#[doc(hidden)]
pub struct UninitRefContainer<'r, T>(&'r mut MaybeUninit<T>);
#[derive(Debug)]
pub struct RefContainer<'r, T>(Option<Pin<&'r mut T>>);
impl<T> Deref for RefContainer<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.0.as_ref().unwrap()
}
}
impl<T> Drop for RefContainer<'_, T> {
#[inline]
fn drop(&mut self) {
let Some(pin): Option<Pin<&mut T>> = self.0.take() else {
return;
};
let rf = unsafe { Pin::into_inner_unchecked(pin) };
let ptr = core::ptr::from_mut(rf);
unsafe { core::ptr::drop_in_place(ptr) };
}
}
impl<T: core::fmt::Display> core::fmt::Display for RefContainer<'_, T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
T::fmt(self.0.as_ref().unwrap(), f)
}
}
unsafe impl<'r, T> Container for RefContainer<'r, T> {
type Allocator = &'r mut MaybeUninit<T>;
type Inner = T;
type Uninit = UninitRefContainer<'r, T>;
#[inline]
fn uninit(allocator: Self::Allocator) -> Self::Uninit {
UninitRefContainer(allocator)
}
#[inline]
fn uninit_inner_ptr(uninit: &mut Self::Uninit) -> *mut Self::Inner {
uninit.0.as_mut_ptr()
}
#[inline]
unsafe fn init(uninit: Self::Uninit) -> Self {
let ref_mut = unsafe { uninit.0.assume_init_mut() };
let pin = unsafe { Pin::new_unchecked(ref_mut) };
Self(Some(pin))
}
#[inline]
fn try_inner(&mut self) -> Option<Pin<&mut Self::Inner>> {
Some(self.inner())
}
#[inline]
fn try_move_out<O>(self, action: impl FnOnce(*mut Self::Inner) -> O) -> Option<O> {
Some(self.move_out(action))
}
}
impl<T> ExclusiveContainer for RefContainer<'_, T> {
#[inline]
fn inner(&mut self) -> Pin<&mut Self::Inner> {
self.0.as_mut().unwrap().as_mut()
}
#[inline]
fn move_out<O>(mut self, action: impl FnOnce(*mut Self::Inner) -> O) -> O {
let pin = self
.0
.take()
.expect("Should contain the pin, since it's only ever taken out by this function and a destructor (both can only be called once)");
let rf = unsafe { Pin::into_inner_unchecked(pin) };
let ptr = core::ptr::from_mut(rf);
action(ptr) }
}
impl_container_traits!(RefContainer<'r, T> | <'r, T> lt: <'r>);
#[cfg(test)]
mod tests;