use std::collections::BTreeMap;
use crate::KwId;
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Keyword {
pub namespace: Option<String>,
pub name: String,
}
impl Keyword {
#[must_use]
pub fn new(namespace: Option<&str>, name: &str) -> Self {
Self {
namespace: namespace.map(str::to_owned),
name: name.to_owned(),
}
}
#[must_use]
pub fn parse(text: &str) -> Self {
match text.split_once('/') {
Some((namespace, name)) if !namespace.is_empty() && !name.is_empty() => {
Self::new(Some(namespace), name)
}
_ => Self::new(None, text),
}
}
}
impl std::fmt::Display for Keyword {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.namespace {
Some(namespace) => write!(f, ":{namespace}/{}", self.name),
None => write!(f, ":{}", self.name),
}
}
}
#[derive(Clone, Debug, Default)]
pub struct KeywordInterner {
by_keyword: BTreeMap<Keyword, KwId>,
by_id: BTreeMap<KwId, Keyword>,
next: KwId,
}
impl KeywordInterner {
pub fn intern(&mut self, keyword: Keyword) -> KwId {
if let Some(id) = self.by_keyword.get(&keyword) {
return *id;
}
let id = self.next;
self.next += 1;
self.by_id.insert(id, keyword.clone());
self.by_keyword.insert(keyword, id);
id
}
#[must_use]
pub fn get(&self, keyword: &Keyword) -> Option<KwId> {
self.by_keyword.get(keyword).copied()
}
#[must_use]
pub fn resolve(&self, id: KwId) -> Option<&Keyword> {
self.by_id.get(&id)
}
pub fn iter(&self) -> impl Iterator<Item = (KwId, &Keyword)> {
self.by_id.iter().map(|(id, keyword)| (*id, keyword))
}
#[must_use]
pub fn len(&self) -> usize {
self.by_id.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.by_id.is_empty()
}
}