use std::fmt::{Display, Debug, Formatter, Result as DResult};
use std::marker::PhantomData;
use std::hash::Hash;
use std::ops::{Index, IndexMut};
#[cfg(feature = "serde")]
pub(crate) mod serde_support;
#[cfg(feature = "serde")]
pub(crate) use serde_support::*;
pub struct IndexTo<Data, In, Idx=usize>
where
Data : ?Sized,
In : ?Sized
{
index : Idx,
index_data : PhantomData<Data>,
index_owner : PhantomData<In>,
}
impl<Data, Inside, Idx> IndexTo<Data, Inside, Idx>
where
Data : ?Sized,
Inside : ?Sized
{
#[inline]
pub const fn from_index(index : Idx) -> Self { Self { index, index_data: PhantomData, index_owner : PhantomData }}
#[inline]
pub const fn index(self) -> Idx where Idx : Copy { self.index }
#[inline]
pub fn set_index(&mut self, index : Idx) -> &mut Self { self.index = index; self }
#[inline]
pub fn with_index(mut self, index : Idx) -> Self { self.set_index(index); self }
}
impl<Data : ?Sized, In : ?Sized, Idx> Hash for IndexTo<Data, In, Idx> where Idx : Hash { #[inline] fn hash<H: std::hash::Hasher>(&self, state: &mut H) { self.index.hash(state); } }
impl<Data : ?Sized, In : ?Sized, Idx> Clone for IndexTo<Data, In, Idx> where Idx : Clone { #[inline] fn clone(&self) -> Self { Self::from_index(self.index.clone()) } }
impl<Data : ?Sized, In : ?Sized, Idx> Copy for IndexTo<Data, In, Idx> where Idx : Copy {}
impl<Data : ?Sized, In : ?Sized, Idx> Debug for IndexTo<Data, In, Idx> where Idx : Debug { fn fmt(&self, f: &mut Formatter<'_>) -> DResult { write!(f, "IndexTo<{}>({:?})", std::any::type_name::<In>(), self.index) } }
impl<Data : ?Sized, In : ?Sized, Idx> Display for IndexTo<Data, In, Idx> where Idx : Display { fn fmt(&self, f: &mut Formatter<'_>) -> DResult { write!(f, "IndexTo<{}>({})", std::any::type_name::<In>(), self.index) } }
impl<Data : ?Sized, In : ?Sized, Idx> Eq for IndexTo<Data, In, Idx> where Idx : Eq {}
impl<Data : ?Sized, In : ?Sized, Idx> PartialEq for IndexTo<Data, In, Idx> where Idx : PartialEq { #[inline] fn eq(&self, other: &Self) -> bool { self.index == other.index } }
impl<Data : ?Sized, In : ?Sized, Idx> Ord for IndexTo<Data, In, Idx> where Idx : Ord { #[inline] fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.index.cmp(&other.index) } }
impl<Data : ?Sized, In : ?Sized, Idx> PartialOrd for IndexTo<Data, In, Idx> where Idx : PartialOrd { #[inline] fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { self.index.partial_cmp(&other.index) } }
impl<D> Index<IndexTo<D, Vec<D>>> for Vec<D>
{
type Output=D;
#[inline]
fn index(&self, index: IndexTo<D, Vec<D>>) -> &Self::Output { self.index(index.index) }
}
impl<T> IndexMut<IndexTo<T, Vec<T>>> for Vec<T>
{
#[inline]
fn index_mut(&mut self, index: IndexTo<T, Vec<T>>) -> &mut Self::Output { self.index_mut(index.index) }
}
impl<T> Index<IndexTo<T, [T]>> for [T]
{
type Output=T;
#[inline]
fn index(&self, index: IndexTo<T, [T]>) -> &Self::Output { self.get(index.index).unwrap() }
}
impl<T> IndexMut<IndexTo<T, [T]>> for [T]
{
#[inline]
fn index_mut(&mut self, index: IndexTo<T, [T]>) -> &mut Self::Output { self.get_mut(index.index).unwrap() }
}
impl Index<IndexTo<u8, str>> for str
{
type Output=u8;
#[inline]
fn index(&self, index: IndexTo<u8, str>) -> &Self::Output { self.as_bytes().index(index.index) }
}
pub trait HaveTypedIndex<Idx=usize> where Idx : ?Sized
{
type IndexTo;
type Output : ?Sized;
fn index_to(&self, index : Idx) -> Self::IndexTo;
}
impl<Idx, T> HaveTypedIndex<Idx> for T where T : Index<Idx> + ?Sized
{
type IndexTo = IndexTo<Self::Output, Self, Idx>;
type Output = T::Output;
fn index_to(&self, index : Idx) -> Self::IndexTo {
IndexTo::from_index(index)
}
}
pub trait TypedIndex<Idx:?Sized> : HaveTypedIndex<Idx> + Index<Self::IndexTo>
{
fn typed_index(&self, index : Self::IndexTo) -> &<Self as Index<Self::IndexTo>>::Output { self.index(index) }
}
impl<T, Idx:?Sized> TypedIndex<Idx> for T where T : HaveTypedIndex<Idx> + Index<T::IndexTo> { }
pub trait TypedIndexMut<Idx:?Sized> : HaveTypedIndex<Idx> + IndexMut<Self::IndexTo>
{
fn typed_index_mut(&mut self, index : Self::IndexTo) -> &mut <Self as Index<Self::IndexTo>>::Output { self.index_mut(index) }
}
impl<T, Idx:?Sized> TypedIndexMut<Idx> for T where T : HaveTypedIndex<Idx> + IndexMut<T::IndexTo> { }
#[cfg(test)]
mod tests {
#[test]
fn test_int_and_bool()
{
use crate::*;
use std::ops::Index;
struct IntAndBool
{
integers : Vec<i32>,
booleans : Vec<bool>,
}
type IntegerIdx = <Vec<i32> as HaveTypedIndex>::IndexTo;
type BooleanIdx = <Vec<bool> as HaveTypedIndex>::IndexTo;
impl Index<IntegerIdx> for IntAndBool
{
type Output=i32;
fn index(&self, index: IntegerIdx) -> &Self::Output { &self.integers[index] }
}
impl Index<BooleanIdx> for IntAndBool
{
type Output=bool;
fn index(&self, index: BooleanIdx) -> &Self::Output { &self.booleans[index] }
}
let mut int_and_bool = IntAndBool { integers : vec![10, 20, 30], booleans : vec![true, false] };
let int_idx = int_and_bool.integers.index_to(1); let bool_idx = int_and_bool.booleans.index_to(0);
assert_eq!(int_and_bool[int_idx ], 20);
assert_eq!(int_and_bool[bool_idx], true);
let int_idx_2 = IntegerIdx::from_index(1); let bool_idx_2 = BooleanIdx::from_index(0);
assert_eq!(int_and_bool[int_idx_2 ], 20);
assert_eq!(int_and_bool[bool_idx_2], true);
assert_eq!(int_and_bool.integers.typed_index(IntegerIdx::from_index(1)), &20);
assert_eq!(int_and_bool.booleans.typed_index(BooleanIdx::from_index(0)), &true);
assert_eq!(int_and_bool.integers.typed_index_mut(IntegerIdx::from_index(1)), &mut 20);
assert_eq!(int_and_bool.booleans.typed_index_mut(BooleanIdx::from_index(0)), &mut true);
}
}