#[macro_export(local_inner_macros)]
macro_rules! define_index_type {
(
$(#[$attrs:meta])*
$v:vis struct $type:ident ($inner_v:vis $raw:ident);
$($config:tt)*
) => {
define_index_type!{
@__inner
@attrs [$(#[$attrs])*]
@derives [#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]]
@decl [$v struct $type ($inner_v $raw)]
@max [(<$raw>::max_value() as usize)]
@no_check_max [false]
{ $($config)* }
}
};
(@__inner
@attrs [$(#[$attrs:meta])*]
@derives [$(#[$derive:meta])*]
@decl [$v:vis struct $type:ident ($inner_v:vis $raw:ident)]
@max [$max:expr]
@no_check_max [$_old_no_check_max:expr]
{ DISABLE_MAX_INDEX_CHECK_IF = $no_check_max:expr; $($tok:tt)* }
) => {
define_index_type!{
@__inner
@attrs [$(#[$attrs])*]
@derives [$(#[$derive])*]
@decl [$v struct $type ($inner_v $raw)]
@max [$max]
@no_check_max [$no_check_max]
{ $($tok)* }
}
};
(@__inner
@attrs [$(#[$attrs:meta])*]
@derives [$(#[$derive:meta])*]
@decl [$v:vis struct $type:ident ($inner_v:vis $raw:ident)]
@max [$max:expr]
@no_check_max [$cm:expr]
{ MAX_INDEX = $new_max:expr; $($tok:tt)* }
) => {
define_index_type!{
@__inner
@attrs [$(#[$attrs])*]
@derives [$(#[$derive])*]
@decl [$v struct $type ($inner_v $raw)]
@max [$new_max]
@no_check_max [$cm]
{ $($tok)* }
}
};
(@__inner
@attrs [$(#[$attrs:meta])*]
@derives [$(#[$derive:meta])*]
@decl [$v:vis struct $type:ident ($inner_v:vis $raw:ident)]
@max [$max:expr]
@no_check_max [$no_check_max:expr]
{ DEFAULT = $default_expr:expr; $($tok:tt)* }
) => {
define_index_type!{
@__inner
@attrs [$(#[$attrs])*]
@derives [$(#[$derive])*]
@decl [$v struct $type ($inner_v $raw)]
@max [$max]
@no_check_max [$no_check_max]
{ $($tok)* }
}
impl Default for $type {
#[inline]
fn default() -> Self {
$default_expr
}
}
};
(@__inner
@attrs [$(#[$attrs:meta])*]
@derives [$(#[$derive:meta])*]
@decl [$v:vis struct $type:ident ($inner_v:vis $raw:ident)]
@max [$max:expr]
@no_check_max [$no_check_max:expr]
{ NO_DERIVES = true; $($tok:tt)* }
) => {
define_index_type!{
@__inner
@attrs [$(#[$attrs])*]
@derives []
@decl [$v struct $type ($inner_v $raw)]
@max [$max]
@no_check_max [$no_check_max]
{ $($tok)* }
}
};
(@__inner
@attrs [$(#[$attrs:meta])*]
@derives [$(#[$derive:meta])*]
@decl [$v:vis struct $type:ident ($inner_v:vis $raw:ident)]
@max [$max:expr]
@no_check_max [$no_check_max:expr]
{ }
) => {
$(#[$derive])*
$(#[$attrs])*
$v struct $type($inner_v $raw);
impl $type {
$v const MAX_INDEX: usize = $max;
$v const CHECKS_MAX_INDEX: bool = !$no_check_max;
#[inline]
$v fn new(value: usize) -> Self {
Self::from_usize(value)
}
#[inline]
$v fn from_raw(value: $raw) -> Self {
Self::from_usize(value as usize)
}
#[inline]
$v const fn from_usize_unchecked(value: usize) -> Self {
Self(value as $raw)
}
#[inline]
$v const fn from_raw_unchecked(raw: $raw) -> Self {
Self(raw)
}
#[inline]
$v fn from_usize(value: usize) -> Self {
Self::maybe_check_index(value as usize);
Self(value as $raw)
}
#[inline]
$v fn index(self) -> usize {
self.as_usize()
}
#[inline]
$v fn raw(self) -> $raw {
self.0
}
#[inline]
$v fn maybe_check_index(v: usize) {
if Self::CHECKS_MAX_INDEX && (v > Self::MAX_INDEX) {
Self::max_check_fail(v);
}
}
#[inline]
$v fn as_usize(self) -> usize {
self.0 as usize
}
#[inline(never)]
#[cold]
fn max_check_fail(u: usize) {
core::panic!(
"index_vec index overfow: {} is outside the range [0, {})",
u,
Self::MAX_INDEX,
);
}
const _ENSURE_RAW_IS_UNSIGNED: [(); 0] = [(); <$raw>::min_value() as usize];
}
impl core::cmp::PartialOrd<usize> for $type {
#[inline]
fn partial_cmp(&self, other: &usize) -> Option<core::cmp::Ordering> {
self.index().partial_cmp(other)
}
}
impl core::cmp::PartialOrd<$type> for usize {
#[inline]
fn partial_cmp(&self, other: &$type) -> Option<core::cmp::Ordering> {
self.partial_cmp(&other.index())
}
}
impl PartialEq<usize> for $type {
#[inline]
fn eq(&self, other: &usize) -> bool {
self.index() == *other
}
}
impl PartialEq<$type> for usize {
#[inline]
fn eq(&self, other: &$type) -> bool {
*self == other.index()
}
}
impl core::ops::Add<usize> for $type {
type Output = Self;
#[inline]
fn add(self, other: usize) -> Self {
Self::new(self.index() + other)
}
}
impl core::ops::AddAssign<usize> for $type {
#[inline]
fn add_assign(&mut self, other: usize) {
*self = *self + other
}
}
impl core::ops::Sub<usize> for $type {
type Output = Self;
#[inline]
fn sub(self, other: usize) -> Self {
Self::new(self.index() - other)
}
}
impl core::ops::SubAssign<usize> for $type {
#[inline]
fn sub_assign(&mut self, other: usize) {
*self = *self - other;
}
}
impl core::ops::Rem<usize> for $type {
type Output = Self;
#[inline]
fn rem(self, other: usize) -> Self {
Self::new(self.index() % other)
}
}
impl core::ops::Add<$type> for usize {
type Output = $type;
#[inline]
fn add(self, other: $type) -> $type {
$type::new(self + other.index())
}
}
impl core::ops::Sub<$type> for usize {
type Output = $type;
#[inline]
fn sub(self, other: $type) -> $type {
$type::new(self - other.index())
}
}
impl $crate::Idx for $type {
#[inline]
fn from_usize(value: usize) -> Self {
Self::from(value)
}
#[inline]
fn index(self) -> usize {
usize::from(self)
}
}
impl From<$type> for usize {
#[inline]
fn from(v: $type) -> usize {
v.as_usize()
}
}
impl From<usize> for $type {
#[inline]
fn from(value: usize) -> Self {
$type::from_usize(value)
}
}
define_index_type! { @__impl_from_rep_unless_usize $type, $raw }
};
(@__impl_from_rep_unless_usize $type:ident, usize) => {};
(@__impl_from_rep_unless_usize $type:ident, $raw:ident) => {
impl From<$type> for $raw {
#[inline]
fn from(v: $type) -> $raw {
v.raw()
}
}
impl From<$raw> for $type {
#[inline]
fn from(value: $raw) -> Self {
Self::from_raw(value)
}
}
};
}
#[macro_export]
macro_rules! index_vec {
($($tokens:tt)*) => {
$crate::IndexVec::from_vec(vec![$($tokens)*])
}
}