use core::fmt;
use devela::num::{NonMaxU16, NonMaxU32, NonMaxU8, NonMaxUsize};
#[rustfmt::skip]
macro_rules! index {
($name:ident, $B:literal, $b:literal, $t:ty, $nmt:ty) => { devela::paste! {
#[doc = "An " $b "-bit index that is known not to equal [`" $t "::MAX`]."]
#[doc = "It can index from `0` to [`" $t "::MAX`]`-1` elements."]
#[doc = "For example, `Option<NonMaxIndex" $b ">` is the same size as `u" $b "`."]
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
pub struct $name(pub(super) Option<$nmt>);
impl fmt::Debug for $name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "NonMaxIndex{} {{ {} }}", $b, self)
}
}
impl fmt::Display for $name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(index) = self.0 {
write!(f, "{index}")
} else {
write!(f, "_")
}
}
}
impl $name {
#[doc = "or `None` if the provided `index` equals [`" $t "::MAX`]."]
#[inline]
pub const fn new(index: $t) -> Option<Self> {
if let Some(i) = $nmt::new(index) {
Some(Self(Some(i)))
} else {
None
}
}
#[inline]
pub const fn none() -> Self {
Self(None)
}
}
impl $name {
#[inline]
pub const fn is_some(&self) -> bool {
self.0.is_some()
}
#[inline]
pub const fn is_none(&self) -> bool {
self.0.is_none()
}
#[inline]
pub const fn get(&self) -> Option<$t> {
if let Some(i) = self.0 {
Some(i.get())
} else {
None
}
}
#[inline]
pub fn as_usize(&self) -> usize {
core::cmp::min(self.as_primitive(), usize::MAX as $t) as usize
}
#[inline]
pub const fn as_primitive(&self) -> $t {
if let Some(i) = self.0 {
i.get()
} else {
$t::MAX
}
}
}
impl From<$t> for $name {
#[inline]
fn from(index: $t) -> Self {
if let Some(i) = $nmt::new(index) {
Self(Some(i))
} else {
Self(None)
}
}
}
impl From<Option<$t>> for $name {
#[inline]
fn from(index: Option<$t>) -> Self {
if let Some(i) = index {
Self($nmt::new(i))
} else {
Self(None)
}
}
}
impl From<$nmt> for $name {
#[inline]
fn from(index: $nmt) -> Self {
Self(Some(index))
}
}
}};
}
index![NonMaxIndex8, 1, 8, u8, NonMaxU8];
index![NonMaxIndex16, 2, 16, u16, NonMaxU16];
index![NonMaxIndex32, 4, 32, u32, NonMaxU32];
#[cfg(target_pointer_width = "8")]
#[cfg_attr(feature = "nightly", doc(cfg(target_pointer_width = "8")))]
index![NonMaxIndexUsize, 1, 8, usize, NonMaxUsize];
#[cfg(target_pointer_width = "16")]
#[cfg_attr(feature = "nightly", doc(cfg(target_pointer_width = "16")))]
index![NonMaxIndexUsize, 2, 16, usize, NonMaxUsize];
#[cfg(target_pointer_width = "32")]
#[cfg_attr(feature = "nightly", doc(cfg(target_pointer_width = "32")))]
index![NonMaxIndexUsize, 4, 32, usize, NonMaxUsize];
#[cfg(target_pointer_width = "64")]
#[cfg_attr(feature = "nightly", doc(cfg(target_pointer_width = "64")))]
index![NonMaxIndexUsize, 8, 64, usize, NonMaxUsize];
#[cfg(test)]
mod tests {
use super::*;
use core::mem::size_of;
#[test]
fn index_size() {
assert_eq!(1, size_of::<NonMaxIndex8>());
assert_eq!(2, size_of::<NonMaxIndex16>());
assert_eq!(4, size_of::<NonMaxIndex32>());
}
}