use core::{marker::PhantomData, mem};
use crate::{PutAt, PutFromSliceAt, WriteAt, WriteFromSliceAt};
pub struct WriteOnlySlice<'a, T: 'a> {
data: *mut T,
len: usize,
_phantom: PhantomData<&'a T>,
}
impl<'a, T: 'a> WriteOnlySlice<'a, T> {
#[inline]
pub unsafe fn from_raw_parts(data: *mut T, len: usize) -> Self {
debug_assert!(
!data.is_null() && (data.align_offset(mem::align_of::<u16>()) == 0),
"attempt to create unaligned or null slice"
);
debug_assert!(
mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
"attempt to create slice covering at least half the address space"
);
Self {
data,
len,
_phantom: PhantomData,
}
}
#[inline]
pub fn len(&self) -> usize {
self.len
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
}
impl<'a, T: 'a> PutAt<T> for WriteOnlySlice<'a, T> {
#[inline]
fn put_at(&mut self, index: usize, value: T) {
assert!(index < self.len);
unsafe {
self.put_at_unchecked(index, value);
}
}
#[inline]
unsafe fn put_at_unchecked(&mut self, index: usize, value: T) {
*self.data.add(index) = value;
}
}
impl<'a, T: 'a> WriteAt<T> for WriteOnlySlice<'a, T> {
#[inline]
fn write_at(&mut self, index: usize, value: T) {
assert!(index < self.len);
unsafe {
self.write_at_unchecked(index, value);
}
}
#[inline]
unsafe fn write_at_unchecked(&mut self, index: usize, value: T) {
self.data.add(index).write(value);
}
}
impl<'a, T: 'a> PutFromSliceAt<T> for WriteOnlySlice<'a, T> {
#[inline]
fn put_cloning_from_slice_at(&mut self, src: &[T], offset: usize)
where
T: Clone,
{
assert!(offset + src.len() <= self.len);
for (index, item) in src.iter().enumerate() {
unsafe {
*self.data.add(offset + index) = item.clone();
}
}
}
}
impl<'a, T: 'a> WriteFromSliceAt<T> for WriteOnlySlice<'a, T> {
#[inline]
fn write_cloning_from_slice_at(&mut self, src: &[T], offset: usize)
where
T: Clone,
{
assert!(offset + src.len() <= self.len);
for (index, item) in src.iter().enumerate() {
unsafe {
self.data.add(offset + index).write(item.clone());
}
}
}
#[inline]
fn write_copying_from_slice_at(&mut self, src: &[T], offset: usize)
where
T: Copy,
{
assert!(src.len() <= self.len - offset);
unsafe {
self.data
.add(offset)
.copy_from_nonoverlapping(src.as_ptr(), src.len());
}
}
}
impl<'a, T: 'a> From<&'a mut [T]> for WriteOnlySlice<'a, T> {
#[inline]
fn from(slice: &'a mut [T]) -> Self {
unsafe { Self::from_raw_parts(slice.as_mut_ptr(), slice.len()) }
}
}
#[cfg(test)]
mod tests {
use super::*;
use droptest::prelude::*;
#[test]
fn from_raw_parts() {
let registry = DropRegistry::default();
let mut guards: Vec<_> = (0..3).map(|i| registry.new_guard_for(i)).collect();
let reference = unsafe { WriteOnlySlice::from_raw_parts(&mut guards, 3) };
std::mem::drop(reference);
assert_drop_stats!(registry, { created: 3, dropped: 0 });
std::mem::drop(guards);
assert_drop_stats!(registry, { created: 3, dropped: 3 });
}
#[test]
fn from() {
let registry = DropRegistry::default();
let mut guards: Vec<_> = (0..3).map(|i| registry.new_guard_for(i)).collect();
let reference = WriteOnlySlice::from(&mut guards[..]);
std::mem::drop(reference);
assert_drop_stats!(registry, { created: 3, dropped: 0 });
std::mem::drop(guards);
assert_drop_stats!(registry, { created: 3, dropped: 3 });
}
#[test]
fn put_at() {
let registry = DropRegistry::default();
let (old_ids, mut guards): (Vec<_>, Vec<_>) =
(0..3).map(|i| registry.new_guard_for(i).by_id()).unzip();
let (new_id, new_guard) = registry.new_guard_for(3).by_id();
let mut slice = WriteOnlySlice::from(&mut guards[..]);
slice.put_at(1, new_guard);
assert_eq!(guards[1].id(), new_id);
assert_eq!(guards[1].value(), &3);
assert_drop!(registry, old_ids[1]);
assert_drop_stats!(registry, { created: 4, dropped: 1 });
}
#[test]
#[should_panic]
fn put_at_out_of_bounds() {
let registry = DropRegistry::default();
let mut guards: Vec<_> = (0..3).map(|i| registry.new_guard_for(i)).collect();
let new_guard = registry.new_guard_for(3);
let mut slice = WriteOnlySlice::from(&mut guards[..]);
slice.put_at(10, new_guard);
}
#[test]
fn write_at() {
let registry = DropRegistry::default();
let (old_ids, mut guards): (Vec<_>, Vec<_>) =
(0..3).map(|i| registry.new_guard_for(i).by_id()).unzip();
let (new_id, new_guard) = registry.new_guard_for(3).by_id();
let mut slice = WriteOnlySlice::from(&mut guards[..]);
slice.write_at(1, new_guard);
assert_eq!(guards[1].id(), new_id);
assert_eq!(guards[1].value(), &3);
assert_no_drop!(registry, old_ids[1]);
assert_drop_stats!(registry, { created: 4, dropped: 0 });
}
#[test]
#[should_panic]
fn write_at_out_of_bounds() {
let registry = DropRegistry::default();
let mut guards: Vec<_> = (0..3).map(|i| registry.new_guard_for(i)).collect();
let new_guard = registry.new_guard_for(3);
let mut slice = WriteOnlySlice::from(&mut guards[..]);
slice.write_at(10, new_guard);
}
#[test]
fn put_cloning_from_slice_at() {
let registry = DropRegistry::default();
let (old_ids, mut guards): (Vec<_>, Vec<_>) =
(0..5).map(|i| registry.new_guard_for(i).by_id()).unzip();
let new_guards: Vec<_> = (5..8).map(|i| registry.new_guard_for(i)).collect();
let mut slice = WriteOnlySlice::from(&mut guards[..]);
slice.put_cloning_from_slice_at(&new_guards[..], 1);
assert_ne!(guards[1].id(), old_ids[1]);
assert_eq!(guards[1].value(), &5);
assert_ne!(guards[2].id(), old_ids[1]);
assert_eq!(guards[2].value(), &6);
assert_ne!(guards[3].id(), old_ids[2]);
assert_eq!(guards[3].value(), &7);
assert_drop!(registry, old_ids[1]);
assert_drop!(registry, old_ids[2]);
assert_drop!(registry, old_ids[3]);
assert_drop_stats!(registry, { created: 11, dropped: 3 });
}
#[test]
fn write_cloning_from_slice_at() {
let registry = DropRegistry::default();
let (old_ids, mut guards): (Vec<_>, Vec<_>) =
(0..5).map(|i| registry.new_guard_for(i).by_id()).unzip();
let new_guards: Vec<_> = (5..8).map(|i| registry.new_guard_for(i)).collect();
let mut slice = WriteOnlySlice::from(&mut guards[..]);
slice.write_cloning_from_slice_at(&new_guards[..], 1);
assert_ne!(guards[1].id(), old_ids[1]);
assert_eq!(guards[1].value(), &5);
assert_ne!(guards[2].id(), old_ids[1]);
assert_eq!(guards[2].value(), &6);
assert_ne!(guards[3].id(), old_ids[2]);
assert_eq!(guards[3].value(), &7);
assert_no_drop!(registry, old_ids[1]);
assert_no_drop!(registry, old_ids[2]);
assert_no_drop!(registry, old_ids[3]);
assert_drop_stats!(registry, { created: 11, dropped: 0 });
}
#[test]
fn write_copying_from_slice_at() {
let mut values: Vec<_> = (0..5).collect();
let new_values: Vec<_> = (5..8).collect();
let mut slice = WriteOnlySlice::from(&mut values[..]);
slice.write_copying_from_slice_at(&new_values[..], 1);
assert_eq!(values, &[0, 5, 6, 7, 4]);
}
}