use crate::{
chunks_exact::ChunksExact, index::SoaIndex, iter_raw::IterRaw, AsSoaRef, Iter, IterMut,
SliceMut, SliceRef, Soa, SoaDeref, SoaRaw, Soapy,
};
use std::{
cmp::Ordering,
fmt::{self, Debug, Formatter},
hash::{Hash, Hasher},
marker::PhantomData,
ops::{ControlFlow, Deref, DerefMut},
};
pub struct Slice<T: Soapy, D: ?Sized = [()]> {
pub(crate) raw: T::Raw,
pub(crate) dst: D,
}
impl<T> Slice<T, ()>
where
T: Soapy,
{
pub(crate) fn empty() -> Self {
Self::with_raw(<T::Raw as SoaRaw>::dangling())
}
#[doc(hidden)]
pub fn with_raw(raw: T::Raw) -> Self {
Self { raw, dst: () }
}
pub(crate) unsafe fn as_unsized_mut<'a>(&mut self, len: usize) -> &'a mut Slice<T> {
&mut *(std::ptr::slice_from_raw_parts_mut(self, len) as *mut Slice<T>)
}
pub(crate) unsafe fn as_unsized<'a>(&self, len: usize) -> &'a Slice<T> {
&*(std::ptr::slice_from_raw_parts(self, len) as *const Slice<T>)
}
}
impl<T, D: ?Sized> Slice<T, D>
where
T: Soapy,
{
#[doc(hidden)]
pub const fn raw(&self) -> T::Raw {
self.raw
}
}
impl<T> Slice<T>
where
T: Soapy,
{
pub const fn len(&self) -> usize {
self.dst.len()
}
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
pub const fn iter(&self) -> Iter<T> {
Iter {
iter_raw: IterRaw {
slice: unsafe { self.as_sized() },
len: self.len(),
adapter: PhantomData,
},
_marker: PhantomData,
}
}
pub fn iter_mut(&mut self) -> IterMut<T> {
IterMut {
iter_raw: IterRaw {
slice: unsafe { self.as_sized() },
len: self.len(),
adapter: PhantomData,
},
_marker: PhantomData,
}
}
pub fn get<I>(&self, index: I) -> Option<I::Output<'_>>
where
I: SoaIndex<T>,
{
index.get(self)
}
pub fn get_mut<I>(&mut self, index: I) -> Option<I::OutputMut<'_>>
where
I: SoaIndex<T>,
{
index.get_mut(self)
}
pub fn idx<I>(&self, index: I) -> I::Output<'_>
where
I: SoaIndex<T>,
{
self.get(index).expect("index out of bounds")
}
pub fn idx_mut<I>(&mut self, index: I) -> I::OutputMut<'_>
where
I: SoaIndex<T>,
{
self.get_mut(index).expect("index out of bounds")
}
pub fn swap(&mut self, a: usize, b: usize) {
if a >= self.len() || b >= self.len() {
panic!("index out of bounds");
}
unsafe {
let a = self.raw().offset(a);
let b = self.raw().offset(b);
let tmp = a.get();
b.copy_to(a, 1);
b.set(tmp);
}
}
pub fn first(&self) -> Option<T::Ref<'_>> {
self.get(0)
}
pub fn first_mut(&mut self) -> Option<T::RefMut<'_>> {
self.get_mut(0)
}
pub fn last(&self) -> Option<T::Ref<'_>> {
self.get(self.len().saturating_sub(1))
}
pub fn last_mut(&mut self) -> Option<T::RefMut<'_>> {
self.get_mut(self.len().saturating_sub(1))
}
pub fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<'_, T> {
if chunk_size == 0 {
panic!("chunk size must be nonzero")
}
ChunksExact::new(self, chunk_size)
}
pub fn slices(&self) -> T::Slices<'_> {
unsafe { self.raw.slices(self.len()) }
}
pub fn slices_mut(&mut self) -> T::SlicesMut<'_> {
unsafe { self.raw.slices_mut(self.len()) }
}
pub(crate) const unsafe fn as_sized(&self) -> Slice<T, ()> {
*(self as *const _ as *const Slice<T, ()>)
}
}
impl<T> Clone for Slice<T, ()>
where
T: Soapy,
{
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for Slice<T, ()> where T: Soapy {}
impl<'a, T> IntoIterator for &'a Slice<T>
where
T: Soapy,
{
type Item = T::Ref<'a>;
type IntoIter = Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T> IntoIterator for &'a mut Slice<T>
where
T: Soapy,
{
type Item = T::RefMut<'a>;
type IntoIter = IterMut<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
impl<T> PartialEq for Slice<T>
where
T: Soapy,
for<'a> T::Ref<'a>: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.len() == other.len() && self.iter().zip(other.iter()).all(|(me, them)| me == them)
}
}
impl<T> Eq for Slice<T>
where
T: Soapy,
for<'a> T::Ref<'a>: Eq,
{
}
impl<T> PartialEq<Slice<T>> for [T]
where
T: Soapy,
for<'a> T::Ref<'a>: PartialEq,
{
fn eq(&self, other: &Slice<T>) -> bool {
self.len() == other.len()
&& self
.iter()
.zip(other.iter())
.all(|(me, them)| them.as_soa_ref() == me.as_soa_ref())
}
}
impl<T> PartialEq<[T]> for Slice<T>
where
T: Soapy,
for<'a> T::Ref<'a>: PartialEq,
{
fn eq(&self, other: &[T]) -> bool {
self.len() == other.len()
&& self
.iter()
.zip(other.iter())
.all(|(me, them)| me == them.as_soa_ref())
}
}
macro_rules! as_slice_eq {
($t:ty $(,$N:tt)?) => {
impl<T $(,const $N: usize)?> PartialEq<$t> for Slice<T>
where
T: Soapy,
for<'a> T::Ref<'a>: PartialEq,
{
fn eq(&self, other: &$t) -> bool {
self.eq(other.as_slice())
}
}
impl<T $(,const $N: usize)?> PartialEq<Slice<T>> for $t
where
T: Soapy,
for<'a> T::Ref<'a>: PartialEq,
{
fn eq(&self, other: &Slice<T>) -> bool {
self.as_slice().eq(other)
}
}
};
}
as_slice_eq!([T; N], N);
as_slice_eq!(Vec<T>);
macro_rules! trivial_ref_eq {
($t:ty $(,$N:tt)?) => {
impl<T $(,const $N: usize)?> PartialEq<$t> for Slice<T>
where
T: Soapy ,
for<'a> T::Ref<'a>: PartialEq,
{
fn eq(&self, other: &$t) -> bool {
self.eq(*other)
}
}
impl<T $(,const $N: usize)?> PartialEq<Slice<T>> for $t
where
T: Soapy,
for<'a> T::Ref<'a>: PartialEq,
{
fn eq(&self, other: &Slice<T>) -> bool {
(**self).eq(other)
}
}
};
}
trivial_ref_eq!(&[T]);
trivial_ref_eq!(&mut [T]);
trivial_ref_eq!(&[T; N], N);
trivial_ref_eq!(&mut [T; N], N);
macro_rules! eq_for_slice_ref {
($t:ty) => {
eq_for_slice_ref!($t, Vec<T>);
eq_for_slice_ref!($t, [T]);
eq_for_slice_ref!($t, [T; N], const N: usize);
eq_for_slice_ref!($t, Slice<T>);
eq_for_slice_ref!($t, SliceRef<'_, T>);
eq_for_slice_ref!($t, SliceMut<'_, T>);
eq_for_slice_ref!($t, Soa<T>);
};
($t:ty, $s:ty $(,$($b:tt)+)?) => {
impl<T $(,$($b)+)?> PartialEq<$s> for $t
where
T: Soapy ,
for<'a> T::Ref<'a>: PartialEq,
{
fn eq(&self, other: &$s) -> bool {
<Slice<T> as PartialEq<$s>>::eq(*self, other)
}
}
};
}
eq_for_slice_ref!(&Slice<T>);
eq_for_slice_ref!(&mut Slice<T>);
impl<T> Debug for Slice<T>
where
T: Soapy,
for<'a> T::Ref<'a>: Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut list = f.debug_list();
self.iter().for_each(|item| {
list.entry(&item);
});
list.finish()
}
}
impl<T> PartialOrd for Slice<T>
where
T: Soapy,
for<'a> T::Ref<'a>: PartialOrd,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match self
.iter()
.zip(other.iter())
.try_fold(Ordering::Equal, |_, (a, b)| match a.partial_cmp(&b) {
ord @ (None | Some(Ordering::Less | Ordering::Greater)) => ControlFlow::Break(ord),
Some(Ordering::Equal) => ControlFlow::Continue(self.len().cmp(&other.len())),
}) {
ControlFlow::Continue(ord) => Some(ord),
ControlFlow::Break(ord) => ord,
}
}
}
impl<T> Ord for Slice<T>
where
T: Soapy,
for<'a> T::Ref<'a>: Ord,
{
fn cmp(&self, other: &Self) -> Ordering {
match self
.iter()
.zip(other.iter())
.try_fold(Ordering::Equal, |_, (a, b)| match a.cmp(&b) {
ord @ (Ordering::Greater | Ordering::Less) => ControlFlow::Break(ord),
Ordering::Equal => ControlFlow::Continue(self.len().cmp(&other.len())),
}) {
ControlFlow::Continue(ord) | ControlFlow::Break(ord) => ord,
}
}
}
impl<T> Hash for Slice<T>
where
T: Soapy,
for<'a> T::Ref<'a>: Hash,
{
fn hash<H: Hasher>(&self, state: &mut H) {
self.len().hash(state);
for item in self {
item.hash(state);
}
}
}
impl<T> Deref for Slice<T>
where
T: Soapy,
{
type Target = T::Deref;
fn deref(&self) -> &Self::Target {
<T::Deref as SoaDeref>::from_slice(self)
}
}
impl<T> DerefMut for Slice<T>
where
T: Soapy,
{
fn deref_mut(&mut self) -> &mut Self::Target {
<T::Deref as SoaDeref>::from_slice_mut(self)
}
}
impl<T> AsRef<Slice<T>> for Slice<T>
where
T: Soapy,
{
fn as_ref(&self) -> &Self {
self
}
}
impl<T> AsMut<Slice<T>> for Slice<T>
where
T: Soapy,
{
fn as_mut(&mut self) -> &mut Self {
self
}
}