use std::{borrow::Borrow, iter::FusedIterator};
use crate::{
error::ParseError,
util::{FlatMap, FlatMapEditGuard},
};
pub trait NameClass: 'static {
type Raw<'a>: std::borrow::Borrow<[u8]> + Clone + Ord;
type Union<'a>;
fn get_tag<'a, 'b>(outer: &'a Self::Union<'b>) -> &'a Self::Raw<'b>;
fn get_tag_mut<'a, 'b>(outer: &'a mut Self::Union<'b>) -> &'a mut Self::Raw<'b>;
}
pub trait Name<Class: NameClass>: std::any::Any + Copy + std::fmt::Display {
fn as_raw(&self) -> &'static <Class as NameClass>::Raw<'static>;
}
pub trait NameValued<Class: NameClass>: Name<Class> {
type Value<'a>;
fn from_union<'a>(
input: &<Class as NameClass>::Union<'a>,
) -> Result<Self::Value<'a>, ParseError>;
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
pub(crate) struct NameExtractor<'a, K: NameClass, V = ()>(std::marker::PhantomData<&'a mut (K, V)>);
impl<'a, K: NameClass, V> crate::util::KeyExtractor<(K::Union<'a>, V)> for NameExtractor<'a, K, V> {
type Key = K::Raw<'a>;
type KeyBorrowed = [u8];
fn extract_key<'b>(elem: &'b (K::Union<'a>, V)) -> &'b Self::Key {
K::get_tag(&elem.0)
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct NameMap<K: NameClass, V: 'static = ()> {
map: crate::util::FlatMap<(K::Union<'static>, V), NameExtractor<'static, K, V>>,
}
macro_rules! tagmap_methods {
($field:tt) => {
#[doc = "Returns a shared reference to the union containing `tag`, if any."]
pub fn get_union<T: Name<K>>(&self, tag: T) -> Option<&K::Union<'static>> {
self.get_union_raw(tag.as_raw())
}
#[doc = "Returns a shared reference to the union containing `tag`, if any."]
pub fn get_union_raw(&self, tag: &K::Raw<'_>) -> Option<&K::Union<'static>> {
Some(&self.$field.get(tag.borrow())?.0)
}
#[doc = "Returns a shared reference to the extra value for `tag`, if any."]
pub fn get_extra_raw(&self, tag: &K::Raw<'_>) -> Option<&V> {
Some(&self.$field.get(tag.borrow())?.1)
}
#[doc = "Returns a mutable reference to the extra value for `tag`, if any."]
pub fn get_extra_raw_mut(&mut self, tag: &K::Raw<'_>) -> Option<&mut V> {
Some(&mut self.$field.get_mut(tag.borrow())?.1)
}
#[doc = "Returns a shared reference to the extra value for `tag`, if any."]
pub fn get_extra<T: Name<K>>(&self, tag: T) -> Option<&V> {
self.get_extra_raw(tag.as_raw())
}
#[doc = "Returns a mutable reference to the extra value for `tag`, if any."]
pub fn get_extra_mut<T: Name<K>>(&mut self, tag: T) -> Option<&mut V> {
self.get_extra_raw_mut(tag.as_raw())
}
#[doc = "Returns and parses the value stored for `tag`, if any."]
pub fn get_parsed<T: NameValued<K>>(
&self,
tag: T,
) -> Option<Result<T::Value<'static>, ParseError>> {
let (u, _) = self.$field.get(tag.as_raw().borrow())?;
Some(T::from_union(u))
}
#[doc = "Returns both the parsed value and"]
#[doc = "a shared reference to the extra value for `tag`, if any."]
pub fn get_both<T: NameValued<K>>(
&self,
tag: T,
) -> Option<(Result<T::Value<'static>, ParseError>, &V)> {
let (u, x) = self.$field.get(tag.as_raw().borrow())?;
Some((T::from_union(u), x))
}
#[doc = "Returns both the parsed value and"]
#[doc = "a mutable reference to the extra value for `tag`, if any."]
pub fn get_both_mut<T: NameValued<K>>(
&mut self,
tag: T,
) -> Option<(Result<T::Value<'static>, ParseError>, &mut V)> {
let (u, x) = self.$field.get_mut(tag.as_raw().borrow())?;
Some((T::from_union(u), x))
}
#[doc = "Clears the map of all elements."]
pub fn clear(&mut self) {
self.$field.clear();
}
};
}
impl<K: NameClass, V: 'static> NameMap<K, V> {
pub const fn new() -> Self {
NameMap { map: FlatMap::new() }
}
collection_methods!(map);
tagmap_methods!(map);
pub fn edit(&mut self) -> NameMapEditGuard<'_, K, V> {
NameMapEditGuard(self.map.edit())
}
pub fn keys(&self) -> NameMapIter<'_, K, V, true> {
NameMapIter { slice: self.map.as_slice() }
}
}
#[derive(Clone, PartialEq, Eq, Debug, Default)]
pub struct NameMapIter<
'a,
K: NameClass,
V: 'static,
const SORTED: bool,
const KEY_ONLY: bool = true,
const OMIT_EXTRA: bool = true,
> {
slice: &'a [(K::Union<'static>, V)],
}
impl<'a, const SORTED: bool, K: NameClass, V: 'static> Iterator for NameMapIter<'a, K, V, SORTED> {
type Item = &'a K::Raw<'static>;
fn next(&mut self) -> Option<Self::Item> {
let (next, rest) = self.slice.split_first()?;
self.slice = rest;
Some(K::get_tag(&next.0))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.slice.len();
(size, Some(size))
}
}
impl<'a, const SORTED: bool, K: NameClass, V: 'static> DoubleEndedIterator
for NameMapIter<'a, K, V, SORTED>
{
fn next_back(&mut self) -> Option<Self::Item> {
let (next, rest) = self.slice.split_last()?;
self.slice = rest;
Some(K::get_tag(&next.0))
}
}
impl<'a, const SORTED: bool, K: NameClass, V: 'static> FusedIterator
for NameMapIter<'a, K, V, SORTED>
{
}
impl<'a, const SORTED: bool, K: NameClass, V: 'static> ExactSizeIterator
for NameMapIter<'a, K, V, SORTED>
{
}
#[derive(Debug)]
pub struct NameMapEditGuard<'a, K: NameClass, V: 'static>(
pub(self) FlatMapEditGuard<'a, (K::Union<'static>, V), NameExtractor<'static, K, V>>,
);
impl<'a, K: NameClass, V: 'static> NameMapEditGuard<'a, K, V> {
collection_methods!(0);
tagmap_methods!(0);
#[inline]
pub fn insert(&mut self, elem: K::Union<'static>, extra: V) -> Option<(K::Union<'static>, V)> {
self.0.insert((elem, extra))
}
#[inline]
pub fn insert_or_update(
&mut self,
elem: K::Union<'static>,
extra: V,
) -> Option<K::Union<'static>> {
match self.0.get_or_insert((elem, extra)) {
(eref, Some((elem, extra))) => {
eref.1 = extra;
Some(elem)
}
_ => None,
}
}
#[inline]
pub fn try_insert(
&mut self,
elem: K::Union<'static>,
extra: V,
) -> Option<(K::Union<'static>, V)> {
self.0.try_insert((elem, extra))
}
#[inline]
pub fn remove<T: Name<K>>(&mut self, tag: T) -> Option<(K::Union<'static>, V)> {
self.remove_raw(tag.as_raw())
}
#[inline]
pub fn remove_raw(&mut self, tag: &K::Raw<'_>) -> Option<(K::Union<'static>, V)> {
self.0.remove(tag.borrow())
}
}
impl<K: NameClass> Default for NameMap<K> {
fn default() -> Self {
Self::new()
}
}