diff --git a/src/iter.rs b/src/iter.rs index e19c105..7ab57e8 100644 --- a/src/iter.rs +++ b/src/iter.rs @@ -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; + type Item = &'a mut T; fn next(&mut self) -> Option { 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) { diff --git a/src/lib.rs b/src/lib.rs index bbf2c4e..b6163b8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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 Vechonk { } /// 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> { + 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 Vechonk { /// # Safety /// The index must be in bounds - pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> MutGuard { - // 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 Vechonk { } } -/// 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 { - raw: RawVechonk, - /// Must always be in bounds - index: usize, -} - -impl MutGuard { - /// # Safety - /// The index must not be out of bounds, and `raw` must be mutable - pub(crate) unsafe fn new(raw: RawVechonk, 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) -> Result, Box> { - self.raw.try_replace_elem(element, self.index) - } -} - -impl Deref for MutGuard { - 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 Index for Vechonk { type Output = T; @@ -222,6 +189,17 @@ impl Index for Vechonk { } } +impl IndexMut for Vechonk { + 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 Drop for Vechonk { fn drop(&mut self) { diff --git a/src/test.rs b/src/test.rs index 413b814..cb5838e 100644 --- a/src/test.rs +++ b/src/test.rs @@ -6,6 +6,12 @@ use alloc::boxed::Box; #[repr(align(2048))] struct BigAlign(u8); +trait TakeMut { + fn take_mut(&mut self) {} +} + +impl 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 = 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 = vechonk!["hello".into(), "uwu".into()]; + let mut chonk1: Vechonk = 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]