polars_utils/
pl_str.rs

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