use std::collections::HashMap;
use std::hash::{BuildHasher, RandomState};
use std::sync::LazyLock;
use super::visibility::EntityVisibility;
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct Entity {
pub value: String,
pub description: String,
pub visibility: EntityVisibility,
}
impl Entity {
pub(super) fn globals<S: BuildHasher>(hasher: S) -> HashMap<&'static [u8], &'static str, S> {
let mut globals =
HashMap::with_capacity_and_hasher(html_escape::NAMED_ENTITIES.len() + 1, hasher);
globals.extend(html_escape::NAMED_ENTITIES);
globals.insert(b"text", "&text;");
globals
}
pub fn global<S: AsRef<[u8]>>(name: S) -> Option<&'static str> {
static GLOBALS: LazyLock<HashMap<&'static [u8], &'static str>> =
LazyLock::new(|| Entity::globals(RandomState::new()));
GLOBALS.get(name.as_ref()).copied()
}
pub const fn const_global(name: &str) -> Option<&'static str> {
const fn const_eq(mut a: &[u8], mut b: &[u8]) -> bool {
if a.len() != b.len() {
return false;
}
while let ([first_a, rest_a @ ..], [first_b, rest_b @ ..]) = (a, b) {
if *first_a != *first_b {
return false;
}
a = rest_a;
b = rest_b;
}
true
}
let name = name.as_bytes();
let mut entities = html_escape::NAMED_ENTITIES.as_slice();
while let [(key, value), rest @ ..] = entities {
if const_eq(key, name) {
return Some(value);
}
entities = rest;
}
None
}
pub const fn new(value: String) -> Self {
Self {
value,
description: String::new(),
visibility: EntityVisibility::Default,
}
}
pub const fn is_private(&self) -> bool {
matches!(self.visibility, EntityVisibility::Private)
}
pub const fn is_published(&self) -> bool {
matches!(self.visibility, EntityVisibility::Publish)
}
pub fn add(&mut self, value: &str) {
self.value.reserve(value.len() + 1);
self.value.push('|');
self.value.push_str(value);
}
pub fn remove(&mut self, value: &str) {
self.value = self
.value
.split('|')
.filter(|item| *item != value)
.collect::<Vec<_>>()
.join("|");
}
}
impl From<String> for Entity {
fn from(value: String) -> Self {
Self::new(value)
}
}