use std::collections::HashMap;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RefEntry {
pub r#ref: String,
pub backend_node_id: u64,
pub role: String,
pub name: String,
}
#[derive(Debug, Clone)]
pub struct RefTable {
pub doc_token: u64,
by_ref: HashMap<String, RefEntry>,
by_backend: HashMap<u64, String>,
next: u32,
}
impl RefTable {
pub fn new(doc_token: u64) -> Self {
Self {
doc_token,
by_ref: HashMap::new(),
by_backend: HashMap::new(),
next: 1,
}
}
pub fn intern(&mut self, backend_node_id: u64, role: &str, name: &str) -> String {
if let Some(r) = self.by_backend.get(&backend_node_id) {
if let Some(entry) = self.by_ref.get_mut(r) {
entry.role = role.to_string();
entry.name = name.to_string();
}
return r.clone();
}
let r = format!("e{}", self.next);
self.next += 1;
self.by_backend.insert(backend_node_id, r.clone());
self.by_ref.insert(
r.clone(),
RefEntry {
r#ref: r.clone(),
backend_node_id,
role: role.to_string(),
name: name.to_string(),
},
);
r
}
pub fn lookup(&self, r: &str) -> Option<&RefEntry> {
self.by_ref.get(r)
}
pub fn len(&self) -> usize {
self.by_ref.len()
}
pub fn is_empty(&self) -> bool {
self.by_ref.is_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn intern_is_stable_per_backend_node() {
let mut t = RefTable::new(1);
let a = t.intern(10, "button", "Save");
let b = t.intern(11, "link", "Docs");
let a2 = t.intern(10, "button", "Save changes");
assert_eq!(a, "e1");
assert_eq!(b, "e2");
assert_eq!(a2, "e1");
assert_eq!(t.lookup("e1").unwrap().name, "Save changes");
assert_eq!(t.lookup("e1").unwrap().backend_node_id, 10);
assert!(t.lookup("e3").is_none());
assert_eq!(t.len(), 2);
}
}