kstring/
cow.rs

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