use std::collections::HashMap;
use std::fmt;
use std::iter::FusedIterator;
#[derive(Clone)]
pub struct Metadata(Impl);
#[derive(Clone)]
enum Impl {
Static(&'static phf::Map<&'static str, &'static str>),
Dynamic(HashMap<String, String>),
}
impl Metadata {
pub fn new(map: HashMap<String, String>) -> Self {
Self(Impl::Dynamic(map))
}
pub(crate) const fn default_const() -> Self {
const EMPTY_MAP: phf::Map<&str, &str> = phf::Map::new();
Self::new_static(&EMPTY_MAP)
}
pub(crate) const fn new_static(map: &'static phf::Map<&'static str, &'static str>) -> Self {
Self(Impl::Static(map))
}
pub fn is_empty(&self) -> bool {
match &self.0 {
Impl::Static(map) => map.is_empty(),
Impl::Dynamic(map) => map.is_empty(),
}
}
pub fn len(&self) -> usize {
match &self.0 {
Impl::Static(map) => map.len(),
Impl::Dynamic(map) => map.len(),
}
}
pub fn contains_key(&self, key: &str) -> bool {
match &self.0 {
Impl::Static(map) => map.contains_key(key),
Impl::Dynamic(map) => map.contains_key(key),
}
}
pub fn get(&self, key: &str) -> Option<&str> {
match &self.0 {
Impl::Static(map) => map.get(key).copied(),
Impl::Dynamic(map) => map.get(key).map(|s| &**s),
}
}
pub fn iter(&self) -> MetadataIter {
MetadataIter(match &self.0 {
Impl::Static(map) => IterImpl::Static(map.entries()),
Impl::Dynamic(map) => IterImpl::Dynamic(map.iter()),
})
}
}
impl From<HashMap<String, String>> for Metadata {
fn from(value: HashMap<String, String>) -> Self {
Self(Impl::Dynamic(value))
}
}
impl Default for Metadata {
fn default() -> Self {
Self::default_const()
}
}
impl fmt::Debug for Metadata {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.0 {
Impl::Static(map) => map.fmt(f),
Impl::Dynamic(map) => map.fmt(f),
}
}
}
impl<'a> IntoIterator for &'a Metadata {
type Item = (&'a str, &'a str);
type IntoIter = MetadataIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[derive(Clone, Debug)]
pub struct MetadataIter<'a>(IterImpl<'a>);
impl<'a> MetadataIter<'a> {
fn map_entries((key, value): (&&'a str, &&'a str)) -> (&'a str, &'a str) {
(*key, *value)
}
fn map_iter((key, value): (&'a String, &'a String)) -> (&'a str, &'a str) {
(&**key, &**value)
}
}
#[derive(Clone, Debug)]
enum IterImpl<'a> {
Static(phf::map::Entries<'a, &'static str, &'static str>),
Dynamic(std::collections::hash_map::Iter<'a, String, String>),
}
impl<'a> Iterator for MetadataIter<'a> {
type Item = (&'a str, &'a str);
fn next(&mut self) -> Option<Self::Item> {
match &mut self.0 {
IterImpl::Static(iter) => iter.next().map(Self::map_entries),
IterImpl::Dynamic(iter) => iter.next().map(Self::map_iter),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
match &self.0 {
IterImpl::Static(iter) => iter.size_hint(),
IterImpl::Dynamic(iter) => iter.size_hint(),
}
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
match &mut self.0 {
IterImpl::Static(iter) => iter.nth(n).map(Self::map_entries),
IterImpl::Dynamic(iter) => iter.nth(n).map(Self::map_iter),
}
}
fn fold<B, F>(self, init: B, mut f: F) -> B
where
Self: Sized,
F: FnMut(B, Self::Item) -> B,
{
match self.0 {
IterImpl::Static(iter) => iter.fold(init, move |acc, (k, v)| f(acc, (*k, *v))),
IterImpl::Dynamic(iter) => iter.fold(init, move |acc, (k, v)| f(acc, (&**k, &**v))),
}
}
fn count(self) -> usize
where
Self: Sized,
{
self.len()
}
}
impl<'a> ExactSizeIterator for MetadataIter<'a> {}
impl<'a> FusedIterator for MetadataIter<'a> {}