use std::fmt;
use std::ops::{Add, AddAssign, Div, Mul, Rem, Sub};
mod checked;
pub use self::checked::*;
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(transparent)]
pub struct Index(usize);
unsafe impl bytemuck::Pod for Index {}
unsafe impl bytemuck::Zeroable for Index {}
impl Index {
pub const INVALID: Index = Index(std::usize::MAX);
#[inline]
pub fn new(i: usize) -> Index {
debug_assert!(Index::fits(i));
Index(i)
}
#[inline]
pub fn into_option(self) -> Option<usize> {
self.into()
}
#[inline]
pub fn map_inner<F: FnOnce(usize) -> usize>(self, f: F) -> Index {
Index::new(f(self.0))
}
#[inline]
pub fn and_then<F: FnOnce(usize) -> Index>(self, f: F) -> Index {
if self.is_valid() {
f(self.0 as usize)
} else {
self
}
}
#[inline]
pub fn apply<F: FnOnce(&mut usize)>(&mut self, f: F) {
if self.is_valid() {
f(&mut self.0);
}
}
#[inline]
pub fn if_valid<F: FnOnce(usize)>(self, f: F) {
if self.is_valid() {
f(self.0);
}
}
#[inline]
pub fn into_inner(self) -> usize {
self.0
}
#[inline]
fn fits(i: usize) -> bool {
i != std::usize::MAX
}
}
macro_rules! impl_from_unsigned {
($u:ty) => {
impl From<$u> for Index {
#[inline]
fn from(i: $u) -> Self {
Index::new(i as usize)
}
}
};
}
impl_from_unsigned!(usize);
impl_from_unsigned!(u64);
impl_from_unsigned!(u32);
impl_from_unsigned!(u16);
impl_from_unsigned!(u8);
macro_rules! impl_from_signed {
($i:ty) => {
impl From<$i> for Index {
#[inline]
fn from(i: $i) -> Self {
if i < 0 {
Index::invalid()
} else {
Index(i as usize)
}
}
}
};
}
impl_from_signed!(isize);
impl_from_signed!(i64);
impl_from_signed!(i32);
impl_from_signed!(i16);
impl_from_signed!(i8);
impl From<Index> for Option<usize> {
#[inline]
fn from(val: Index) -> Self {
if val.is_valid() {
Some(val.0 as usize)
} else {
None
}
}
}
impl From<Option<usize>> for Index {
#[inline]
fn from(i: Option<usize>) -> Index {
match i {
Some(i) => Index::new(i),
None => Index::INVALID,
}
}
}
impl IntoIterator for Index {
type Item = usize;
type IntoIter = std::option::IntoIter<usize>;
fn into_iter(self) -> Self::IntoIter {
self.into_option().into_iter()
}
}
impl Add<usize> for Index {
type Output = Index;
#[inline]
fn add(self, rhs: usize) -> Index {
self.map(|x| x + rhs)
}
}
impl AddAssign<usize> for Index {
#[inline]
fn add_assign(&mut self, rhs: usize) {
self.apply(|x| *x += rhs)
}
}
impl Add<Index> for usize {
type Output = Index;
#[inline]
fn add(self, rhs: Index) -> Index {
rhs + self
}
}
impl Add for Index {
type Output = Index;
#[inline]
fn add(self, rhs: Index) -> Index {
self.and_then(|x| rhs.map(|y| x + y))
}
}
impl Sub<usize> for Index {
type Output = Index;
#[inline]
fn sub(self, rhs: usize) -> Index {
self.map(|x| x - rhs)
}
}
impl Sub<Index> for usize {
type Output = Index;
#[inline]
fn sub(self, rhs: Index) -> Index {
rhs.map(|x| self - x)
}
}
impl Sub for Index {
type Output = Index;
#[inline]
fn sub(self, rhs: Index) -> Index {
self.and_then(|x| rhs.map(|y| x - y))
}
}
impl Mul<usize> for Index {
type Output = Index;
#[inline]
fn mul(self, rhs: usize) -> Index {
self.map(|x| x * rhs)
}
}
impl Mul<Index> for usize {
type Output = Index;
#[inline]
fn mul(self, rhs: Index) -> Index {
rhs * self
}
}
impl Div<usize> for Index {
type Output = Index;
#[inline]
fn div(self, rhs: usize) -> Index {
if rhs != 0 {
self.map(|x| x / rhs)
} else {
Index::invalid()
}
}
}
impl Rem<usize> for Index {
type Output = Index;
#[inline]
fn rem(self, rhs: usize) -> Index {
if rhs != 0 {
self.map(|x| x % rhs)
} else {
Index::invalid()
}
}
}
impl PartialEq<usize> for Index {
#[inline]
fn eq(&self, other: &usize) -> bool {
self.map_or(false, |x| x == *other)
}
}
impl PartialOrd<usize> for Index {
#[inline]
fn partial_cmp(&self, other: &usize) -> Option<std::cmp::Ordering> {
self.map_or(None, |x| x.partial_cmp(other))
}
}
impl Default for Index {
fn default() -> Self {
Self::invalid()
}
}
impl fmt::Display for Index {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
macro_rules! impl_index_for {
(__impl, $value_type:ty, $idx_type:ty) => {
impl ::std::ops::Index<$idx_type> for Vec<$value_type> {
type Output = $value_type;
fn index(&self, index: $idx_type) -> &$value_type {
&self[usize::from(index)]
}
}
impl ::std::ops::IndexMut<$idx_type> for Vec<$value_type> {
fn index_mut(&mut self, index: $idx_type) -> &mut $value_type {
&mut self[usize::from(index)]
}
}
};
(Vec<$value_type:ty> by $($idx_type:ty),+) => {
$(impl_index_for!(__impl, $value_type, $idx_type);)*
};
(__impl_newtype, $collection_type:ident (Vec<$value_type:ty>) by $idx_type:ty) => {
impl ::std::ops::Index<$idx_type> for $collection_type {
type Output = $value_type;
fn index(&self, index: $idx_type) -> &$value_type {
&self.0[usize::from(index)]
}
}
impl ::std::ops::IndexMut<$idx_type> for $collection_type {
fn index_mut(&mut self, index: $idx_type) -> &mut $value_type {
&mut self.0[usize::from(index)]
}
}
};
(__impl_newtype, $collection_type:ident (Vec<$value_type:ty>) by $idx_type:ty
where $t:ident: $($traits:tt)*) => {
impl<$t: $($traits)*> ::std::ops::Index<$idx_type> for $collection_type<$t> {
type Output = $value_type;
fn index(&self, index: $idx_type) -> &$value_type {
&self.0[usize::from(index)]
}
}
impl<$t: $($traits)*> ::std::ops::IndexMut<$idx_type> for $collection_type<$t> {
fn index_mut(&mut self, index: $idx_type) -> &mut $value_type {
&mut self.0[usize::from(index)]
}
}
};
($collection_type:ident (Vec<$value_type:ty>) by $($idx_type:ty),+
where $t:ident: $($traits:tt)*) => {
#[derive(Clone, Debug, PartialEq, NewCollectionType)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct $collection_type<$t: $($traits)*>(Vec<$value_type>);
$(impl_index_for!(__impl_newtype, $collection_type(Vec<$value_type>) by $idx_type
where $t: $traits);)*
};
($collection_type:ident (Vec<$value_type:ty>) by $($idx_type:ty),+) => {
#[derive(Clone, Debug, PartialEq, NewCollectionType)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct $collection_type(Vec<$value_type>);
$(impl_index_for!(__impl_newtype, $collection_type(Vec<$value_type>) by $idx_type);)*
};
($collection_type:ident ([$value_type:ty; $n:expr]) by $($idx_type:ty),+) => {
#[derive(Clone, Debug, PartialEq, NewCollectionType)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct $collection_type([$value_type;$n]);
$(impl_index_for!(__impl_newtype, $collection_type(Vec<$value_type>) by $idx_type);)*
};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn index_test() {
let i = Index::new(2);
let j = Index::new(4);
let k = Index::invalid();
assert_eq!(i + j, Index::new(6));
assert_eq!(j - i, Index::new(2));
assert_eq!(j * 3, Index::new(12));
assert_eq!(j % 3, Index::new(1));
assert_eq!(j / 3, Index::new(1));
assert_eq!(i - k, Index::invalid());
assert_eq!(i + k, Index::invalid());
assert_eq!(k * 2, Index::invalid());
assert_eq!(k / 2, Index::invalid());
assert_eq!(k % 2, Index::invalid());
}
}