use std::collections::HashMap;
use std::sync::Arc;
use crate::style::Style;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct StyleId(u32);
impl StyleId {
pub const NULL: StyleId = StyleId(0);
pub const fn as_u32(self) -> u32 {
self.0
}
}
impl Default for StyleId {
fn default() -> Self {
Self::NULL
}
}
#[derive(Debug)]
pub struct StyleInterner {
forward: Vec<Arc<Style>>,
reverse: HashMap<Arc<Style>, StyleId>,
}
impl StyleInterner {
pub fn new() -> Self {
let null_style = Arc::new(Style::null());
let mut interner = Self {
forward: Vec::new(),
reverse: HashMap::new(),
};
interner.forward.push(Arc::clone(&null_style));
interner.reverse.insert(null_style, StyleId::NULL);
interner
}
pub fn intern(&mut self, style: Style) -> StyleId {
let arc = Arc::new(style);
if let Some(&id) = self.reverse.get(&arc) {
return id;
}
let id = StyleId(self.forward.len() as u32);
self.forward.push(Arc::clone(&arc));
self.reverse.insert(arc, id);
id
}
pub fn get(&self, id: StyleId) -> Option<&Arc<Style>> {
self.forward.get(id.0 as usize)
}
pub fn len(&self) -> usize {
self.forward.len()
}
pub fn is_empty(&self) -> bool {
self.forward.len() <= 1
}
}
impl Default for StyleInterner {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn null_is_pre_seeded() {
let interner = StyleInterner::new();
assert_eq!(interner.len(), 1);
assert!(interner.is_empty()); let arc = interner.get(StyleId::NULL).expect("null present");
assert!(arc.is_null());
}
#[test]
fn dedup_returns_same_id() {
let mut interner = StyleInterner::new();
let s = Style::parse("bold red").unwrap();
let id1 = interner.intern(s.clone());
let id2 = interner.intern(s);
assert_eq!(id1, id2);
assert_eq!(interner.len(), 2); }
#[test]
fn distinct_styles_get_distinct_ids() {
let mut interner = StyleInterner::new();
let bold = Style::parse("bold").unwrap();
let italic = Style::parse("italic").unwrap();
let id1 = interner.intern(bold);
let id2 = interner.intern(italic);
assert_ne!(id1, id2);
assert_eq!(interner.len(), 3);
}
#[test]
fn null_intern_returns_null_id() {
let mut interner = StyleInterner::new();
let id = interner.intern(Style::null());
assert_eq!(id, StyleId::NULL);
assert_eq!(interner.len(), 1); }
#[test]
fn get_unknown_id_returns_none() {
let interner = StyleInterner::new();
assert!(interner.get(StyleId(999)).is_none());
}
#[test]
fn ids_are_stable() {
let mut interner = StyleInterner::new();
let s = Style::parse("bold").unwrap();
let id = interner.intern(s.clone());
for i in 0..10 {
interner.intern(Style::parse(&format!("color({i})")).unwrap());
}
assert_eq!(interner.intern(s), id);
}
}