mirror of
https://github.com/Noratrieb/vechonk.git
synced 2026-01-14 16:45:10 +01:00
use &mut T again
This commit is contained in:
parent
e5b7c40028
commit
9a0d125d8d
3 changed files with 37 additions and 53 deletions
11
src/iter.rs
11
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<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>) {
|
||||
|
|
|
|||
58
src/lib.rs
58
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<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) {
|
||||
|
|
|
|||
21
src/test.rs
21
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<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]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue