Skip to main content

veilid_tools/
static_string_table.rs

1use super::*;
2
3static STRING_TABLE: std::sync::LazyLock<Mutex<BTreeSet<&'static str>>> =
4    std::sync::LazyLock::new(|| Mutex::new(BTreeSet::new()));
5
6static STRING_TRANSFORM_TABLE: std::sync::LazyLock<Mutex<HashMap<(usize, usize), &'static str>>> =
7    std::sync::LazyLock::new(|| Mutex::new(HashMap::new()));
8
9pub trait ToStaticStr {
10    fn to_static_str(&self) -> &'static str;
11}
12
13impl<T: AsRef<str>> ToStaticStr for T {
14    fn to_static_str(&self) -> &'static str {
15        let s = self.as_ref();
16        let mut string_table = STRING_TABLE.lock();
17        if let Some(v) = string_table.get(s) {
18            return v;
19        }
20        let ss = Box::leak(s.to_owned().into_boxed_str());
21        string_table.insert(ss);
22        ss
23    }
24}
25
26pub trait StaticStrTransform {
27    fn static_transform<F: FnOnce(&'static str) -> &'static str>(
28        self,
29        transform: F,
30    ) -> &'static str;
31}
32
33impl StaticStrTransform for &'static str {
34    fn static_transform<F: FnOnce(&'static str) -> &'static str>(
35        self,
36        transform: F,
37    ) -> &'static str {
38        // multiple keys can point to the same data, but it must be bounded due to static lifetime
39        // a pointer to static memory plus its length must always be the same immutable slice
40        // this is maybe slightly faster for use in log string transformation where speed is essential at scale
41        // otherwise we would have used a hash here.
42        // TODO: if performance does not suffer, consider switching to a hash at a later point, as this could cause
43        // the STRING_TRANSFORM_TABLE to be bigger than necessary, depending on unknowns in rustc about 'static str deduplication.
44
45        let key = (self.as_ptr() as usize, self.len());
46
47        let mut transform_table = STRING_TRANSFORM_TABLE.lock();
48        if let Some(v) = transform_table.get(&key) {
49            return v;
50        }
51        let out = transform(self);
52        transform_table.insert(key, out);
53        out
54    }
55}