Skip to main content

radiate_utils/
str.rs

1use crate::ToSnakeCase;
2use std::borrow::Cow;
3
4type Inner = compact_str::CompactString;
5
6#[derive(Clone, Eq, Hash, PartialOrd, Ord)]
7#[cfg_attr(
8    feature = "serde",
9    derive(serde::Serialize, serde::Deserialize),
10    serde(transparent)
11)]
12#[repr(transparent)]
13pub struct SmallStr(Inner);
14
15impl SmallStr {
16    pub const EMPTY: Self = Self::from_static("");
17    pub const EMPTY_REF: &'static Self = &Self::from_static("");
18
19    #[inline(always)]
20    pub const fn from_static(s: &'static str) -> Self {
21        Self(Inner::const_new(s))
22    }
23
24    #[inline(always)]
25    pub fn from_string(s: String) -> Self {
26        Self(Inner::from(s))
27    }
28
29    #[inline(always)]
30    pub fn as_str(&self) -> &str {
31        self.0.as_str()
32    }
33
34    #[inline(always)]
35    pub fn as_mut_str(&mut self) -> &mut str {
36        self.0.as_mut_str()
37    }
38
39    #[inline(always)]
40    #[allow(clippy::inherent_to_string_shadow_display)] // This is faster.
41    pub fn to_string(&self) -> String {
42        self.0.as_str().to_owned()
43    }
44
45    #[inline(always)]
46    pub fn into_string(self) -> String {
47        self.0.into_string()
48    }
49
50    #[inline(always)]
51    pub fn contains(&self, pat: impl AsRef<str>) -> bool {
52        self.as_str().contains(pat.as_ref())
53    }
54}
55
56impl Default for SmallStr {
57    #[inline(always)]
58    fn default() -> Self {
59        Self::EMPTY
60    }
61}
62
63impl ToSnakeCase<SmallStr> for SmallStr {
64    fn to_snake_case(&self) -> SmallStr {
65        self.as_str().to_snake_case().into()
66    }
67}
68
69// AsRef, Borrow, Deref impls
70
71impl AsRef<str> for SmallStr {
72    #[inline(always)]
73    fn as_ref(&self) -> &str {
74        self.as_str()
75    }
76}
77
78impl core::ops::Deref for SmallStr {
79    type Target = str;
80
81    #[inline(always)]
82    fn deref(&self) -> &Self::Target {
83        self.as_str()
84    }
85}
86
87impl core::ops::DerefMut for SmallStr {
88    #[inline(always)]
89    fn deref_mut(&mut self) -> &mut Self::Target {
90        self.as_mut_str()
91    }
92}
93
94impl core::borrow::Borrow<str> for SmallStr {
95    #[inline(always)]
96    fn borrow(&self) -> &str {
97        self.as_str()
98    }
99}
100
101// AsRef impls
102
103impl AsRef<std::path::Path> for SmallStr {
104    #[inline(always)]
105    fn as_ref(&self) -> &std::path::Path {
106        self.as_str().as_ref()
107    }
108}
109
110impl AsRef<[u8]> for SmallStr {
111    #[inline(always)]
112    fn as_ref(&self) -> &[u8] {
113        self.as_str().as_bytes()
114    }
115}
116
117impl AsRef<std::ffi::OsStr> for SmallStr {
118    #[inline(always)]
119    fn as_ref(&self) -> &std::ffi::OsStr {
120        self.as_str().as_ref()
121    }
122}
123
124// From impls
125
126impl From<&str> for SmallStr {
127    #[inline(always)]
128    fn from(value: &str) -> Self {
129        Self(Inner::from(value))
130    }
131}
132
133impl From<&&str> for SmallStr {
134    #[inline(always)]
135    fn from(value: &&str) -> Self {
136        Self(Inner::from(*value))
137    }
138}
139
140impl From<String> for SmallStr {
141    #[inline(always)]
142    fn from(value: String) -> Self {
143        Self::from_string(value)
144    }
145}
146
147impl From<SmallStr> for String {
148    #[inline(always)]
149    fn from(value: SmallStr) -> Self {
150        value.to_string()
151    }
152}
153
154impl From<Cow<'_, str>> for SmallStr {
155    #[inline(always)]
156    fn from(value: Cow<str>) -> Self {
157        Self(Inner::from(value))
158    }
159}
160
161impl From<&String> for SmallStr {
162    #[inline(always)]
163    fn from(value: &String) -> Self {
164        Self(Inner::from(value.as_str()))
165    }
166}
167
168impl From<Inner> for SmallStr {
169    #[inline(always)]
170    fn from(value: Inner) -> Self {
171        Self(value)
172    }
173}
174
175// FromIterator impls
176
177impl FromIterator<SmallStr> for SmallStr {
178    #[inline(always)]
179    fn from_iter<T: IntoIterator<Item = SmallStr>>(iter: T) -> Self {
180        Self(Inner::from_iter(iter.into_iter().map(|x| x.0)))
181    }
182}
183
184impl<'a> FromIterator<&'a SmallStr> for SmallStr {
185    #[inline(always)]
186    fn from_iter<T: IntoIterator<Item = &'a SmallStr>>(iter: T) -> Self {
187        Self(Inner::from_iter(iter.into_iter().map(|x| x.as_str())))
188    }
189}
190
191impl FromIterator<char> for SmallStr {
192    #[inline(always)]
193    fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> SmallStr {
194        Self(Inner::from_iter(iter))
195    }
196}
197
198impl<'a> FromIterator<&'a char> for SmallStr {
199    #[inline(always)]
200    fn from_iter<I: IntoIterator<Item = &'a char>>(iter: I) -> SmallStr {
201        Self(Inner::from_iter(iter))
202    }
203}
204
205impl<'a> FromIterator<&'a str> for SmallStr {
206    #[inline(always)]
207    fn from_iter<I: IntoIterator<Item = &'a str>>(iter: I) -> SmallStr {
208        Self(Inner::from_iter(iter))
209    }
210}
211
212impl FromIterator<String> for SmallStr {
213    #[inline(always)]
214    fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> SmallStr {
215        Self(Inner::from_iter(iter))
216    }
217}
218
219impl FromIterator<Box<str>> for SmallStr {
220    #[inline(always)]
221    fn from_iter<I: IntoIterator<Item = Box<str>>>(iter: I) -> SmallStr {
222        Self(Inner::from_iter(iter))
223    }
224}
225
226impl<'a> FromIterator<std::borrow::Cow<'a, str>> for SmallStr {
227    #[inline(always)]
228    fn from_iter<I: IntoIterator<Item = std::borrow::Cow<'a, str>>>(iter: I) -> SmallStr {
229        Self(Inner::from_iter(iter))
230    }
231}
232
233// PartialEq impls
234
235impl<T> PartialEq<T> for SmallStr
236where
237    T: AsRef<str> + ?Sized,
238{
239    #[inline(always)]
240    fn eq(&self, other: &T) -> bool {
241        self.as_str() == other.as_ref()
242    }
243}
244
245impl PartialEq<SmallStr> for &str {
246    #[inline(always)]
247    fn eq(&self, other: &SmallStr) -> bool {
248        *self == other.as_str()
249    }
250}
251
252impl PartialEq<SmallStr> for String {
253    #[inline(always)]
254    fn eq(&self, other: &SmallStr) -> bool {
255        self.as_str() == other.as_str()
256    }
257}
258
259// Write
260
261impl core::fmt::Write for SmallStr {
262    #[inline(always)]
263    fn write_char(&mut self, c: char) -> std::fmt::Result {
264        self.0.write_char(c)
265    }
266
267    #[inline(always)]
268    fn write_fmt(&mut self, args: std::fmt::Arguments<'_>) -> std::fmt::Result {
269        self.0.write_fmt(args)
270    }
271
272    #[inline(always)]
273    fn write_str(&mut self, s: &str) -> std::fmt::Result {
274        self.0.write_str(s)
275    }
276}
277
278// Debug, Display
279
280impl core::fmt::Debug for SmallStr {
281    #[inline(always)]
282    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
283        self.as_str().fmt(f)
284    }
285}
286
287impl core::fmt::Display for SmallStr {
288    #[inline(always)]
289    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
290        self.as_str().fmt(f)
291    }
292}