use std::fmt;
use std::iter::Zip;
use std::ops::{Deref, DerefMut};
use std::slice;
pub struct Mut<'w, T> {
value: &'w mut T,
changed: &'w mut u64,
tick: u64,
}
impl<'w, T> Mut<'w, T> {
#[must_use]
pub fn into_inner(self) -> &'w mut T {
*self.changed = self.tick;
self.value
}
}
impl<T> Deref for Mut<'_, T> {
type Target = T;
fn deref(&self) -> &T {
self.value
}
}
impl<T> DerefMut for Mut<'_, T> {
fn deref_mut(&mut self) -> &mut T {
*self.changed = self.tick;
self.value
}
}
impl<T> AsRef<T> for Mut<'_, T> {
fn as_ref(&self) -> &T {
self.value
}
}
impl<T> AsMut<T> for Mut<'_, T> {
fn as_mut(&mut self) -> &mut T {
self
}
}
impl<T: fmt::Debug> fmt::Debug for Mut<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
#[doc(hidden)]
#[derive(Debug)]
pub struct MutSlice<'w, T> {
values: &'w mut [T],
ticks: &'w mut [u64],
tick: u64,
}
impl<'w, T> MutSlice<'w, T> {
pub(crate) fn new(values: &'w mut [T], ticks: &'w mut [u64], tick: u64) -> Option<Self> {
(values.len() == ticks.len()).then_some(Self {
values,
ticks,
tick,
})
}
pub(crate) fn split_at(self, mid: usize) -> (Self, Self) {
let mid = mid.min(self.values.len()).min(self.ticks.len());
let (values, other_values) = self.values.split_at_mut(mid);
let (ticks, other_ticks) = self.ticks.split_at_mut(mid);
(
Self {
values,
ticks,
tick: self.tick,
},
Self {
values: other_values,
ticks: other_ticks,
tick: self.tick,
},
)
}
}
impl<'w, T> IntoIterator for MutSlice<'w, T> {
type Item = Mut<'w, T>;
type IntoIter = MutIter<'w, T>;
fn into_iter(self) -> MutIter<'w, T> {
MutIter {
rows: self.values.iter_mut().zip(self.ticks.iter_mut()),
tick: self.tick,
}
}
}
#[doc(hidden)]
#[derive(Debug)]
pub struct MutIter<'w, T> {
rows: Zip<slice::IterMut<'w, T>, slice::IterMut<'w, u64>>,
tick: u64,
}
impl<'w, T> Iterator for MutIter<'w, T> {
type Item = Mut<'w, T>;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
let (value, changed) = self.rows.next()?;
Some(Mut {
value,
changed,
tick: self.tick,
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.rows.size_hint()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn only_mutable_access_stamps_the_tick() {
let mut values = [1_u32, 2, 3];
let mut ticks = [1_u64; 3];
let slice = MutSlice::new(&mut values, &mut ticks, 9).unwrap();
let (left, right) = slice.split_at(1);
for mut item in left {
*item += 10;
assert_eq!(format!("{item:?}"), "11");
}
for (i, item) in right.into_iter().enumerate() {
if i == 1 {
let _ = item.into_inner();
} else {
assert_eq!(*item.as_ref(), 2);
}
}
assert_eq!(values, [11, 2, 3]);
assert_eq!(ticks, [9, 1, 9]);
assert!(MutSlice::new(&mut [1_u8][..], &mut [], 0).is_none());
}
}