kstring/
string_cow.rs

1use std::{borrow::Cow, fmt};
2
3use crate::KStringBase;
4use crate::KStringRef;
5use crate::KStringRefInner;
6
7type StdString = std::string::String;
8type BoxedStr = Box<str>;
9
10/// A reference to a UTF-8 encoded, immutable string.
11pub type KStringCow<'s> = KStringCowBase<'s, crate::backend::DefaultStr>;
12
13/// A reference to a UTF-8 encoded, immutable string.
14#[derive(Clone)]
15#[repr(transparent)]
16pub struct KStringCowBase<'s, B = crate::backend::DefaultStr> {
17    pub(crate) inner: KStringCowInner<'s, B>,
18}
19
20#[derive(Clone)]
21pub(crate) enum KStringCowInner<'s, B> {
22    Borrowed(&'s str),
23    Owned(KStringBase<B>),
24}
25
26impl<'s, B> KStringCowBase<'s, B> {
27    /// Create a new empty `KStringCowBase`.
28    #[inline]
29    #[must_use]
30    pub const fn new() -> Self {
31        Self::from_static("")
32    }
33
34    /// Create a reference to a `'static` data.
35    #[inline]
36    #[must_use]
37    pub const fn from_static(other: &'static str) -> Self {
38        Self {
39            inner: KStringCowInner::Owned(KStringBase::from_static(other)),
40        }
41    }
42}
43
44impl<'s, B: crate::backend::HeapStr> KStringCowBase<'s, B> {
45    /// Create an owned `KStringCowBase`.
46    #[inline]
47    #[must_use]
48    pub fn from_boxed(other: BoxedStr) -> Self {
49        Self {
50            inner: KStringCowInner::Owned(KStringBase::from_boxed(other)),
51        }
52    }
53
54    /// Create an owned `KStringCowBase`.
55    #[inline]
56    #[must_use]
57    pub fn from_string(other: StdString) -> Self {
58        Self {
59            inner: KStringCowInner::Owned(KStringBase::from_string(other)),
60        }
61    }
62
63    /// Create a reference to a borrowed data.
64    #[inline]
65    #[must_use]
66    pub fn from_ref(other: &'s str) -> Self {
67        Self {
68            inner: KStringCowInner::Borrowed(other),
69        }
70    }
71
72    /// Get a reference to the `KStringBase`.
73    #[inline]
74    #[must_use]
75    pub fn as_ref(&self) -> KStringRef<'_> {
76        self.inner.as_ref()
77    }
78
79    /// Clone the data into an owned-type.
80    #[inline]
81    #[must_use]
82    pub fn into_owned(self) -> KStringBase<B> {
83        self.inner.into_owned()
84    }
85
86    /// Extracts a string slice containing the entire `KStringCowBase`.
87    #[inline]
88    #[must_use]
89    pub fn as_str(&self) -> &str {
90        self.inner.as_str()
91    }
92
93    /// Convert to a mutable string type, cloning the data if necessary.
94    #[inline]
95    #[must_use]
96    pub fn into_string(self) -> StdString {
97        String::from(self.into_boxed_str())
98    }
99
100    /// Convert to a mutable string type, cloning the data if necessary.
101    #[inline]
102    #[must_use]
103    pub fn into_boxed_str(self) -> BoxedStr {
104        self.inner.into_boxed_str()
105    }
106
107    /// Convert to a Cow str
108    #[inline]
109    #[must_use]
110    pub fn into_cow_str(self) -> Cow<'s, str> {
111        self.inner.into_cow_str()
112    }
113}
114
115impl<'s, B: crate::backend::HeapStr> KStringCowInner<'s, B> {
116    #[inline]
117    fn as_ref(&self) -> KStringRef<'_> {
118        match self {
119            Self::Borrowed(s) => KStringRef::from_ref(s),
120            Self::Owned(s) => s.as_ref(),
121        }
122    }
123
124    #[inline]
125    fn into_owned(self) -> KStringBase<B> {
126        match self {
127            Self::Borrowed(s) => KStringBase::from_ref(s),
128            Self::Owned(s) => s,
129        }
130    }
131
132    #[inline]
133    fn as_str(&self) -> &str {
134        match self {
135            Self::Borrowed(s) => s,
136            Self::Owned(s) => s.as_str(),
137        }
138    }
139
140    #[inline]
141    fn into_boxed_str(self) -> BoxedStr {
142        match self {
143            Self::Borrowed(s) => BoxedStr::from(s),
144            Self::Owned(s) => s.into_boxed_str(),
145        }
146    }
147
148    /// Convert to a Cow str
149    #[inline]
150    fn into_cow_str(self) -> Cow<'s, str> {
151        match self {
152            Self::Borrowed(s) => Cow::Borrowed(s),
153            Self::Owned(s) => s.into_cow_str(),
154        }
155    }
156}
157
158impl<'s, B: crate::backend::HeapStr> std::ops::Deref for KStringCowBase<'s, B> {
159    type Target = str;
160
161    #[inline]
162    fn deref(&self) -> &str {
163        self.as_str()
164    }
165}
166
167impl<'s, B: crate::backend::HeapStr> Eq for KStringCowBase<'s, B> {}
168
169impl<'s, B: crate::backend::HeapStr> PartialEq<KStringCowBase<'s, B>> for KStringCowBase<'s, B> {
170    #[inline]
171    fn eq(&self, other: &KStringCowBase<'s, B>) -> bool {
172        PartialEq::eq(self.as_str(), other.as_str())
173    }
174}
175
176impl<'s, B: crate::backend::HeapStr> PartialEq<str> for KStringCowBase<'s, B> {
177    #[inline]
178    fn eq(&self, other: &str) -> bool {
179        PartialEq::eq(self.as_str(), other)
180    }
181}
182
183impl<'s, B: crate::backend::HeapStr> PartialEq<&'s str> for KStringCowBase<'s, B> {
184    #[inline]
185    fn eq(&self, other: &&str) -> bool {
186        PartialEq::eq(self.as_str(), *other)
187    }
188}
189
190impl<'s, B: crate::backend::HeapStr> PartialEq<String> for KStringCowBase<'s, B> {
191    #[inline]
192    fn eq(&self, other: &StdString) -> bool {
193        PartialEq::eq(self.as_str(), other.as_str())
194    }
195}
196
197impl<'s, B: crate::backend::HeapStr> Ord for KStringCowBase<'s, B> {
198    #[inline]
199    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
200        self.as_str().cmp(other.as_str())
201    }
202}
203
204impl<'s, B: crate::backend::HeapStr> PartialOrd for KStringCowBase<'s, B> {
205    #[inline]
206    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
207        Some(self.cmp(other))
208    }
209}
210
211impl<'s, B: crate::backend::HeapStr> std::hash::Hash for KStringCowBase<'s, B> {
212    #[inline]
213    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
214        self.as_str().hash(state);
215    }
216}
217
218impl<'s, B: crate::backend::HeapStr> fmt::Debug for KStringCowBase<'s, B> {
219    #[inline]
220    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
221        self.as_str().fmt(f)
222    }
223}
224
225impl<'s, B: crate::backend::HeapStr> fmt::Display for KStringCowBase<'s, B> {
226    #[inline]
227    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228        fmt::Display::fmt(self.as_str(), f)
229    }
230}
231
232impl<'s, B: crate::backend::HeapStr> AsRef<str> for KStringCowBase<'s, B> {
233    #[inline]
234    fn as_ref(&self) -> &str {
235        self.as_str()
236    }
237}
238
239impl<'s, B: crate::backend::HeapStr> AsRef<[u8]> for KStringCowBase<'s, B> {
240    #[inline]
241    fn as_ref(&self) -> &[u8] {
242        self.as_bytes()
243    }
244}
245
246impl<'s, B: crate::backend::HeapStr> AsRef<std::ffi::OsStr> for KStringCowBase<'s, B> {
247    #[inline]
248    fn as_ref(&self) -> &std::ffi::OsStr {
249        (**self).as_ref()
250    }
251}
252
253impl<'s, B: crate::backend::HeapStr> AsRef<std::path::Path> for KStringCowBase<'s, B> {
254    #[inline]
255    fn as_ref(&self) -> &std::path::Path {
256        std::path::Path::new(self)
257    }
258}
259
260impl<'s, B: crate::backend::HeapStr> std::borrow::Borrow<str> for KStringCowBase<'s, B> {
261    #[inline]
262    fn borrow(&self) -> &str {
263        self.as_str()
264    }
265}
266
267impl<'s, B> Default for KStringCowBase<'s, B> {
268    #[inline]
269    fn default() -> Self {
270        Self::new()
271    }
272}
273
274impl<'s, B: crate::backend::HeapStr> From<KStringBase<B>> for KStringCowBase<'s, B> {
275    #[inline]
276    fn from(other: KStringBase<B>) -> Self {
277        let inner = KStringCowInner::Owned(other);
278        Self { inner }
279    }
280}
281
282impl<'s, B: crate::backend::HeapStr> From<&'s KStringBase<B>> for KStringCowBase<'s, B> {
283    #[inline]
284    fn from(other: &'s KStringBase<B>) -> Self {
285        let other = other.as_ref();
286        other.into()
287    }
288}
289
290impl<'s, B: crate::backend::HeapStr> From<KStringRef<'s>> for KStringCowBase<'s, B> {
291    #[inline]
292    fn from(other: KStringRef<'s>) -> Self {
293        match other.inner {
294            KStringRefInner::Borrowed(s) => Self::from_ref(s),
295            KStringRefInner::Singleton(s) => Self::from_static(s),
296        }
297    }
298}
299
300impl<'s, B: crate::backend::HeapStr> From<&'s KStringRef<'s>> for KStringCowBase<'s, B> {
301    #[inline]
302    fn from(other: &'s KStringRef<'s>) -> Self {
303        match other.inner {
304            KStringRefInner::Borrowed(s) => Self::from_ref(s),
305            KStringRefInner::Singleton(s) => Self::from_static(s),
306        }
307    }
308}
309
310impl<'s, B: crate::backend::HeapStr> From<StdString> for KStringCowBase<'s, B> {
311    #[inline]
312    fn from(other: StdString) -> Self {
313        Self::from_string(other)
314    }
315}
316
317impl<'s, B: crate::backend::HeapStr> From<&'s StdString> for KStringCowBase<'s, B> {
318    #[inline]
319    fn from(other: &'s StdString) -> Self {
320        Self::from_ref(other.as_str())
321    }
322}
323
324impl<'s, B: crate::backend::HeapStr> From<BoxedStr> for KStringCowBase<'s, B> {
325    #[inline]
326    fn from(other: BoxedStr) -> Self {
327        // Since the memory is already allocated, don't bother moving it into a FixedString
328        Self::from_boxed(other)
329    }
330}
331
332impl<'s, B: crate::backend::HeapStr> From<&'s BoxedStr> for KStringCowBase<'s, B> {
333    #[inline]
334    fn from(other: &'s BoxedStr) -> Self {
335        Self::from_ref(other)
336    }
337}
338
339impl<'s, B: crate::backend::HeapStr> From<&'s str> for KStringCowBase<'s, B> {
340    #[inline]
341    fn from(other: &'s str) -> Self {
342        Self::from_ref(other)
343    }
344}
345
346impl<B: crate::backend::HeapStr> std::str::FromStr for KStringCowBase<'_, B> {
347    type Err = std::convert::Infallible;
348    #[inline]
349    fn from_str(s: &str) -> Result<Self, Self::Err> {
350        Ok(Self::from_string(s.into()))
351    }
352}
353
354#[cfg(feature = "serde")]
355impl<'s, B: crate::backend::HeapStr> serde::Serialize for KStringCowBase<'s, B> {
356    #[inline]
357    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
358    where
359        S: serde::Serializer,
360    {
361        serializer.serialize_str(self.as_str())
362    }
363}
364
365#[cfg(feature = "serde")]
366impl<'de, 's, B: crate::backend::HeapStr> serde::Deserialize<'de> for KStringCowBase<'s, B> {
367    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
368    where
369        D: serde::Deserializer<'de>,
370    {
371        KStringBase::deserialize(deserializer).map(|s| s.into())
372    }
373}
374
375#[cfg(test)]
376mod test {
377    use super::*;
378
379    #[test]
380    fn test_size() {
381        println!("KStringCow: {}", std::mem::size_of::<KStringCow<'static>>());
382    }
383}