heron_rebuild_workflow/
string_cache.rs

1use std::cell::{Ref, RefCell};
2
3use anyhow::Result;
4
5use util::{HashMap, Hasher};
6
7use crate::WorkflowStrings;
8
9pub trait StringMaker<T> {
10    fn make_string(&self, val: &T, wf: &WorkflowStrings, buf: &mut String) -> Result<()>;
11}
12
13#[derive(Debug)]
14pub struct StringCache<T, M, Idx = u16> {
15    strings: RefCell<String>,
16    idxs: RefCell<HashMap<T, (Idx, Idx)>>,
17    maker: M,
18}
19
20impl<T, M, Idx> StringCache<T, M, Idx> {
21    pub fn with_capacity_and_str_len(maker: M, cap: usize, str_len: usize) -> Self {
22        Self {
23            strings: RefCell::new(String::with_capacity(str_len)),
24            idxs: RefCell::new(HashMap::with_capacity_and_hasher(cap, Hasher::default())),
25            maker,
26        }
27    }
28}
29
30impl<T, M, Idx> StringCache<T, M, Idx>
31where
32    T: Clone + Eq + std::hash::Hash,
33    M: StringMaker<T>,
34    Idx: Copy + TryFrom<usize> + Into<usize>,
35    Idx::Error: std::error::Error + Send + Sync + 'static,
36{
37    pub fn get_or_insert(&self, val: &T, wf: &WorkflowStrings) -> Result<Ref<str>> {
38        if let Some((start, end)) = self.idxs.borrow().get(val).copied() {
39            return Ok(self.get_substr(start.into(), end.into()));
40        }
41        let (start, end) = self.push_new_str(val, wf)?;
42        self.idxs.borrow_mut().insert(val.clone(), (start.try_into()?, end.try_into()?));
43        Ok(self.get_substr(start, end))
44    }
45
46    fn push_new_str(&self, val: &T, wf: &WorkflowStrings) -> Result<(usize, usize)> {
47        let mut s = self.strings.borrow_mut();
48        let start = s.len();
49        self.maker.make_string(val, wf, &mut s)?;
50        Ok((start, s.len()))
51    }
52
53    fn get_substr(&self, start: usize, end: usize) -> Ref<str> {
54        let s = self.strings.borrow();
55        Ref::map(s, |s| &s[start..end])
56    }
57}