tracexec_core/
cache.rs

1use serde::{Serialize, Serializer};
2use std::{
3  borrow::Cow,
4  fmt::{Debug, Display},
5  ops::Deref,
6  sync::{Arc, LazyLock, Weak},
7};
8use weak_table::WeakHashSet;
9
10#[derive(Clone)]
11#[repr(transparent)]
12pub struct ArcStr(Arc<str>);
13
14impl ArcStr {
15  pub fn as_str(&self) -> &str {
16    &self.0
17  }
18}
19
20impl Deref for ArcStr {
21  type Target = str;
22
23  fn deref(&self) -> &Self::Target {
24    &self.0
25  }
26}
27
28impl AsRef<str> for ArcStr {
29  fn as_ref(&self) -> &str {
30    &self.0
31  }
32}
33
34impl<T> PartialEq<T> for ArcStr
35where
36  T: AsRef<str>,
37{
38  fn eq(&self, other: &T) -> bool {
39    &*self.0 == other.as_ref()
40  }
41}
42
43impl Eq for ArcStr {}
44
45impl From<Arc<str>> for ArcStr {
46  fn from(value: Arc<str>) -> Self {
47    Self(value)
48  }
49}
50
51impl From<ArcStr> for Cow<'_, str> {
52  fn from(value: ArcStr) -> Self {
53    Self::Owned(value.to_string())
54  }
55}
56
57impl Serialize for ArcStr {
58  fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
59  where
60    S: Serializer,
61  {
62    serializer.serialize_str(&self.0)
63  }
64}
65
66impl std::hash::Hash for ArcStr {
67  fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
68    self.0.hash(state);
69  }
70}
71
72impl PartialOrd for ArcStr {
73  fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
74    Some(self.cmp(other))
75  }
76}
77
78impl Ord for ArcStr {
79  fn cmp(&self, other: &Self) -> std::cmp::Ordering {
80    self.0.cmp(&other.0)
81  }
82}
83
84impl Display for ArcStr {
85  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86    Display::fmt(&self.0, f)
87  }
88}
89
90impl Debug for ArcStr {
91  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92    Debug::fmt(&self.0, f)
93  }
94}
95
96impl From<&str> for ArcStr {
97  fn from(value: &str) -> Self {
98    Arc::<str>::from(value).into()
99  }
100}
101
102impl Default for ArcStr {
103  fn default() -> Self {
104    DEFAULT_ARCSTR.clone()
105  }
106}
107
108static DEFAULT_ARCSTR: LazyLock<ArcStr> = LazyLock::new(|| "".into());
109
110#[derive(Default)]
111pub struct StringCache {
112  inner: WeakHashSet<Weak<str>>,
113}
114
115impl StringCache {
116  pub fn new() -> Self {
117    Self::default()
118  }
119
120  pub fn get_or_insert(&mut self, s: &str) -> ArcStr {
121    if let Some(s) = self.inner.get(s) {
122      s.into()
123    } else {
124      let arc: Arc<str> = Arc::from(s);
125      self.inner.insert(arc.clone());
126      arc.into()
127    }
128  }
129
130  // Probably this is not necessary.
131  // I don't think we can find a way to turn a String into Arc<str> in-place.
132  pub fn get_or_insert_owned(&mut self, s: String) -> ArcStr {
133    if let Some(s) = self.inner.get(s.as_str()) {
134      s.into()
135    } else {
136      let arc: Arc<str> = Arc::from(s);
137      self.inner.insert(arc.clone());
138      arc.into()
139    }
140  }
141}