1#[cfg(feature = "unsafe-assert")]
6use core::hint::assert_unchecked;
7
8use core::{fmt, ops::Deref};
9
10#[cfg(feature = "std")]
11use std::borrow::Cow;
12
13#[cfg(all(not(feature = "std"), feature = "alloc"))]
14use alloc::{borrow::Cow, string::String};
15
16#[cfg(all(
17 not(feature = "std"),
18 feature = "alloc",
19 feature = "serde",
20 feature = "borrow"
21))]
22use alloc::borrow::ToOwned;
23
24use const_macros::{const_none, const_ok, const_try};
25
26#[cfg(feature = "serde")]
27use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
28
29#[cfg(all(feature = "serde", feature = "borrow"))]
30use serde::de::Visitor;
31
32use crate::{
33 empty::{Empty, check_str},
34 str::Str,
35};
36
37#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
39pub struct CowStr<'s> {
40 value: Cow<'s, str>,
41}
42
43#[cfg(feature = "serde")]
44impl Serialize for CowStr<'_> {
45 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
46 self.get().serialize(serializer)
47 }
48}
49
50#[cfg(all(feature = "serde", feature = "borrow"))]
51struct CowStrVisitor;
52
53#[cfg(all(feature = "serde", feature = "borrow"))]
54impl<'de> Visitor<'de> for CowStrVisitor {
55 type Value = CowStr<'de>;
56
57 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
58 formatter.write_str("non-empty string")
59 }
60
61 fn visit_borrowed_str<E: Error>(self, value: &'de str) -> Result<Self::Value, E> {
62 CowStr::borrowed(value).map_err(Error::custom)
63 }
64
65 fn visit_str<E: Error>(self, value: &str) -> Result<Self::Value, E> {
66 self.visit_string(value.to_owned())
67 }
68
69 fn visit_string<E: Error>(self, value: String) -> Result<Self::Value, E> {
70 CowStr::owned(value).map_err(Error::custom)
71 }
72}
73
74#[cfg(all(feature = "serde", feature = "borrow"))]
75impl<'de: 'c, 'c> Deserialize<'de> for CowStr<'c> {
76 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
77 deserializer.deserialize_str(CowStrVisitor)
78 }
79}
80
81#[cfg(all(feature = "serde", not(feature = "borrow")))]
82impl<'de> Deserialize<'de> for CowStr<'_> {
83 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
84 let value = Cow::deserialize(deserializer)?;
85
86 Self::new(value).map_err(Error::custom)
87 }
88}
89
90impl fmt::Display for CowStr<'_> {
91 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
92 self.get().fmt(formatter)
93 }
94}
95
96impl AsRef<str> for CowStr<'_> {
97 fn as_ref(&self) -> &str {
98 self.get()
99 }
100}
101
102impl Deref for CowStr<'_> {
103 type Target = str;
104
105 fn deref(&self) -> &Self::Target {
106 self.get()
107 }
108}
109
110impl<'s> TryFrom<Cow<'s, str>> for CowStr<'s> {
111 type Error = Empty;
112
113 fn try_from(value: Cow<'s, str>) -> Result<Self, Self::Error> {
114 Self::new(value)
115 }
116}
117
118impl<'s> TryFrom<&'s str> for CowStr<'s> {
119 type Error = Empty;
120
121 fn try_from(value: &'s str) -> Result<Self, Self::Error> {
122 Self::borrowed(value)
123 }
124}
125
126impl TryFrom<String> for CowStr<'_> {
127 type Error = Empty;
128
129 fn try_from(value: String) -> Result<Self, Self::Error> {
130 Self::owned(value)
131 }
132}
133
134impl<'s> From<Str<'s>> for CowStr<'s> {
135 fn from(string: Str<'s>) -> Self {
136 Self::from_str(string)
137 }
138}
139
140impl<'s> From<CowStr<'s>> for Cow<'s, str> {
141 fn from(value: CowStr<'s>) -> Self {
142 value.take()
143 }
144}
145
146impl<'s> CowStr<'s> {
147 pub fn new(value: Cow<'s, str>) -> Result<Self, Empty> {
153 const_try!(check_str(value.as_ref()));
154
155 Ok(unsafe { Self::new_unchecked(value) })
156 }
157
158 pub fn new_ok(value: Cow<'s, str>) -> Option<Self> {
162 const_ok!(Self::new(value))
163 }
164
165 pub const unsafe fn new_unchecked(value: Cow<'s, str>) -> Self {
171 Self { value }
172 }
173
174 pub const fn borrowed(value: &'s str) -> Result<Self, Empty> {
182 const_try!(check_str(value));
183
184 Ok(unsafe { Self::borrowed_unchecked(value) })
186 }
187
188 pub const fn borrowed_ok(value: &'s str) -> Option<Self> {
192 const_none!(const_ok!(check_str(value)));
195
196 Some(unsafe { Self::borrowed_unchecked(value) })
197 }
198
199 pub const unsafe fn borrowed_unchecked(value: &'s str) -> Self {
207 unsafe { Self::new_unchecked(Cow::Borrowed(value)) }
209 }
210
211 pub fn owned(value: String) -> Result<Self, Empty> {
219 const_try!(check_str(value.as_str()));
220
221 Ok(unsafe { Self::owned_unchecked(value) })
223 }
224
225 pub fn owned_ok(value: String) -> Option<Self> {
229 const_ok!(Self::owned(value))
230 }
231
232 pub const unsafe fn owned_unchecked(value: String) -> Self {
240 unsafe { Self::new_unchecked(Cow::Owned(value)) }
241 }
242
243 #[cfg(feature = "unsafe-assert")]
244 fn assert_non_empty(&self) {
245 unsafe { assert_unchecked(!self.value.is_empty()) }
246 }
247
248 pub fn take(self) -> Cow<'s, str> {
250 #[cfg(feature = "unsafe-assert")]
251 self.assert_non_empty();
252
253 self.value
254 }
255
256 pub const fn from_str(string: Str<'s>) -> Self {
258 unsafe { Self::borrowed_unchecked(string.take()) }
260 }
261}
262
263pub type StaticCowStr = CowStr<'static>;
265
266impl CowStr<'_> {
267 pub fn get(&self) -> &str {
269 #[cfg(feature = "unsafe-assert")]
270 self.assert_non_empty();
271
272 self.value.as_ref()
273 }
274
275 pub fn into_static(self) -> StaticCowStr {
277 unsafe { StaticCowStr::owned_unchecked(self.take().into_owned()) }
279 }
280}