use std::cell::Cell;
#[derive(Clone, Copy, Debug)]
pub struct DomainGloss {
pub templates: &'static [(&'static str, &'static str)],
pub glosses: &'static [(&'static str, &'static str)],
pub names: &'static [(&'static str, &'static str)],
}
impl DomainGloss {
pub fn template(&self, relation: &str) -> Option<&'static str> {
lookup(self.templates, relation)
}
pub fn gloss(&self, relation: &str) -> Option<&'static str> {
lookup(self.glosses, relation)
}
pub fn name(&self, constant: &str) -> Option<&'static str> {
lookup(self.names, constant)
}
}
fn lookup(table: &[(&'static str, &'static str)], key: &str) -> Option<&'static str> {
table.iter().find(|(k, _)| *k == key).map(|(_, v)| *v)
}
thread_local! {
static OVERLAY: Cell<Option<&'static DomainGloss>> = const { Cell::new(None) };
}
pub(crate) fn with_overlay<T>(overlay: Option<&'static DomainGloss>, f: impl FnOnce() -> T) -> T {
struct Guard(Option<&'static DomainGloss>);
impl Drop for Guard {
fn drop(&mut self) {
OVERLAY.with(|o| o.set(self.0));
}
}
let _guard = OVERLAY.with(|o| Guard(o.replace(overlay)));
f()
}
pub(crate) fn active() -> Option<&'static DomainGloss> {
OVERLAY.with(Cell::get)
}
#[cfg(test)]
mod tests {
use super::*;
static SAMPLE: DomainGloss = DomainGloss {
templates: &[("dangerous", "{x1} is at toxicity risk")],
glosses: &[("chemical", "drug")],
names: &[("varfarin", "warfarin")],
};
#[test]
fn lookups_resolve() {
assert_eq!(
SAMPLE.template("dangerous"),
Some("{x1} is at toxicity risk")
);
assert_eq!(SAMPLE.template("increases"), None);
assert_eq!(SAMPLE.gloss("chemical"), Some("drug"));
assert_eq!(SAMPLE.name("varfarin"), Some("warfarin"));
assert_eq!(SAMPLE.name("adam"), None);
}
#[test]
fn overlay_is_scoped_and_restored() {
assert!(active().is_none());
with_overlay(Some(&SAMPLE), || {
assert!(std::ptr::eq(active().unwrap(), &SAMPLE));
with_overlay(None, || assert!(active().is_none()));
assert!(std::ptr::eq(active().unwrap(), &SAMPLE));
});
assert!(active().is_none());
}
}