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#[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 #[inline]
26 pub fn new() -> Self {
27 Default::default()
28 }
29
30 #[inline]
32 pub fn from_boxed(other: BoxedStr) -> Self {
33 Self {
34 inner: KStringCowInner::Owned(KString::from_boxed(other)),
35 }
36 }
37
38 #[inline]
40 pub fn from_string(other: StdString) -> Self {
41 Self {
42 inner: KStringCowInner::Owned(KString::from_string(other)),
43 }
44 }
45
46 #[inline]
48 pub fn from_ref(other: &'s str) -> Self {
49 Self {
50 inner: KStringCowInner::Borrowed(other),
51 }
52 }
53
54 #[inline]
56 pub fn from_static(other: &'static str) -> Self {
57 Self {
58 inner: KStringCowInner::Owned(KString::from_static(other)),
59 }
60 }
61
62 #[inline]
64 pub fn as_ref(&self) -> KStringRef<'_> {
65 self.inner.as_ref()
66 }
67
68 #[inline]
70 pub fn into_owned(self) -> KString {
71 self.inner.into_owned()
72 }
73
74 #[inline]
76 pub fn as_str(&self) -> &str {
77 self.inner.as_str()
78 }
79
80 #[inline]
82 pub fn into_string(self) -> StdString {
83 String::from(self.into_boxed_str())
84 }
85
86 #[inline]
88 pub fn into_boxed_str(self) -> BoxedStr {
89 self.inner.into_boxed_str()
90 }
91
92 #[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 #[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 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}