use std::convert::TryFrom;
use crate::trusted_len::TrustedLen;
use super::NativeType;
pub trait Index:
NativeType
+ std::ops::AddAssign
+ std::ops::Sub<Output = Self>
+ num_traits::One
+ num_traits::Num
+ num_traits::CheckedAdd
+ PartialOrd
+ Ord
{
fn to_usize(&self) -> usize;
fn from_usize(index: usize) -> Option<Self>;
fn from_as_usize(index: usize) -> Self;
fn range(start: usize, end: usize) -> Option<IndexRange<Self>> {
let start = Self::from_usize(start);
let end = Self::from_usize(end);
match (start, end) {
(Some(start), Some(end)) => Some(IndexRange::new(start, end)),
_ => None,
}
}
}
macro_rules! index {
($t:ty) => {
impl Index for $t {
#[inline]
fn to_usize(&self) -> usize {
*self as usize
}
#[inline]
fn from_usize(value: usize) -> Option<Self> {
Self::try_from(value).ok()
}
#[inline]
fn from_as_usize(value: usize) -> Self {
value as $t
}
}
};
}
index!(i8);
index!(i16);
index!(i32);
index!(i64);
index!(u8);
index!(u16);
index!(u32);
index!(u64);
pub struct IndexRange<I: Index> {
start: I,
end: I,
}
impl<I: Index> IndexRange<I> {
pub fn new(start: I, end: I) -> Self {
assert!(end >= start);
Self { start, end }
}
}
impl<I: Index> Iterator for IndexRange<I> {
type Item = I;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.start == self.end {
return None;
}
let old = self.start;
self.start += I::one();
Some(old)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = (self.end - self.start).to_usize();
(len, Some(len))
}
}
unsafe impl<I: Index> TrustedLen for IndexRange<I> {}