// SPDX-FileCopyrightText: 2025 Topola contributors // // SPDX-License-Identifier: MIT // //! `MaybeReversed`: Structure making it easier to interact with a vector/slice and its reversal uniformly. use alloc::{sync::Arc, vec::Vec}; use core::{borrow, iter::DoubleEndedIterator, marker::PhantomData, ops}; /// Structure making it easier to interact with a vector/slice and its reversal uniformly. #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct MaybeReversed { pub inner: I, pub reversed: bool, item_marker: PhantomData T>, } impl Clone for MaybeReversed { fn clone(&self) -> Self { Self { inner: self.inner.clone(), reversed: self.reversed, item_marker: PhantomData, } } } impl Copy for MaybeReversed {} impl MaybeReversed { pub fn new(inner: I) -> Self { Self { inner, reversed: false, item_marker: PhantomData, } } pub fn map(self, f: F) -> MaybeReversed where F: FnOnce(I) -> J, { let Self { inner, reversed, .. } = self; MaybeReversed { inner: f(inner), reversed, item_marker: PhantomData, } } #[inline] #[must_use] pub fn flip(mut self) -> Self { self.reversed ^= true; self } } impl MaybeReversed<&mut Arc<[T]>, T> { pub fn with_borrow_mut(&mut self, f: F) -> R where F: FnOnce(MaybeReversed<&mut Vec, T>) -> R, T: Clone, { let mut inner: Vec = self.inner.iter().cloned().collect(); let ret = f(MaybeReversed { inner: &mut inner, reversed: self.reversed, item_marker: PhantomData, }); *self.inner = Arc::from(inner.into_boxed_slice()); ret } } impl<'a, I: ?Sized + borrow::Borrow<[T]>, T> MaybeReversed<&'a I, T> { pub fn as_ref(&self) -> MaybeReversed<&'a [T], T> { MaybeReversed { inner: self.inner.borrow(), reversed: self.reversed, item_marker: PhantomData, } } #[inline] pub fn len(&self) -> usize { self.inner.borrow().len() } pub fn resolve_index(&self, index: usize) -> usize { if self.reversed { self.len().checked_sub(index + 1).unwrap() } else { index } } #[inline] pub fn iter(&self) -> MaybeReversed, T> { MaybeReversed { inner: self.inner.borrow().iter(), reversed: self.reversed, item_marker: PhantomData, } } } impl, T> MaybeReversed<&mut I, T> { #[inline(always)] pub fn as_ref(&self) -> MaybeReversed<&'_ I, T> { MaybeReversed { inner: &*self.inner, reversed: self.reversed, item_marker: PhantomData, } } #[inline] pub fn len(&self) -> usize { self.inner.borrow().len() } #[inline] pub fn is_empty(&self) -> bool { self.inner.borrow().is_empty() } #[inline] pub fn resolve_index(&self, index: usize) -> usize { self.as_ref().resolve_index(index) } #[inline] pub fn iter(&self) -> MaybeReversed, T> { self.as_ref().iter() } } impl MaybeReversed<&mut [T], T> { #[inline] pub fn iter_mut(&mut self) -> MaybeReversed, T> { MaybeReversed { inner: self.inner.iter_mut(), reversed: self.reversed, item_marker: PhantomData, } } } impl MaybeReversed<&mut Vec, T> { #[inline(always)] pub fn as_ref_slice(&self) -> MaybeReversed<&'_ [T], T> { MaybeReversed { inner: &self.inner[..], reversed: self.reversed, item_marker: PhantomData, } } #[inline(always)] pub fn as_mut_slice(&mut self) -> MaybeReversed<&'_ mut [T], T> { MaybeReversed { inner: &mut self.inner[..], reversed: self.reversed, item_marker: PhantomData, } } pub fn insert(&mut self, index: usize, element: T) { if self.reversed { self.inner .insert(self.len().checked_sub(index).unwrap(), element); } else { self.inner.insert(index, element); } } } impl + ops::Index, T> ops::Index for MaybeReversed<&I, T> { type Output = >::Output; fn index(&self, index: usize) -> &Self::Output { self.inner.index(self.resolve_index(index)) } } impl + ops::Index, T> ops::Index for MaybeReversed<&mut I, T> { type Output = >::Output; fn index(&self, index: usize) -> &Self::Output { self.inner.index(self.resolve_index(index)) } } impl + ops::IndexMut, T> ops::IndexMut for MaybeReversed<&mut I, T> { fn index_mut(&mut self, index: usize) -> &mut Self::Output { self.inner.index_mut(self.resolve_index(index)) } } #[inline] pub fn index(obj: &[T], idx: MaybeReversed) -> &T { use ops::Index; obj.index( MaybeReversed { inner: obj, reversed: idx.reversed, item_marker: PhantomData, } .resolve_index(idx.inner), ) } #[inline] pub fn index_mut(obj: &mut [T], idx: MaybeReversed) -> &mut T { use ops::IndexMut; obj.index_mut( MaybeReversed { inner: &obj[..], reversed: idx.reversed, item_marker: PhantomData, } .resolve_index(idx.inner), ) } #[inline] pub fn index_forward(obj: &[T], idx: MaybeReversed) -> MaybeReversed<&T, U> { MaybeReversed { inner: &obj[idx.inner], reversed: idx.reversed, item_marker: PhantomData, } } #[inline] pub fn index_mut_forward( obj: &mut [T], idx: MaybeReversed, ) -> MaybeReversed<&mut T, U> { MaybeReversed { inner: &mut obj[idx.inner], reversed: idx.reversed, item_marker: PhantomData, } } impl Iterator for MaybeReversed { type Item = ::Item; fn next(&mut self) -> Option<::Item> { match self.reversed { false => self.inner.next(), true => self.inner.next_back(), } } fn fold(self, init: B, f: F) -> B where F: FnMut(B, Self::Item) -> B, { match self.reversed { false => self.inner.fold(init, f), true => self.inner.rfold(init, f), } } } impl DoubleEndedIterator for MaybeReversed { fn next_back(&mut self) -> Option<::Item> { match self.reversed { false => self.inner.next_back(), true => self.inner.next(), } } fn rfold(self, init: B, f: F) -> B where F: FnMut(B, Self::Item) -> B, { match self.reversed { false => self.inner.rfold(init, f), true => self.inner.fold(init, f), } } }