#![cfg_attr(not(test), no_std)]
#![cfg_attr(feature = "nightly", feature(slice_ptr_get))]
#![cfg_attr(feature = "nightly", feature(doc_cfg))]
#![cfg_attr(feature = "nightly", doc(auto_cfg))]
use core::{
fmt,
iter::FusedIterator,
marker::PhantomData,
mem::MaybeUninit,
ptr::{self, NonNull},
slice,
};
#[cfg(feature = "nightly")]
use core::slice::SliceIndex;
pub struct Iter<'a, T> {
inner: slice::IterMut<'a, MaybeUninit<T>>,
}
impl<T> fmt::Debug for Iter<'_, T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Iter")
.field("len", &self.inner.len())
.finish_non_exhaustive()
}
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = WRef<'a, T>;
#[inline]
fn next(&mut self) -> Option<WRef<'a, T>> {
self.inner.next().map(WRef::from_maybe_uninit_mut)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
#[inline]
fn next_back(&mut self) -> Option<WRef<'a, T>> {
self.inner.next_back().map(WRef::from_maybe_uninit_mut)
}
}
impl<T> ExactSizeIterator for Iter<'_, T> {
#[inline]
fn len(&self) -> usize {
self.inner.len()
}
}
impl<T> FusedIterator for Iter<'_, T> {}
#[inline]
pub const fn from_mut<T: ?Sized>(value: &mut T) -> WRef<'_, T> {
WRef::from_mut(value)
}
#[inline]
pub const fn from_maybe_uninit_mut<T>(maybe: &mut MaybeUninit<T>) -> WRef<'_, T> {
WRef::from_maybe_uninit_mut(maybe)
}
#[inline]
pub const fn from_maybe_uninit_slice_mut<T>(slice: &mut [MaybeUninit<T>]) -> WRef<'_, [T]> {
WRef::from_maybe_uninit_slice_mut(slice)
}
#[repr(transparent)]
pub struct WRef<'a, T: ?Sized> {
inner: NonNull<T>,
marker: PhantomData<&'a mut T>,
}
impl<'a, T: ?Sized> WRef<'a, T> {
#[inline]
pub const fn from_mut(value: &mut T) -> WRef<'a, T> {
WRef {
inner: NonNull::from_mut(value),
marker: PhantomData,
}
}
#[inline]
pub const fn as_mut_ptr(&mut self) -> *mut T {
self.inner.as_ptr()
}
#[inline]
pub const fn as_non_null_ptr(&mut self) -> NonNull<T> {
self.inner
}
#[inline]
pub const fn reborrow(&mut self) -> WRef<'_, T> {
WRef {
inner: self.inner,
marker: PhantomData,
}
}
}
impl<'a, T> WRef<'a, T> {
#[inline]
pub const fn from_maybe_uninit_mut(maybe: &'a mut MaybeUninit<T>) -> WRef<'a, T> {
WRef {
inner: NonNull::from_mut(maybe).cast::<T>(),
marker: PhantomData,
}
}
pub const unsafe fn as_maybe_uninit(self) -> &'a mut MaybeUninit<T> {
unsafe { &mut *self.inner.cast::<MaybeUninit<T>>().as_ptr() }
}
#[inline]
pub const fn write(self, value: T) -> &'a mut T {
unsafe { self.inner.write(value) }
unsafe { self.assume_init_mut() }
}
}
impl<'a, T: ?Sized> WRef<'a, T> {
#[inline]
pub const unsafe fn assume_init_mut(mut self) -> &'a mut T {
unsafe { self.inner.as_mut() }
}
}
impl<'a, T> WRef<'a, [T]> {
#[inline]
pub const fn from_maybe_uninit_slice_mut(slice: &mut [MaybeUninit<T>]) -> WRef<'a, [T]> {
let inner =
unsafe { NonNull::new_unchecked(ptr::from_mut::<[MaybeUninit<T>]>(slice) as *mut [T]) };
WRef {
inner,
marker: PhantomData,
}
}
pub const unsafe fn as_maybe_uninit_slice(self) -> &'a mut [MaybeUninit<T>] {
unsafe { &mut *(self.inner.as_ptr() as *mut [MaybeUninit<T>]) }
}
#[cfg(feature = "nightly")]
pub fn index<I: Clone + SliceIndex<[T]> + SliceIndex<[MaybeUninit<T>]>>(
mut self,
index: I,
) -> WRef<'a, <I as SliceIndex<[T]>>::Output> {
let _ = unsafe { &self.reborrow().as_maybe_uninit_slice()[index.clone()] };
let inner = unsafe { self.inner.get_unchecked_mut(index.clone()) };
WRef {
inner,
marker: PhantomData,
}
}
pub const fn split_at(self, index: usize) -> (WRef<'a, [T]>, WRef<'a, [T]>) {
let (lo, hi) = unsafe { self.as_maybe_uninit_slice().split_at_mut(index) };
(
WRef::from_maybe_uninit_slice_mut(lo),
WRef::from_maybe_uninit_slice_mut(hi),
)
}
#[inline]
pub const fn len(&self) -> usize {
self.inner.len()
}
#[inline]
pub const fn is_empty(&self) -> bool {
self.inner.is_empty()
}
#[inline]
pub fn iter(self) -> Iter<'a, T> {
Iter {
inner: unsafe { self.as_maybe_uninit_slice().iter_mut() },
}
}
}
impl<'a, T: Clone> WRef<'a, [T]> {
#[inline]
pub fn write_clone_of_slice(self, src: &[T]) -> &'a mut [T] {
unsafe { self.as_maybe_uninit_slice().write_clone_of_slice(src) }
}
}
impl<'a, T: Copy> WRef<'a, [T]> {
#[inline]
pub const fn write_copy_of_slice(self, src: &[T]) -> &'a mut [T] {
unsafe { self.as_maybe_uninit_slice().write_copy_of_slice(src) }
}
}
impl<T> fmt::Debug for WRef<'_, T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&<MaybeUninit<T>>::uninit(), f)
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::undocumented_unsafe_blocks)]
use core::mem::MaybeUninit;
use crate::WRef;
#[test]
fn init_maybe_uninit_int() {
let mut maybe = MaybeUninit::uninit();
let fwd = WRef::from_maybe_uninit_mut(&mut maybe);
fwd.write(1);
assert_eq!(unsafe { maybe.assume_init() }, 1);
}
#[test]
fn init_init_int() {
let mut init = 4;
let fwd = WRef::from_mut(&mut init);
fwd.write(1);
assert_eq!(init, 1);
}
#[test]
fn assume_init_int() {
let mut init = 4;
let fwd = WRef::from_mut(&mut init);
assert_eq!(*unsafe { fwd.assume_init_mut() }, 4);
}
#[test]
fn init_maybe_uninit_int_slice() {
let mut maybe = [MaybeUninit::uninit(); 10];
let fwd = WRef::from_maybe_uninit_slice_mut(&mut maybe);
fwd.write_copy_of_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
assert_eq!(
maybe.map(|x| unsafe { x.assume_init() }),
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
);
}
#[test]
fn init_init_int_slice() {
let mut init = [0; 10];
let fwd = WRef::from_mut(&mut init[..]);
fwd.write_copy_of_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
assert_eq!(init, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
}
#[test]
fn assume_init_int_slice() {
let mut init = [0; 10];
let fwd = WRef::from_mut(&mut init[..]);
assert_eq!(unsafe { fwd.assume_init_mut() }, &[0; 10]);
}
#[test]
fn init_maybe_uninit_char() {
let mut maybe = MaybeUninit::uninit();
let fwd = WRef::from_maybe_uninit_mut(&mut maybe);
fwd.write('あ');
assert_eq!(unsafe { maybe.assume_init() }, 'あ');
}
#[test]
fn init_init_char() {
let mut init = 'A';
let fwd = WRef::from_mut(&mut init);
fwd.write('あ');
assert_eq!(init, 'あ');
}
#[test]
fn assume_init_char() {
let mut init = 'A';
let fwd = WRef::from_mut(&mut init);
assert_eq!(*unsafe { fwd.assume_init_mut() }, 'A');
}
#[test]
fn init_maybe_uninit_char_slice() {
let mut maybe = [MaybeUninit::uninit(); 5];
let fwd = WRef::from_maybe_uninit_slice_mut(&mut maybe);
fwd.write_clone_of_slice(&['あ', 'い', 'う', 'え', 'お']);
assert_eq!(
maybe.map(|x| unsafe { x.assume_init() }),
['あ', 'い', 'う', 'え', 'お']
);
}
#[test]
fn init_init_char_slice() {
let mut init = ['\0'; 5];
let fwd = WRef::from_mut(&mut init[..]);
fwd.write_clone_of_slice(&['あ', 'い', 'う', 'え', 'お']);
assert_eq!(init, ['あ', 'い', 'う', 'え', 'お']);
}
#[test]
fn assume_init_char_slice() {
let mut init = ['\0'; 5];
let fwd = WRef::from_mut(&mut init[..]);
assert_eq!(unsafe { fwd.assume_init_mut() }, &['\0'; 5]);
}
}