diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 940319f..593fd5b 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -8,7 +8,7 @@ pub mod types; use std::borrow::Cow; pub use rhei::RheiContext; use style::StyleSheet as SS; -pub use types::{ComponentDef, Document, Element, InterpError}; +pub use types::{ComponentDef, Document, Element, Interner, InterpError}; use compact_str::CompactString; use opcodes::*; @@ -44,7 +44,7 @@ impl Interpreter { //let rhei_ctx = RheiContext::new(&rhei_scripts); //rhei_ctx.initialize(&mut variables); - Ok(Document { roots, components, variables, rhei_scripts, stylesheet }) + Ok(Document { roots, components, variables, rhei_scripts, stylesheet, interner: Interner::new() }) } fn parse_block_elements<'a>( diff --git a/src/interpreter/types.rs b/src/interpreter/types.rs index 6fac207..ac44f9e 100644 --- a/src/interpreter/types.rs +++ b/src/interpreter/types.rs @@ -2,9 +2,78 @@ use std::borrow::Cow; use std::collections::HashMap; use std::fmt; + use super::style::{ComputedStyle, StyleSheet}; use compact_str::CompactString; +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct InternedStr(u32); + +impl InternedStr { + pub const fn from_raw(id: u32) -> Self { + Self(id) + } + + pub fn raw(&self) -> u32 { + self.0 + } +} + +impl InternedStr { + pub fn eq_str(&self, other: &str) -> bool { + with_interner(|interner| interner.lookup(*self) == other) + } +} + +#[derive(Debug, Clone)] +pub struct Interner { + strings: Vec, + map: HashMap, + next_id: u32, +} + +impl Interner { + pub fn new() -> Self { + Self { + strings: Vec::new(), + map: HashMap::new(), + next_id: 0, + } + } + + pub fn intern(&mut self, s: &str) -> InternedStr { + if let Some(&id) = self.map.get(s) { + return InternedStr(id); + } + let id = self.next_id; + self.next_id += 1; + self.strings.push(s.to_string()); + self.map.insert(s.to_string(), id); + InternedStr(id) + } + + pub fn lookup(&self, id: InternedStr) -> &str { + &self.strings[id.0 as usize] + } + + pub fn intern_or_none(&mut self, s: Option<&str>) -> Option { + s.map(|s| self.intern(s)) + } +} + +use std::cell::RefCell; + +thread_local! { + static GLOBAL_INTERNER: RefCell = RefCell::new(Interner::new()); +} + +pub fn with_interner(f: F) -> R +where + F: FnOnce(&mut Interner) -> R, +{ + GLOBAL_INTERNER.with(|i| f(&mut *i.borrow_mut())) +} + #[derive(Clone, Debug)] pub enum Value { Str(CompactString), @@ -128,6 +197,7 @@ pub struct Document<'a> { pub variables: HashMap, pub rhei_scripts: Vec, pub stylesheet: StyleSheet, + pub interner: Interner, } #[derive(Debug)]