use core::{iter::Fuse, num::NonZero};
use crate::Traversal;
pub struct KeyLookup {
pub len: NonZero<usize>,
pub names: Option<&'static [&'static str]>,
}
impl KeyLookup {
#[inline]
pub const fn homogeneous(len: usize) -> Self {
match NonZero::new(len) {
Some(len) => Self { len, names: None },
None => panic!("Internal nodes must have at least one leaf"),
}
}
#[inline]
pub fn lookup(&self, index: usize) -> Result<Option<&'static str>, Traversal> {
match self.names {
Some(names) => {
debug_assert!(names.len() == self.len.get());
match names.get(index) {
Some(name) => Ok(Some(name)),
None => Err(Traversal::NotFound(1)),
}
}
None => {
if index >= self.len.get() {
Err(Traversal::NotFound(1))
} else {
Ok(None)
}
}
}
}
#[inline]
pub fn clamp(&self, index: usize) -> Result<usize, Traversal> {
if index >= self.len.get() {
Err(Traversal::NotFound(1))
} else {
Ok(index)
}
}
}
pub trait Key {
fn find(&self, lookup: &KeyLookup) -> Result<usize, Traversal>;
}
impl<T: Key> Key for &T
where
T: Key + ?Sized,
{
#[inline]
fn find(&self, lookup: &KeyLookup) -> Result<usize, Traversal> {
(**self).find(lookup)
}
}
impl<T: Key> Key for &mut T
where
T: Key + ?Sized,
{
#[inline]
fn find(&self, lookup: &KeyLookup) -> Result<usize, Traversal> {
(**self).find(lookup)
}
}
macro_rules! impl_key_integer {
($($t:ty)+) => {$(
impl Key for $t {
#[inline]
fn find(&self, lookup: &KeyLookup) -> Result<usize, Traversal> {
let index = (*self).try_into().or(Err(Traversal::NotFound(1)))?;
lookup.clamp(index)
}
}
)+};
}
impl_key_integer!(usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128);
impl Key for str {
#[inline]
fn find(&self, lookup: &KeyLookup) -> Result<usize, Traversal> {
let index = match lookup.names {
Some(names) => names.iter().position(|n| *n == self),
None => self.parse().ok(),
}
.ok_or(Traversal::NotFound(1))?;
lookup.clamp(index)
}
}
pub trait Keys {
fn next(&mut self, lookup: &KeyLookup) -> Result<usize, Traversal>;
fn finalize(&mut self) -> Result<(), Traversal>;
#[inline]
fn chain<U: IntoKeys>(self, other: U) -> Chain<Self, U::IntoKeys>
where
Self: Sized,
{
Chain(self, other.into_keys())
}
}
impl<T> Keys for &mut T
where
T: Keys + ?Sized,
{
#[inline]
fn next(&mut self, lookup: &KeyLookup) -> Result<usize, Traversal> {
(**self).next(lookup)
}
#[inline]
fn finalize(&mut self) -> Result<(), Traversal> {
(**self).finalize()
}
}
#[derive(Debug, Clone)]
#[repr(transparent)]
pub struct KeysIter<T>(Fuse<T>);
impl<T: Iterator> KeysIter<T> {
#[inline]
fn new(inner: T) -> Self {
Self(inner.fuse())
}
}
impl<T> Keys for KeysIter<T>
where
T: Iterator,
T::Item: Key,
{
#[inline]
fn next(&mut self, lookup: &KeyLookup) -> Result<usize, Traversal> {
self.0.next().ok_or(Traversal::TooShort(0))?.find(lookup)
}
#[inline]
fn finalize(&mut self) -> Result<(), Traversal> {
self.0
.next()
.is_none()
.then_some(())
.ok_or(Traversal::TooLong(0))
}
}
pub trait IntoKeys {
type IntoKeys: Keys;
fn into_keys(self) -> Self::IntoKeys;
}
impl<T> IntoKeys for T
where
T: IntoIterator,
<T::IntoIter as Iterator>::Item: Key,
{
type IntoKeys = KeysIter<T::IntoIter>;
#[inline]
fn into_keys(self) -> Self::IntoKeys {
KeysIter::new(self.into_iter())
}
}
impl<T> IntoKeys for KeysIter<T>
where
T: Iterator,
T::Item: Key,
{
type IntoKeys = KeysIter<T>;
#[inline]
fn into_keys(self) -> Self::IntoKeys {
self
}
}
pub struct Chain<T, U>(T, U);
impl<T, U> Chain<T, U> {
#[inline]
pub fn new(t: T, u: U) -> Self {
Self(t, u)
}
}
impl<T: Keys, U: Keys> Keys for Chain<T, U> {
#[inline]
fn next(&mut self, lookup: &KeyLookup) -> Result<usize, Traversal> {
match self.0.next(lookup) {
Err(Traversal::TooShort(_)) => self.1.next(lookup),
ret => ret,
}
}
#[inline]
fn finalize(&mut self) -> Result<(), Traversal> {
self.0.finalize().and_then(|()| self.1.finalize())
}
}
impl<T: Keys, U: Keys> IntoKeys for Chain<T, U> {
type IntoKeys = Self;
#[inline]
fn into_keys(self) -> Self::IntoKeys {
self
}
}