heron_rebuild_workflow/
string_cache.rs1use 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}