1use std::fmt;
2
3use crate::KStringBase;
4use crate::KStringCowBase;
5
6type StdString = std::string::String;
7type BoxedStr = Box<str>;
8
9#[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 #[inline]
25 #[must_use]
26 pub const fn new() -> Self {
27 Self::from_static("")
28 }
29
30 #[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 #[inline]
41 #[must_use]
42 pub fn from_ref(other: &'s str) -> Self {
43 Self {
44 inner: KStringRefInner::Borrowed(other),
45 }
46 }
47
48 #[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 #[inline]
58 #[must_use]
59 pub fn as_str(&self) -> &str {
60 self.inner.as_str()
61 }
62
63 #[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}