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