use core::{
mem::{ManuallyDrop, MaybeUninit, take, transmute},
ptr::NonNull,
};
pub struct Guarded<'a, T>(&'a mut T)
where
T: ?Sized;
impl<'a, T> Guarded<'a, T> {
pub fn forget(self) -> &'a mut T {
let result = self.0 as *mut T; let _ = unsafe { transmute::<Guarded<'a, T>, Guarded<'a, ManuallyDrop<T>>>(self) };
unsafe { &mut *result }
}
}
impl<'a, T> Guarded<'a, [T]> {
pub fn forget(mut self) -> &'a mut [T] {
take(&mut self.0)
}
}
impl<'a, T> Guarded<'a, MaybeUninit<T>> {
pub unsafe fn assume_init(self) -> Guarded<'a, T> {
unsafe { transmute::<Guarded<'a, MaybeUninit<T>>, Guarded<'a, T>>(self) }
}
}
impl<'a, T> Guarded<'a, [MaybeUninit<T>]> {
pub unsafe fn assume_init(self) -> Guarded<'a, [T]> {
unsafe { transmute::<Guarded<'a, [MaybeUninit<T>]>, Guarded<'a, [T]>>(self) }
}
}
impl<'a, T> Guarded<'a, T>
where
T: Copy,
{
pub fn into_mut(self) -> &'a mut T {
self.forget()
}
}
impl<'a, T> Guarded<'a, [T]>
where
T: Copy,
{
pub fn into_mut(self) -> &'a mut [T] {
self.forget()
}
}
impl<T> core::ops::Deref for Guarded<'_, T>
where
T: ?Sized,
{
type Target = T;
fn deref(&self) -> &Self::Target {
self.0
}
}
impl<T> core::ops::DerefMut for Guarded<'_, T>
where
T: ?Sized,
{
fn deref_mut(&mut self) -> &mut Self::Target {
self.0
}
}
impl<'a, T> Default for Guarded<'a, T>
where
&'a mut T: Default,
{
fn default() -> Self {
Self(Default::default())
}
}
impl<T> Drop for Guarded<'_, T>
where
T: ?Sized,
{
fn drop(&mut self) {
if core::mem::needs_drop::<T>() {
let to_drop = unsafe { core::mem::transmute::<&mut T, &mut ManuallyDrop<T>>(self.0) };
unsafe { ManuallyDrop::drop(to_drop) };
}
}
}
impl<T> core::fmt::Debug for Guarded<'_, T>
where
T: core::fmt::Debug + ?Sized,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Debug::fmt(self.0, f)
}
}
#[derive(Debug)]
pub(crate) struct GuardedBuilderInner {
pub(crate) next: Option<*mut GuardedBuilderInner>,
pub(crate) ptr: Option<NonNull<u8>>,
pub(crate) align: usize,
pub(crate) size: usize,
}
pub struct GuardedBuilder<'guard, T>
where
T: ?Sized,
{
pub(crate) inner: GuardedBuilderInner,
n: usize,
pd: ::core::marker::PhantomData<&'guard T>,
}
impl<'a, T> GuardedBuilder<'a, [T]> {
pub fn new_slice(n: usize) -> Self {
Self {
inner: GuardedBuilderInner {
next: None,
ptr: None,
align: align_of::<T>(),
size: size_of::<T>() * n,
},
n,
pd: Default::default(),
}
}
pub unsafe fn build(self, init: impl FnOnce(&mut [MaybeUninit<T>])) -> Guarded<'a, [T]> {
let Self {
inner: GuardedBuilderInner { ptr, .. },
n,
..
} = self;
let Some(ptr) = ptr else {
panic!(
"Attempting to build GuardedSliceBuilder that was not subscribed and for which the Subscriber successfully finished"
);
};
let elem = ptr.as_ptr().cast::<MaybeUninit<T>>().cast_slice(n);
debug_assert!(elem.is_aligned_to(align_of::<T>()));
let elem = unsafe { &mut *elem };
init(elem);
Guarded(unsafe { transmute::<&mut [MaybeUninit<T>], &mut [T]>(elem) })
}
pub fn build_from_fn(self, mut f: impl FnMut(usize) -> T) -> Guarded<'a, [T]> {
unsafe {
self.build(|elem| {
elem.iter_mut().enumerate().for_each(|(i, e)| {
e.write(f(i));
});
})
}
}
pub fn build_default(self) -> Guarded<'a, [T]>
where
T: Default,
{
self.build_from_fn(|_| T::default())
}
}
impl<'a, T> GuardedBuilder<'a, [MaybeUninit<T>]> {
pub fn build_uninit(self) -> Guarded<'a, [MaybeUninit<T>]> {
unsafe { self.build(|_| ()) }
}
}
impl<'a, T> Default for GuardedBuilder<'a, T>
where
T: Sized,
{
fn default() -> Self {
Self::new()
}
}
impl<'a, T> GuardedBuilder<'a, T>
where
T: Sized,
{
pub fn new() -> Self {
Self {
inner: GuardedBuilderInner {
next: None,
ptr: None,
align: align_of::<T>(),
size: size_of::<T>(),
},
n: 1,
pd: Default::default(),
}
}
pub unsafe fn build(self, init: impl FnOnce(&mut MaybeUninit<T>)) -> Guarded<'a, T> {
let Self {
inner: GuardedBuilderInner { ptr, .. },
..
} = self;
let Some(ptr) = ptr else {
panic!(
"Attempting to build GuardedSliceBuilder that was not subscribed and for which the Subscriber successfully finished"
);
};
let elem = ptr.as_ptr().cast::<MaybeUninit<T>>();
let elem = unsafe { &mut *elem };
init(elem);
Guarded(unsafe { transmute::<&mut MaybeUninit<T>, &mut T>(elem) })
}
pub fn build_from_fn(self, mut f: impl FnMut() -> T) -> Guarded<'a, T> {
unsafe {
self.build(|elem| {
elem.write(f());
})
}
}
pub fn build_default(self) -> Guarded<'a, T>
where
T: Default,
{
self.build_from_fn(|| T::default())
}
}
impl<'a, T> GuardedBuilder<'a, MaybeUninit<T>> {
pub fn build_uninit(self) -> Guarded<'a, MaybeUninit<T>> {
unsafe { self.build(|_| ()) }
}
}