use &mut T again

This commit is contained in:
nora 2021-12-22 21:34:38 +01:00
parent e5b7c40028
commit 9a0d125d8d
3 changed files with 37 additions and 53 deletions

View file

@ -1,4 +1,4 @@
use crate::{MutGuard, RawVechonk, Vechonk};
use crate::{RawVechonk, Vechonk};
use alloc::boxed::Box;
use core::marker::PhantomData;
use core::mem;
@ -68,19 +68,20 @@ impl<'a, T: ?Sized> IterMut<'a, T> {
}
impl<'a, T: ?Sized> Iterator for IterMut<'a, T> {
type Item = MutGuard<T>;
type Item = &'a mut T;
fn next(&mut self) -> Option<Self::Item> {
if self.current_index == self.raw.len {
return None;
}
let old_index = self.current_index;
// SAFETY: We just did a bounds check above
let ptr = unsafe { self.raw.get_unchecked_ptr(self.current_index) };
self.current_index += 1;
// SAFETY: We did a bounds check above, and taken `&mut Vechonk`
unsafe { Some(MutGuard::new(self.raw.copy(), old_index)) }
// SAFETY: We rely on `get_unchecked_ptr` returning a valid pointer, which is does, see its SAFETY comments
unsafe { Some(&mut *ptr) }
}
fn size_hint(&self) -> (usize, Option<usize>) {

View file

@ -46,7 +46,7 @@ use alloc::boxed::Box;
use core::cmp;
use core::cmp::Ordering;
use core::hash::{Hash, Hasher};
use core::ops::{Deref, Index};
use core::ops::{Index, IndexMut};
pub use iter::{IntoIter, Iter, IterMut};
@ -137,7 +137,7 @@ impl<T: ?Sized> Vechonk<T> {
}
/// Get a mutable guard to an element at the index. Returns `None` if the index is out of bounds
pub fn get_mut(&mut self, index: usize) -> Option<MutGuard<T>> {
pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
if index < self.len() {
// SAFETY: The index has been checked above
unsafe { Some(self.get_unchecked_mut(index)) }
@ -148,9 +148,11 @@ impl<T: ?Sized> Vechonk<T> {
/// # Safety
/// The index must be in bounds
pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> MutGuard<T> {
// SAFETY: We can assume that `index` is not out of bounds
unsafe { MutGuard::new(self.raw.copy(), index) }
pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut T {
// SAFETY: The metadata is only assigned directly from the pointer metadata of the original object and therefore valid
// The pointer is calculated from the offset, which is also valid
// The pointer is aligned, because it has been aligned manually in `Self::push`
unsafe { &mut *self.raw.get_unchecked_ptr(index) }
}
/// # Safety
@ -174,41 +176,6 @@ impl<T: ?Sized> Vechonk<T> {
}
}
/// A guard that acts similarly to a `&mut T`, but does not allow any arbitrary value to be written,
/// instead checking whether the element has the correct size/alignment to fit the space of the old element.
pub struct MutGuard<T: ?Sized> {
raw: RawVechonk<T>,
/// Must always be in bounds
index: usize,
}
impl<T: ?Sized> MutGuard<T> {
/// # Safety
/// The index must not be out of bounds, and `raw` must be mutable
pub(crate) unsafe fn new(raw: RawVechonk<T>, index: usize) -> Self {
Self { raw, index }
}
/// Write a new element to the location.
/// * If the element fits in the space, the old element is returned
/// * If the element does not fit in the space, the new element is returned again
pub fn try_write(&mut self, element: Box<T>) -> Result<Box<T>, Box<T>> {
self.raw.try_replace_elem(element, self.index)
}
}
impl<T: ?Sized> Deref for MutGuard<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
// SAFETY: The metadata is only assigned directly from the pointer metadata of the original object and therefore valid
// The pointer is calculated from the offset, which is also valid
// The pointer is aligned, because it has been aligned manually in `Self::push`
// We can assume that the index is in bounds
unsafe { &*self.raw.get_unchecked_ptr(self.index) }
}
}
impl<T: ?Sized> Index<usize> for Vechonk<T> {
type Output = T;
@ -222,6 +189,17 @@ impl<T: ?Sized> Index<usize> for Vechonk<T> {
}
}
impl<T: ?Sized> IndexMut<usize> for Vechonk<T> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
if index >= self.len() {
panic!("Out of bounds, index {} for len {}", index, self.len());
}
// SAFETY: The index is not out of bounds
unsafe { self.get_unchecked_mut(index) }
}
}
/// don't bother with destructors for now
impl<T: ?Sized> Drop for Vechonk<T> {
fn drop(&mut self) {

View file

@ -6,6 +6,12 @@ use alloc::boxed::Box;
#[repr(align(2048))]
struct BigAlign(u8);
trait TakeMut {
fn take_mut(&mut self) {}
}
impl<T: ?Sized> TakeMut for T {}
#[test]
fn new() {
let chonk = Vechonk::<()>::new();
@ -236,7 +242,7 @@ fn eq_ne() {
}
#[test]
fn get_mut_deref() {
fn get_mut() {
let mut chonk1: Vechonk<str> = vechonk!["hello".into(), "uwu".into()];
let hello = chonk1.get_mut(0).unwrap();
@ -246,16 +252,15 @@ fn get_mut_deref() {
#[test]
fn get_mut_mutating() {
let mut chonk1: Vechonk<str> = vechonk!["hello".into(), "uwu".into()];
let mut chonk1: Vechonk<dyn TakeMut> = Vechonk::new();
chonk1.push(Box::new("hello"));
chonk1.push(Box::new("uwu"));
let mut hello = chonk1.get_mut(0).unwrap();
let hello = chonk1.get_mut(0).unwrap();
hello.try_write("owo".into()).unwrap();
hello
.try_write("hi, I'm wayyyyy too long".into())
.unwrap_err();
hello.take_mut();
assert_eq!(&*hello, "owo");
assert_eq!(chonk1.len(), 2);
}
#[test]