#![cfg_attr(not(test), no_std)]
#![warn(missing_docs)]
use core::{
borrow::{Borrow, BorrowMut},
iter::FusedIterator,
marker::PhantomData,
mem::{MaybeUninit, forget, take, transmute},
ops::{Deref, DerefMut},
slice::IterMut,
};
#[derive(Debug)]
pub struct Initialized<'a, T> {
data: &'a mut [MaybeUninit<T>],
_marker: PhantomData<T>,
}
type InitializedWithRemainder<'a, T> = (Initialized<'a, T>, &'a mut [MaybeUninit<T>]);
pub trait SliceExt {
type Item;
fn write_copy_of_slice_owned(&mut self, src: &[Self::Item]) -> Initialized<Self::Item>
where
Self::Item: Copy;
fn write_clone_of_slice_owned(&mut self, src: &[Self::Item]) -> Initialized<Self::Item>
where
Self::Item: Clone;
fn write_filled_owned(&mut self, value: Self::Item) -> Initialized<Self::Item>
where
Self::Item: Clone;
fn write_with_owned<F>(&mut self, f: F) -> Initialized<Self::Item>
where
F: FnMut(usize) -> Self::Item;
fn write_iter_owned<I>(&mut self, it: I) -> InitializedWithRemainder<Self::Item>
where
I: IntoIterator<Item = Self::Item>;
fn try_write_iter_owned<I, E>(
&mut self,
it: I,
) -> Result<InitializedWithRemainder<Self::Item>, E>
where
I: IntoIterator<Item = Result<Self::Item, E>>;
}
#[derive(Debug, Default)]
pub struct IntoIter<'a, T> {
iter: IterMut<'a, MaybeUninit<T>>,
_marker: PhantomData<T>,
}
struct Guard<'a, T> {
slice: &'a mut [MaybeUninit<T>],
initialized: usize,
}
impl<T> Deref for Initialized<'_, T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
unsafe { &*(self.data as *const [MaybeUninit<T>] as *const [T]) }
}
}
impl<T> DerefMut for Initialized<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *(self.data as *mut [MaybeUninit<T>] as *mut [T]) }
}
}
impl<'a, T> IntoIterator for Initialized<'a, T> {
type Item = T;
type IntoIter = IntoIter<'a, T>;
fn into_iter(mut self) -> Self::IntoIter {
let im = take(&mut self.data).iter_mut();
forget(self);
IntoIter {
iter: im,
_marker: PhantomData,
}
}
}
impl<T> Iterator for IntoIter<'_, T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|v| unsafe { v.assume_init_read() })
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<T> DoubleEndedIterator for IntoIter<'_, T> {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter
.next_back()
.map(|v| unsafe { v.assume_init_read() })
}
}
impl<T> ExactSizeIterator for IntoIter<'_, T> {
fn len(&self) -> usize {
self.iter.len()
}
}
impl<T> Drop for Initialized<'_, T> {
fn drop(&mut self) {
for v in self.data.iter_mut() {
unsafe { v.assume_init_drop() }
}
}
}
impl<T> Drop for IntoIter<'_, T> {
fn drop(&mut self) {
for v in self.iter.by_ref() {
unsafe { v.assume_init_drop() }
}
}
}
impl<T> SliceExt for [MaybeUninit<T>] {
type Item = T;
fn write_copy_of_slice_owned(&mut self, src: &[Self::Item]) -> Initialized<Self::Item>
where
Self::Item: Copy,
{
let uninit_src: &[MaybeUninit<T>] = unsafe { transmute(src) };
self.copy_from_slice(uninit_src);
Initialized {
data: self,
_marker: PhantomData,
}
}
fn write_clone_of_slice_owned(&mut self, src: &[Self::Item]) -> Initialized<Self::Item>
where
Self::Item: Clone,
{
assert_eq!(
self.len(),
src.len(),
"destination and source slices have different lengths"
);
let len = self.len();
let src = &src[..len];
let mut guard = Guard {
slice: self,
initialized: 0,
};
for (i, val) in src.iter().enumerate() {
guard.slice[i].write(val.clone());
guard.initialized += 1;
}
forget(guard);
Initialized {
data: self,
_marker: PhantomData,
}
}
#[doc(alias = "memset")]
fn write_filled_owned(&mut self, value: Self::Item) -> Initialized<Self::Item>
where
Self::Item: Clone,
{
let mut guard = Guard {
slice: self,
initialized: 0,
};
if let Some((last, elems)) = guard.slice.split_last_mut() {
for el in elems {
el.write(value.clone());
guard.initialized += 1;
}
last.write(value);
}
forget(guard);
Initialized {
data: self,
_marker: PhantomData,
}
}
fn write_with_owned<F>(&mut self, mut f: F) -> Initialized<Self::Item>
where
F: FnMut(usize) -> Self::Item,
{
let mut guard = Guard {
slice: self,
initialized: 0,
};
for (idx, element) in guard.slice.iter_mut().enumerate() {
element.write(f(idx));
guard.initialized += 1;
}
forget(guard);
Initialized {
data: self,
_marker: PhantomData,
}
}
fn write_iter_owned<I>(
&mut self,
it: I,
) -> (Initialized<Self::Item>, &mut [MaybeUninit<Self::Item>])
where
I: IntoIterator<Item = Self::Item>,
{
let iter = it.into_iter();
let mut guard = Guard {
slice: self,
initialized: 0,
};
for (element, val) in guard.slice.iter_mut().zip(iter) {
element.write(val);
guard.initialized += 1;
}
let initialized_len = guard.initialized;
forget(guard);
let (initted, remainder) = unsafe { self.split_at_mut_unchecked(initialized_len) };
(
Initialized {
data: initted,
_marker: PhantomData,
},
remainder,
)
}
fn try_write_iter_owned<I, E>(
&mut self,
it: I,
) -> Result<(Initialized<Self::Item>, &mut [MaybeUninit<Self::Item>]), E>
where
I: IntoIterator<Item = Result<Self::Item, E>>,
{
let iter = it.into_iter();
let mut guard = Guard {
slice: self,
initialized: 0,
};
for (element, val) in guard.slice.iter_mut().zip(iter) {
element.write(val?);
guard.initialized += 1;
}
let initialized_len = guard.initialized;
forget(guard);
let (initted, remainder) = unsafe { self.split_at_mut_unchecked(initialized_len) };
Ok((
Initialized {
data: initted,
_marker: PhantomData,
},
remainder,
))
}
}
impl<T> Drop for Guard<'_, T> {
fn drop(&mut self) {
for v in self.slice[..self.initialized].iter_mut() {
unsafe {
v.assume_init_drop();
}
}
}
}
impl<T> AsRef<[T]> for Initialized<'_, T> {
fn as_ref(&self) -> &[T] {
self.deref()
}
}
impl<T> AsRef<[T]> for IntoIter<'_, T> {
fn as_ref(&self) -> &[T] {
unsafe { &*(self.iter.as_slice() as *const [MaybeUninit<T>] as *const [T]) }
}
}
impl<T> AsMut<[T]> for Initialized<'_, T> {
fn as_mut(&mut self) -> &mut [T] {
self.deref_mut()
}
}
impl<T> Borrow<[T]> for Initialized<'_, T> {
fn borrow(&self) -> &[T] {
self.deref()
}
}
impl<T> BorrowMut<[T]> for Initialized<'_, T> {
fn borrow_mut(&mut self) -> &mut [T] {
self.deref_mut()
}
}
unsafe impl<T: Send> Send for Initialized<'_, T> {}
unsafe impl<T: Send> Send for IntoIter<'_, T> {}
unsafe impl<T: Sync> Sync for Initialized<'_, T> {}
unsafe impl<T: Sync> Sync for IntoIter<'_, T> {}
impl<T> Default for Initialized<'_, T> {
fn default() -> Self {
Self {
data: &mut [],
_marker: PhantomData,
}
}
}
impl<T> FusedIterator for IntoIter<'_, T> {}
impl<T> IntoIter<'_, T> {
pub fn as_slice(&self) -> &[T] {
self.as_ref()
}
}
#[cfg(test)]
mod tests {
use core::cell::RefCell;
use std::collections::HashSet;
use super::*;
#[derive(Debug)]
struct DropKey<'a> {
index: usize,
set: &'a RefCell<HashSet<usize>>,
inset: bool,
}
impl<'a> DropKey<'a> {
fn new(index: usize, set: &'a RefCell<HashSet<usize>>) -> Self {
assert!(
set.borrow_mut().insert(index),
"set already contains index {index}"
);
Self {
index,
set,
inset: true,
}
}
fn new_notinset(index: usize, set: &'a RefCell<HashSet<usize>>) -> Self {
Self {
index,
set,
inset: false,
}
}
}
impl<'a> Drop for DropKey<'a> {
fn drop(&mut self) {
if self.inset {
assert!(
self.set.borrow_mut().remove(&self.index),
"set does not contain index {}",
self.index
);
}
}
}
impl<'a> Clone for DropKey<'a> {
fn clone(&self) -> Self {
assert!(
self.set.borrow_mut().insert(self.index),
"set already contains index {}",
self.index
);
Self {
index: self.index,
set: self.set,
inset: true,
}
}
}
struct DropCount<'a> {
count: &'a RefCell<usize>,
}
impl<'a> DropCount<'a> {
fn new(count: &'a RefCell<usize>) -> Self {
*count.borrow_mut() += 1;
Self { count }
}
}
impl<'a> Clone for DropCount<'a> {
fn clone(&self) -> Self {
Self::new(self.count)
}
}
impl<'a> Drop for DropCount<'a> {
fn drop(&mut self) {
*self.count.borrow_mut() -= 1;
}
}
impl<'a> PartialEq for DropKey<'a> {
fn eq(&self, other: &Self) -> bool {
self.index == other.index
}
}
#[test]
fn write_iter() {
let set = RefCell::new(HashSet::new());
const CAP: usize = 10;
const NUM: usize = 5;
let mut buf = [const { MaybeUninit::uninit() }; CAP];
let (written, uninit) = buf.write_iter_owned((0..NUM).map(|v| DropKey::new(v, &set)));
let setcmp = RefCell::new(HashSet::new());
let expected = (0..NUM)
.map(|v| DropKey::new(v, &setcmp))
.collect::<Vec<_>>();
assert_eq!(*written, *expected);
assert_eq!(uninit.len(), CAP - NUM);
for idx in 0..NUM {
assert!(
set.borrow().contains(&idx),
"set does not contain index {idx}"
);
}
drop(written);
assert!(set.borrow().is_empty(), "set is empty after dropping");
}
#[test]
fn write_with() {
let set = RefCell::new(HashSet::new());
const CAP: usize = 10;
let mut buf = [const { MaybeUninit::uninit() }; CAP];
let written = buf.write_with_owned(|i| DropKey::new(i, &set));
let setcmp = RefCell::new(HashSet::new());
let expected = (0..CAP)
.map(|v| DropKey::new(v, &setcmp))
.collect::<Vec<_>>();
assert_eq!(*written, *expected);
for idx in 0..CAP {
assert!(
set.borrow().contains(&idx),
"set does not contain index {idx}"
);
}
drop(written);
assert!(set.borrow().is_empty(), "set is empty after dropping");
}
#[test]
fn write_clone_of_slice() {
let set = RefCell::new(HashSet::new());
const CAP: usize = 10;
let slc = (0..CAP)
.map(|v| DropKey::new_notinset(v, &set))
.collect::<Vec<_>>();
let mut buf = [const { MaybeUninit::uninit() }; CAP];
let written = buf.write_clone_of_slice_owned(&slc);
assert_eq!(*written, *slc);
for idx in 0..CAP {
assert!(
set.borrow().contains(&idx),
"set does not contain index {idx}"
);
}
drop(written);
assert!(set.borrow().is_empty(), "set is empty after dropping");
}
#[test]
fn write_copy_of_slice() {
const CAP: usize = 10;
let slc = (0..CAP).collect::<Vec<_>>();
let mut buf = [const { MaybeUninit::uninit() }; CAP];
let written = buf.write_copy_of_slice_owned(&slc);
assert_eq!(*written, *slc);
}
#[test]
fn write_filled() {
const CAP: usize = 10;
let count = RefCell::new(0);
let mut buf = [const { MaybeUninit::uninit() }; CAP];
let written = buf.write_filled_owned(DropCount::new(&count));
assert_eq!(*count.borrow(), 10);
drop(written);
assert_eq!(*count.borrow(), 0);
}
#[test]
fn test_into_iter() {
let set = RefCell::new(HashSet::new());
const CAP: usize = 10;
let mut buf = [const { MaybeUninit::uninit() }; CAP];
let mut iter = buf.write_with_owned(|i| DropKey::new(i, &set)).into_iter();
assert_eq!(iter.len(), 10);
const TAKE: usize = 5;
iter.nth(TAKE - 1).unwrap();
let borrow = set.borrow();
for j in 0..TAKE {
assert!(!borrow.contains(&j), "set contains index {j}");
}
for j in TAKE..CAP {
assert!(borrow.contains(&j), "set does not contains index {j}");
}
drop(borrow);
assert_eq!(iter.len(), 5);
iter.next_back().unwrap();
let borrow = set.borrow();
for j in 0..TAKE {
assert!(!borrow.contains(&j), "set contains index {j}");
}
for j in TAKE..(CAP - 1) {
assert!(borrow.contains(&j), "set does not contains index {j}");
}
assert!(!borrow.contains(&CAP), "set contains index 9");
drop(borrow);
drop(iter);
assert!(set.borrow().is_empty(), "set is not empty");
}
#[test]
fn try_write_iter() {
const CAP: usize = 10;
let mut buf = [const { MaybeUninit::uninit() }; CAP];
let first_batch = [Ok::<_, ()>(1), Ok(2), Ok(3), Ok(4)];
let (initialized, remainder) = buf
.try_write_iter_owned(first_batch.iter().cloned())
.unwrap();
let expected = first_batch
.into_iter()
.map(Result::unwrap)
.collect::<Vec<_>>();
assert_eq!(expected.as_slice(), &*initialized);
assert_eq!(remainder.len(), 6);
drop(initialized);
let second_batch = [Ok(1), Ok(2), Err("err")];
assert_eq!(buf.try_write_iter_owned(second_batch).unwrap_err(), "err");
let third_batch = (0..CAP).map(Result::Ok).chain([Err("err")]);
let (initialized, remainder) = buf.try_write_iter_owned(third_batch).unwrap();
assert!(initialized.into_iter().eq(0..CAP));
assert!(remainder.is_empty());
}
}