#![cfg_attr(not(test), deny(warnings, clippy::all, clippy::pedantic, clippy::cargo, missing_docs))]
#![deny(unsafe_code)]
#![cfg_attr(not(any(test, feature = "std")), no_std)]
#![allow(clippy::module_name_repetitions, clippy::inline_always)]
mod map;
#[cfg(feature = "serde")]
mod serde;
mod set;
mod three_tuple;
mod two_tuple;
#[cfg(feature = "array_map_derive")]
pub use array_map_derive::Indexable;
use core::convert::TryInto;
pub use map::*;
pub use set::*;
pub use three_tuple::*;
pub use two_tuple::*;
#[allow(unsafe_code)]
pub unsafe trait Indexable {
const SIZE: usize;
const SET_SIZE: usize;
type Iter: Iterator<Item = Self>;
fn index(self) -> usize;
fn iter() -> Self::Iter;
}
#[inline(always)]
fn assert_indexable_safe<I: Indexable>() {
#[cfg(debug_assertions)]
{
for (i, k) in I::iter().enumerate().take(I::SIZE + 1) {
let index = k.index();
assert_eq!(index, i);
assert!(index < I::SIZE);
}
}
}
#[allow(unsafe_code)]
pub unsafe trait ReverseIndexable: Indexable {
fn from_index(u: usize) -> Self;
}
#[allow(unsafe_code)]
unsafe impl<T: Indexable> Indexable for Option<T> {
const SIZE: usize = T::SIZE + 1;
const SET_SIZE: usize = set_size(T::SIZE + 1);
#[allow(clippy::type_complexity)]
type Iter = core::iter::Chain<core::iter::Map<T::Iter, fn(T) -> Option<T>>, core::iter::Once<Option<T>>>;
fn index(self) -> usize {
match self {
Some(x) => x.index(),
None => T::SIZE,
}
}
fn iter() -> Self::Iter {
T::iter().map(Some as fn(T) -> Option<T>).chain(core::iter::once(None))
}
}
#[allow(unsafe_code)]
unsafe impl<T: ReverseIndexable> ReverseIndexable for Option<T> {
fn from_index(u: usize) -> Self {
if u == T::SIZE {
None
} else {
Some(T::from_index(u))
}
}
}
#[allow(unsafe_code)]
unsafe impl Indexable for bool {
const SIZE: usize = 2;
const SET_SIZE: usize = set_size(2);
type Iter = core::array::IntoIter<bool, 2>;
#[inline(always)]
fn index(self) -> usize {
usize::from(self)
}
#[inline(always)]
fn iter() -> Self::Iter {
[false, true].into_iter()
}
}
#[allow(unsafe_code)]
unsafe impl ReverseIndexable for bool {
fn from_index(u: usize) -> Self {
[false, true][u]
}
}
#[allow(unsafe_code)]
unsafe impl Indexable for u8 {
const SIZE: usize = u8::MAX as usize + 1;
const SET_SIZE: usize = set_size(u8::MAX as usize + 1);
type Iter = core::ops::RangeInclusive<Self>;
#[inline(always)]
fn index(self) -> usize {
self as usize
}
#[inline(always)]
fn iter() -> Self::Iter {
Self::MIN..=Self::MAX
}
}
#[allow(unsafe_code)]
unsafe impl ReverseIndexable for u8 {
fn from_index(u: usize) -> Self {
u.try_into().unwrap_or_else(|_| panic!("Invalid u8 index provided {}", u))
}
}
#[allow(unsafe_code)]
unsafe impl Indexable for u16 {
const SIZE: usize = u16::MAX as usize + 1;
const SET_SIZE: usize = set_size(u16::MAX as usize + 1);
type Iter = core::ops::RangeInclusive<Self>;
#[inline(always)]
fn index(self) -> usize {
self as usize
}
#[inline(always)]
fn iter() -> Self::Iter {
Self::MIN..=Self::MAX
}
}
#[allow(unsafe_code)]
unsafe impl ReverseIndexable for u16 {
fn from_index(u: usize) -> Self {
u.try_into().unwrap_or_else(|_| panic!("Invalid u16 index provided {}", u))
}
}
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
#[repr(transparent)]
#[must_use]
pub struct IndexU8<const N: u8>(u8);
impl<const N: u8> IndexU8<N> {
#[inline]
#[must_use]
pub const fn new(u: u8) -> Option<Self> {
if u < N {
Some(Self(u))
} else {
None
}
}
#[inline(always)]
#[must_use]
pub const fn get(self) -> u8 {
self.0
}
}
#[allow(unsafe_code)]
unsafe impl<const N: u8> Indexable for IndexU8<N> {
const SIZE: usize = N as usize;
const SET_SIZE: usize = set_size(N as usize);
type Iter = core::iter::Map<core::ops::Range<u8>, fn(u8) -> Self>;
fn index(self) -> usize {
self.0 as usize
}
fn iter() -> Self::Iter {
(0..N).map(Self)
}
}
#[allow(unsafe_code)]
unsafe impl<const N: u8> ReverseIndexable for IndexU8<N> {
fn from_index(u: usize) -> Self {
let u: u8 = u.try_into().unwrap_or_else(|_| panic!("Invalid IndexU8 index provided {}", u));
Self::new(u).unwrap_or_else(|| panic!("Invalid IndexU8 index provided {}", u))
}
}
impl<const N: u8> core::fmt::Display for IndexU8<N> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.0.fmt(f)
}
}
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
#[repr(transparent)]
#[must_use]
pub struct IndexU16<const N: u16>(u16);
impl<const N: u16> IndexU16<N> {
#[inline]
#[must_use]
pub const fn new(u: u16) -> Option<Self> {
if u < N {
Some(Self(u))
} else {
None
}
}
#[inline(always)]
#[must_use]
pub const fn get(self) -> u16 {
self.0
}
}
#[allow(unsafe_code)]
unsafe impl<const N: u16> Indexable for IndexU16<N> {
const SIZE: usize = N as usize;
const SET_SIZE: usize = set_size(N as usize);
type Iter = core::iter::Map<core::ops::Range<u16>, fn(u16) -> Self>;
fn index(self) -> usize {
self.0 as usize
}
fn iter() -> Self::Iter {
(0..N).map(Self)
}
}
#[allow(unsafe_code)]
unsafe impl<const N: u16> ReverseIndexable for IndexU16<N> {
fn from_index(u: usize) -> Self {
let u: u16 = u.try_into().unwrap_or_else(|_| panic!("Invalid IndexU8 index provided {}", u));
Self::new(u).unwrap_or_else(|| panic!("Invalid IndexU8 index provided {}", u))
}
}
impl<const N: u16> core::fmt::Display for IndexU16<N> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.0.fmt(f)
}
}
#[cfg(test)]
mod test {
#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Debug, ::serde::Serialize, ::serde::Deserialize)]
#[serde(transparent)]
pub struct Lowercase(pub(crate) char);
#[allow(unsafe_code)]
unsafe impl crate::Indexable for Lowercase {
const SIZE: usize = 26;
const SET_SIZE: usize = crate::set_size(26);
type Iter = core::iter::Map<core::ops::RangeInclusive<char>, fn(char) -> Lowercase>;
fn index(self) -> usize {
self.0 as usize - 'a' as usize
}
fn iter() -> Self::Iter {
('a'..='z').map(Lowercase)
}
}
}