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 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}