rajac_base/
shared_string.rs1use crate::result::RajacResult;
4use ecow::EcoString;
5use serde::{Deserialize, Deserializer, Serialize, Serializer};
6
7#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
13pub struct SharedString(pub EcoString);
14
15impl SharedString {
16 pub fn new(s: impl Into<String>) -> Self {
18 Self(EcoString::from(s.into()))
19 }
20
21 pub fn empty() -> Self {
23 Self(EcoString::from(""))
24 }
25
26 pub fn clear(&mut self) {
28 self.0 = EcoString::from("");
29 }
30
31 pub fn push_str(&mut self, string: &str) {
33 let mut new_string = self.0.to_string();
34 new_string.push_str(string);
35 self.0 = EcoString::from(new_string);
36 }
37
38 pub fn as_str(&self) -> &str {
40 &self.0
41 }
42
43 pub fn len(&self) -> usize {
45 self.0.len()
46 }
47
48 pub fn is_empty(&self) -> bool {
50 self.0.is_empty()
51 }
52
53 pub fn from_utf8(ut8_bytes: &[u8]) -> RajacResult<Self> {
54 Ok(Self(EcoString::from(str::from_utf8(ut8_bytes)?)))
55 }
56}
57
58#[macro_export]
62macro_rules! shared_format {
63 ($($arg:tt)*) => {
64 $crate::shared_string::SharedString(ecow::eco_format!($($arg)*))
65 };
66}
67
68impl Default for SharedString {
69 fn default() -> Self {
70 Self::empty()
71 }
72}
73
74impl From<String> for SharedString {
75 fn from(s: String) -> Self {
76 Self(EcoString::from(s))
77 }
78}
79
80impl From<&str> for SharedString {
81 fn from(s: &str) -> Self {
82 Self(EcoString::from(s))
83 }
84}
85
86impl From<Box<str>> for SharedString {
87 fn from(s: Box<str>) -> Self {
88 Self(EcoString::from(&*s))
89 }
90}
91
92impl From<&SharedString> for SharedString {
93 fn from(s: &SharedString) -> Self {
94 s.clone()
95 }
96}
97
98impl AsRef<str> for SharedString {
99 fn as_ref(&self) -> &str {
100 &self.0
101 }
102}
103
104impl std::borrow::Borrow<str> for SharedString {
105 fn borrow(&self) -> &str {
106 &self.0
107 }
108}
109
110impl std::fmt::Display for SharedString {
111 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112 write!(f, "{}", self.0)
113 }
114}
115
116impl std::fmt::Debug for SharedString {
117 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
118 write!(f, "`{}`", self.0)
119 }
120}
121
122impl std::ops::Deref for SharedString {
123 type Target = str;
124
125 fn deref(&self) -> &Self::Target {
126 &self.0
127 }
128}
129
130impl PartialEq<str> for SharedString {
131 fn eq(&self, other: &str) -> bool {
132 self.as_str() == other
133 }
134}
135
136impl PartialEq<&str> for SharedString {
137 fn eq(&self, other: &&str) -> bool {
138 self.as_str() == *other
139 }
140}
141
142impl PartialEq<SharedString> for str {
143 fn eq(&self, other: &SharedString) -> bool {
144 self == other.as_str()
145 }
146}
147
148impl PartialEq<SharedString> for &str {
149 fn eq(&self, other: &SharedString) -> bool {
150 *self == other.as_str()
151 }
152}
153
154impl<'a, C> speedy::Readable<'a, C> for SharedString
155where
156 C: speedy::Context,
157{
158 fn read_from<R: speedy::Reader<'a, C>>(reader: &mut R) -> Result<Self, C::Error> {
159 let string = String::read_from(reader)?;
160 Ok(SharedString(EcoString::from(string)))
161 }
162}
163
164impl<C> speedy::Writable<C> for SharedString
165where
166 C: speedy::Context,
167{
168 fn write_to<W>(&self, writer: &mut W) -> Result<(), C::Error>
169 where
170 W: speedy::Writer<C> + ?Sized,
171 {
172 self.as_str().write_to(writer)
173 }
174}
175
176impl Serialize for SharedString {
177 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
178 where
179 S: Serializer,
180 {
181 serializer.serialize_str(self.as_str())
182 }
183}
184
185impl<'de> Deserialize<'de> for SharedString {
186 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
187 where
188 D: Deserializer<'de>,
189 {
190 let value = String::deserialize(deserializer)?;
191 Ok(value.into())
192 }
193}
194
195#[cfg(test)]
196mod tests {
197 use super::*;
198 use speedy::{Readable, Writable};
199
200 #[test]
201 fn test_shared_string_creation() {
202 let s1 = SharedString::new("hello");
203 let s2 = SharedString::from("world");
204 let s3: SharedString = "test".into();
205
206 assert_eq!(s1.as_str(), "hello");
207 assert_eq!(s2.as_str(), "world");
208 assert_eq!(s3.as_str(), "test");
209 }
210
211 #[test]
212 fn test_shared_string_equality() {
213 let s1 = SharedString::new("hello");
214 let s2 = SharedString::new("hello");
215 let s3 = SharedString::new("world");
216
217 assert_eq!(s1, s2);
218 assert_ne!(s1, s3);
219 }
220
221 #[test]
222 fn test_shared_string_clone() {
223 let s1 = SharedString::new("hello");
224 let s2 = s1.clone();
225
226 assert_eq!(s1, s2);
227 assert_eq!(s1.as_str(), s2.as_str());
228 }
229
230 #[test]
231 fn test_shared_string_default() {
232 let s = SharedString::default();
233 assert!(s.is_empty());
234 assert_eq!(s.len(), 0);
235 }
236
237 #[test]
238 fn test_shared_string_deref() {
239 let s = SharedString::new("hello");
240 assert_eq!(s.len(), 5);
241 assert_eq!(&s[0..2], "he");
242 }
243
244 #[test]
245 fn test_shared_string_display() {
246 let s = SharedString::new("hello");
247 assert_eq!(format!("{}", s), "hello");
248 }
249
250 #[test]
251 fn test_shared_string_speedy_serialization() {
252 let original = SharedString::new("hello world");
253
254 let buffer = original.write_to_vec().unwrap();
256 assert!(!buffer.is_empty());
257
258 let deserialized = SharedString::read_from_buffer(&buffer).unwrap();
260 assert_eq!(original, deserialized);
261 assert_eq!(deserialized.as_str(), "hello world");
262 }
263
264 #[test]
265 fn test_shared_string_speedy_empty_string() {
266 let original = SharedString::empty();
267
268 let buffer = original.write_to_vec().unwrap();
269 let deserialized = SharedString::read_from_buffer(&buffer).unwrap();
270
271 assert_eq!(original, deserialized);
272 assert!(deserialized.is_empty());
273 }
274
275 #[test]
276 fn test_shared_string_speedy_unicode() {
277 let original = SharedString::new("Hello π δΈη");
278
279 let buffer = original.write_to_vec().unwrap();
280 let deserialized = SharedString::read_from_buffer(&buffer).unwrap();
281
282 assert_eq!(original, deserialized);
283 assert_eq!(deserialized.as_str(), "Hello π δΈη");
284 }
285
286 #[test]
287 fn test_shared_string_format_macro() {
288 let name = "world";
289 let s = shared_format!("Hello, {}!", name);
290 assert_eq!(s.as_str(), "Hello, world!");
291 }
292
293 #[test]
294 fn test_shared_string_format_macro_multiple_args() {
295 let s = shared_format!("{} + {} = {}", 1, 2, 3);
296 assert_eq!(s.as_str(), "1 + 2 = 3");
297 }
298}