kstring/
string_ref.rs

1use std::fmt;
2
3use crate::KStringBase;
4use crate::KStringCowBase;
5
6type StdString = std::string::String;
7type BoxedStr = Box<str>;
8
9/// A reference to a UTF-8 encoded, immutable string.
10#[derive(Copy, Clone)]
11#[repr(transparent)]
12pub struct KStringRef<'s> {
13    pub(crate) inner: KStringRefInner<'s>,
14}
15
16#[derive(Copy, Clone, Debug)]
17pub(crate) enum KStringRefInner<'s> {
18    Borrowed(&'s str),
19    Singleton(&'static str),
20}
21
22impl<'s> KStringRef<'s> {
23    /// Create a new empty `KStringBase`.
24    #[inline]
25    #[must_use]
26    pub const fn new() -> Self {
27        Self::from_static("")
28    }
29
30    /// Create a reference to a `'static` data.
31    #[inline]
32    #[must_use]
33    pub const fn from_static(other: &'static str) -> Self {
34        Self {
35            inner: KStringRefInner::Singleton(other),
36        }
37    }
38
39    /// Create a reference to a borrowed data.
40    #[inline]
41    #[must_use]
42    pub fn from_ref(other: &'s str) -> Self {
43        Self {
44            inner: KStringRefInner::Borrowed(other),
45        }
46    }
47
48    /// Clone the data into an owned-type.
49    #[inline]
50    #[must_use]
51    #[allow(clippy::wrong_self_convention)]
52    pub fn to_owned<B: crate::backend::HeapStr>(&self) -> KStringBase<B> {
53        self.inner.to_owned()
54    }
55
56    /// Extracts a string slice containing the entire `KStringRef`.
57    #[inline]
58    #[must_use]
59    pub fn as_str(&self) -> &str {
60        self.inner.as_str()
61    }
62
63    /// Convert to a mutable string type, cloning the data if necessary.
64    #[inline]
65    #[must_use]
66    pub fn into_mut(self) -> StdString {
67        self.inner.into_mut()
68    }
69}
70
71impl<'s> KStringRefInner<'s> {
72    #[inline]
73    #[allow(clippy::wrong_self_convention)]
74    fn to_owned<B: crate::backend::HeapStr>(&self) -> KStringBase<B> {
75        match self {
76            Self::Borrowed(s) => KStringBase::from_ref(s),
77            Self::Singleton(s) => KStringBase::from_static(s),
78        }
79    }
80
81    #[inline]
82    fn as_str(&self) -> &str {
83        match self {
84            Self::Borrowed(s) => s,
85            Self::Singleton(s) => s,
86        }
87    }
88
89    #[inline]
90    fn into_mut(self) -> StdString {
91        self.as_str().to_owned()
92    }
93}
94
95impl<'s> std::ops::Deref for KStringRef<'s> {
96    type Target = str;
97
98    #[inline]
99    fn deref(&self) -> &str {
100        self.as_str()
101    }
102}
103
104impl<'s> Eq for KStringRef<'s> {}
105
106impl<'s> PartialEq<KStringRef<'s>> for KStringRef<'s> {
107    #[inline]
108    fn eq(&self, other: &KStringRef<'s>) -> bool {
109        PartialEq::eq(self.as_str(), other.as_str())
110    }
111}
112
113impl<'s> PartialEq<str> for KStringRef<'s> {
114    #[inline]
115    fn eq(&self, other: &str) -> bool {
116        PartialEq::eq(self.as_str(), other)
117    }
118}
119
120impl<'s> PartialEq<&'s str> for KStringRef<'s> {
121    #[inline]
122    fn eq(&self, other: &&str) -> bool {
123        PartialEq::eq(self.as_str(), *other)
124    }
125}
126
127impl<'s> PartialEq<String> for KStringRef<'s> {
128    #[inline]
129    fn eq(&self, other: &StdString) -> bool {
130        PartialEq::eq(self.as_str(), other.as_str())
131    }
132}
133
134impl<'s> Ord for KStringRef<'s> {
135    #[inline]
136    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
137        self.as_str().cmp(other.as_str())
138    }
139}
140
141impl<'s> PartialOrd for KStringRef<'s> {
142    #[inline]
143    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
144        Some(self.cmp(other))
145    }
146}
147
148impl<'s> std::hash::Hash for KStringRef<'s> {
149    #[inline]
150    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
151        self.as_str().hash(state);
152    }
153}
154
155impl<'s> fmt::Debug for KStringRef<'s> {
156    #[inline]
157    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158        fmt::Debug::fmt(&self.inner, f)
159    }
160}
161
162impl<'s> fmt::Display for KStringRef<'s> {
163    #[inline]
164    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
165        fmt::Display::fmt(self.as_str(), f)
166    }
167}
168
169impl<'s> AsRef<str> for KStringRef<'s> {
170    #[inline]
171    fn as_ref(&self) -> &str {
172        self.as_str()
173    }
174}
175
176impl<'s> AsRef<[u8]> for KStringRef<'s> {
177    #[inline]
178    fn as_ref(&self) -> &[u8] {
179        self.as_bytes()
180    }
181}
182
183impl<'s> AsRef<std::ffi::OsStr> for KStringRef<'s> {
184    #[inline]
185    fn as_ref(&self) -> &std::ffi::OsStr {
186        (**self).as_ref()
187    }
188}
189
190impl<'s> AsRef<std::path::Path> for KStringRef<'s> {
191    #[inline]
192    fn as_ref(&self) -> &std::path::Path {
193        std::path::Path::new(self)
194    }
195}
196
197impl<'s> std::borrow::Borrow<str> for KStringRef<'s> {
198    #[inline]
199    fn borrow(&self) -> &str {
200        self.as_str()
201    }
202}
203
204impl<'s> Default for KStringRef<'s> {
205    #[inline]
206    fn default() -> Self {
207        Self::new()
208    }
209}
210
211impl<'s, B: crate::backend::HeapStr> From<&'s KStringBase<B>> for KStringRef<'s> {
212    #[inline]
213    fn from(other: &'s KStringBase<B>) -> Self {
214        other.as_ref()
215    }
216}
217
218impl<'s, B: crate::backend::HeapStr> From<&'s KStringCowBase<'s, B>> for KStringRef<'s> {
219    #[inline]
220    fn from(other: &'s KStringCowBase<'s, B>) -> Self {
221        other.as_ref()
222    }
223}
224
225impl<'s> From<&'s StdString> for KStringRef<'s> {
226    #[inline]
227    fn from(other: &'s StdString) -> Self {
228        KStringRef::from_ref(other.as_str())
229    }
230}
231
232impl<'s> From<&'s BoxedStr> for KStringRef<'s> {
233    #[inline]
234    fn from(other: &'s BoxedStr) -> Self {
235        Self::from_ref(other)
236    }
237}
238
239impl<'s> From<&'s str> for KStringRef<'s> {
240    #[inline]
241    fn from(other: &'s str) -> Self {
242        KStringRef::from_ref(other)
243    }
244}
245
246#[cfg(feature = "serde")]
247impl<'s> serde::Serialize for KStringRef<'s> {
248    #[inline]
249    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
250    where
251        S: serde::Serializer,
252    {
253        serializer.serialize_str(self.as_str())
254    }
255}
256
257#[cfg(feature = "serde")]
258impl<'de: 's, 's> serde::Deserialize<'de> for KStringRef<'s> {
259    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
260    where
261        D: serde::Deserializer<'de>,
262    {
263        let s: &'s str = serde::Deserialize::deserialize(deserializer)?;
264        let s = KStringRef::from_ref(s);
265        Ok(s)
266    }
267}
268
269#[cfg(test)]
270mod test {
271    use super::*;
272
273    #[test]
274    fn test_size() {
275        println!("KStringRef: {}", std::mem::size_of::<KStringRef<'static>>());
276    }
277}