#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
use std::cmp;
use std::convert;
use std::convert::TryFrom;
use std::error;
use std::fmt;
use std::marker::PhantomData;
use std::num;
use std::ops;
use std::str;
pub struct Andex<M, const SIZE: usize>(PhantomData<M>, usize);
impl<M, const SIZE: usize> Andex<M, SIZE> {
pub const SIZE: usize = SIZE;
pub const FIRST: Andex<M, SIZE> = Andex(PhantomData, 0);
pub const LAST: Andex<M, SIZE> = Andex(PhantomData, SIZE - 1);
#[inline]
pub const fn new<const N: usize>() -> Self {
const ASSERT: [(); 1] = [(); 1];
let _ = ASSERT[(N >= SIZE) as usize];
Andex(PhantomData, N)
}
#[inline]
pub const fn pair(self) -> Self {
Andex(PhantomData, SIZE - self.1 - 1)
}
#[inline]
pub fn next(self) -> Option<Self> {
let i = usize::from(self);
if i < SIZE - 1 {
Some(Andex(PhantomData, i + 1))
} else {
None
}
}
#[inline]
fn index_arr<'a, T>(&self, arr: &'a [T]) -> &'a T {
unsafe { arr.get_unchecked(usize::from(self)) }
}
#[inline]
fn index_arr_mut<'a, T>(&self, arr: &'a mut [T]) -> &'a mut T {
unsafe { arr.get_unchecked_mut(usize::from(self)) }
}
pub fn iter() -> AndexIterator<M, SIZE> {
AndexIterator::<M, SIZE>::default()
}
}
impl<M, const SIZE: usize> Clone for Andex<M, SIZE> {
fn clone(&self) -> Self {
*self
}
}
impl<M, const SIZE: usize> Copy for Andex<M, SIZE> {}
impl<M, const SIZE: usize> Default for Andex<M, SIZE> {
fn default() -> Self {
Andex(PhantomData, 0)
}
}
impl<M, const SIZE: usize> PartialEq for Andex<M, SIZE> {
fn eq(&self, other: &Self) -> bool {
self.1 == other.1
}
}
impl<M, const SIZE: usize> Eq for Andex<M, SIZE> {}
impl<M, const SIZE: usize> PartialOrd for Andex<M, SIZE> {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<M, const SIZE: usize> Ord for Andex<M, SIZE> {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.1.cmp(&other.1)
}
}
impl<M, const SIZE: usize> From<Andex<M, SIZE>> for usize {
fn from(andex: Andex<M, SIZE>) -> Self {
andex.1
}
}
impl<M, const SIZE: usize> From<&Andex<M, SIZE>> for usize {
fn from(andex: &Andex<M, SIZE>) -> Self {
andex.1
}
}
impl<M, const SIZE: usize> convert::TryFrom<usize> for Andex<M, SIZE> {
type Error = Error;
fn try_from(value: usize) -> Result<Self, Self::Error> {
if value < SIZE {
Ok(Andex(PhantomData, value))
} else {
Err(Error::OutOfBounds { value, size: SIZE })
}
}
}
impl<M, const SIZE: usize> fmt::Debug for Andex<M, SIZE> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", usize::from(self))
}
}
impl<M, const SIZE: usize> fmt::Display for Andex<M, SIZE> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", usize::from(self))
}
}
impl<M, const SIZE: usize> str::FromStr for Andex<M, SIZE> {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::try_from(usize::from_str(s)?)
}
}
pub struct AndexIterator<M, const SIZE: usize>(Option<Andex<M, SIZE>>);
impl<M, const SIZE: usize> fmt::Debug for AndexIterator<M, SIZE> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "AndexIterator({:?})", self.0)
}
}
impl<M, const SIZE: usize> Default for AndexIterator<M, SIZE> {
fn default() -> Self {
AndexIterator(Some(Andex::<M, SIZE>::default()))
}
}
impl<M, const SIZE: usize> Iterator for AndexIterator<M, SIZE> {
type Item = Andex<M, SIZE>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(i) = self.0.take() {
self.0 = i.next();
Some(i)
} else {
None
}
}
}
#[derive(Debug)]
pub struct AndexableArray<A, Item, const SIZE: usize>(PhantomData<A>, [Item; SIZE]);
#[macro_export]
macro_rules! andex_array {
($andex: ty, $item: ty) => {
$crate::AndexableArray<$andex, $item, { <$andex>::SIZE }>
};
}
impl<A, Item, const SIZE: usize> AndexableArray<A, Item, SIZE> {
pub fn iter(&self) -> impl Iterator<Item = &Item> {
self.1.iter()
}
}
impl<A, Item: Copy, const SIZE: usize> Clone for AndexableArray<A, Item, SIZE> {
fn clone(&self) -> Self {
AndexableArray::<A, Item, SIZE>::from(self.1)
}
}
impl<A, Item: Copy, const SIZE: usize> Copy for AndexableArray<A, Item, SIZE> {}
impl<A, Item: Default + Copy, const SIZE: usize> Default for AndexableArray<A, Item, SIZE> {
fn default() -> Self {
AndexableArray(Default::default(), [Default::default(); SIZE])
}
}
impl<A, Item, const SIZE: usize> ops::Index<Andex<A, SIZE>>
for AndexableArray<Andex<A, SIZE>, Item, SIZE>
{
type Output = Item;
fn index(&self, index: Andex<A, SIZE>) -> &Self::Output {
index.index_arr(&self.1)
}
}
impl<A, Item, const SIZE: usize> ops::IndexMut<Andex<A, SIZE>>
for AndexableArray<Andex<A, SIZE>, Item, SIZE>
{
fn index_mut(&mut self, index: Andex<A, SIZE>) -> &mut Item {
index.index_arr_mut(&mut self.1)
}
}
impl<A, Item, const SIZE: usize> ops::Index<&Andex<A, SIZE>>
for AndexableArray<Andex<A, SIZE>, Item, SIZE>
{
type Output = Item;
fn index(&self, index: &Andex<A, SIZE>) -> &Self::Output {
index.index_arr(&self.1)
}
}
impl<A, Item, const SIZE: usize> ops::IndexMut<&Andex<A, SIZE>>
for AndexableArray<Andex<A, SIZE>, Item, SIZE>
{
fn index_mut(&mut self, index: &Andex<A, SIZE>) -> &mut Item {
index.index_arr_mut(&mut self.1)
}
}
impl<A, Item, const SIZE: usize> convert::AsRef<[Item; SIZE]> for AndexableArray<A, Item, SIZE> {
fn as_ref(&self) -> &[Item; SIZE] {
&self.1
}
}
impl<A, Item, const SIZE: usize> convert::AsMut<[Item; SIZE]> for AndexableArray<A, Item, SIZE> {
fn as_mut(&mut self) -> &mut [Item; SIZE] {
&mut self.1
}
}
impl<A, Item, const SIZE: usize> From<[Item; SIZE]> for AndexableArray<A, Item, SIZE> {
fn from(array: [Item; SIZE]) -> Self {
Self(PhantomData, array)
}
}
impl<A, Item, const SIZE: usize> From<&[Item; SIZE]> for AndexableArray<A, Item, SIZE>
where
Item: Copy,
{
fn from(array: &[Item; SIZE]) -> Self {
Self(PhantomData, *array)
}
}
impl<A, Item, const SIZE: usize> From<AndexableArray<A, Item, SIZE>> for [Item; SIZE]
where
Item: Copy,
{
fn from(andexable_array: AndexableArray<A, Item, SIZE>) -> [Item; SIZE] {
andexable_array.1
}
}
impl<A, Item, const SIZE: usize> From<&AndexableArray<A, Item, SIZE>> for [Item; SIZE]
where
Item: Copy,
{
fn from(andexable_array: &AndexableArray<A, Item, SIZE>) -> [Item; SIZE] {
andexable_array.1
}
}
impl<'a, A, Item, const SIZE: usize> IntoIterator for &'a AndexableArray<A, Item, SIZE> {
type Item = &'a Item;
type IntoIter = std::slice::Iter<'a, Item>;
fn into_iter(self) -> Self::IntoIter {
self.1.iter()
}
}
impl<'a, A, Item, const SIZE: usize> IntoIterator for &'a mut AndexableArray<A, Item, SIZE> {
type Item = &'a mut Item;
type IntoIter = std::slice::IterMut<'a, Item>;
fn into_iter(self) -> Self::IntoIter {
self.1.iter_mut()
}
}
impl<A, Item, const SIZE: usize> core::iter::FromIterator<Item> for AndexableArray<A, Item, SIZE> {
fn from_iter<I: core::iter::IntoIterator<Item = Item>>(intoiter: I) -> Self {
let mut andexable = AndexableArray::<A, Item, SIZE>(
PhantomData,
#[allow(clippy::uninit_assumed_init)]
unsafe {
std::mem::MaybeUninit::uninit().assume_init()
},
);
let mut iter = intoiter.into_iter();
for item in &mut andexable {
if let Some(fromiter) = iter.next() {
*item = fromiter;
} else {
panic!("iterator too short for andexable type");
}
}
if iter.next().is_some() {
panic!("iterator too long for andexable type");
}
andexable
}
}
impl<'a, A, Item: 'a + Copy, const SIZE: usize> core::iter::FromIterator<&'a Item>
for AndexableArray<A, Item, SIZE>
{
fn from_iter<I: core::iter::IntoIterator<Item = &'a Item>>(intoiter: I) -> Self {
let mut andexable = AndexableArray::<A, Item, SIZE>(
PhantomData,
#[allow(clippy::uninit_assumed_init)]
unsafe {
std::mem::MaybeUninit::uninit().assume_init()
},
);
let mut iter = intoiter.into_iter();
for item in &mut andexable {
if let Some(&fromiter) = iter.next() {
*item = fromiter;
} else {
panic!("iterator too short for andexable type");
}
}
if iter.next().is_some() {
panic!("iterator too long for andexable type");
}
andexable
}
}
#[derive(Debug, Clone)]
pub enum Error {
OutOfBounds {
value: usize,
size: usize,
},
ParseIntError(num::ParseIntError),
}
impl error::Error for Error {}
impl From<num::ParseIntError> for Error {
fn from(err: num::ParseIntError) -> Self {
Error::ParseIntError(err)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::OutOfBounds {
ref value,
ref size,
} => write!(
f,
"value {} is out-of-bounds for index with size {}",
value, size
),
Error::ParseIntError(err) => write!(f, "{}", err),
}
}
}