use core::marker::PhantomData;
use crate::{
Array, EnumMap, MapEnum,
bitfld::{BitsEnumReLayout, ReLayoutBitsEnum},
int::{BasicInt, BasicUInt, PrimaryInt},
};
pub trait IterEnumDiscriminants: MapEnum {
type Value: PrimaryInt;
type Discriminants: EnumDiscriminantsIterator<Value = Self::Value> + 'static;
const DISCRIMINANTS: &Self::Discriminants;
}
#[allow(clippy::len_without_is_empty)]
pub trait EnumDiscriminantsIterator {
type Value;
fn len(&self) -> usize;
unsafe fn get_unchecked(&self, index: usize) -> (&str, Self::Value);
}
pub trait EnumDiscriminantsIteratorExt: EnumDiscriminantsIterator {
fn get(&self, index: usize) -> Option<(&str, Self::Value)> {
if index < self.len() { Some(unsafe { self.get_unchecked(index) }) } else { None }
}
}
impl<E: ?Sized + EnumDiscriminantsIterator> EnumDiscriminantsIteratorExt for E {}
impl<Ids: MapEnum, Name: AsRef<str>, Value: PrimaryInt> EnumDiscriminantsIterator for (EnumMap<Ids, Name>, EnumMap<Ids, Value>) {
type Value = Value;
fn len(&self) -> usize {
Ids::Array::LEN
}
unsafe fn get_unchecked(&self, index: usize) -> (&str, Self::Value) {
unsafe { (self.0.as_array().as_ref().get_unchecked(index).as_ref(), *self.1.as_array().as_ref().get_unchecked(index)) }
}
}
impl<Ids: MapEnum, Name: AsRef<str>, Value: PrimaryInt> EnumDiscriminantsIterator for (EnumMap<Ids, Name>, PhantomData<EnumMap<Ids, Value>>) {
type Value = Value;
fn len(&self) -> usize {
Ids::Array::LEN
}
unsafe fn get_unchecked(&self, index: usize) -> (&str, Self::Value) {
unsafe { (self.0.as_array().as_ref().get_unchecked(index).as_ref(), index.cast_as()) }
}
}
impl<Enum: MapEnum + ReLayoutBitsEnum, Bits: BasicUInt, const TAG_START: u32, const PAYLOAD_START: u32> MapEnum
for BitsEnumReLayout<Enum, Bits, TAG_START, PAYLOAD_START>
{
type Discriminant = Enum::Discriminant;
type Array = Enum::Array;
fn iter() -> impl ExactSizeIterator<Item = Self::Discriminant> {
Enum::iter()
}
fn get_index(&self) -> usize {
self.get().get_index()
}
}
impl<Enum: IterEnumDiscriminants + ReLayoutBitsEnum, Bits: BasicUInt, const TAG_START: u32, const PAYLOAD_START: u32> IterEnumDiscriminants
for BitsEnumReLayout<Enum, Bits, TAG_START, PAYLOAD_START>
{
type Value = Enum::Value;
type Discriminants = Enum::Discriminants;
const DISCRIMINANTS: &Self::Discriminants = Enum::DISCRIMINANTS;
}