1#[cfg(not(any(feature = "std", feature = "alloc")))]
4compile_error!("expected either `std` or `alloc` to be enabled");
5
6#[cfg(feature = "unsafe-assert")]
7use core::hint::assert_unchecked;
8
9use core::{fmt, ops::Deref};
10
11#[cfg(feature = "std")]
12use std::borrow::Cow;
13
14#[cfg(all(not(feature = "std"), feature = "alloc"))]
15use alloc::{borrow::Cow, string::String};
16
17#[cfg(all(
18 not(feature = "std"),
19 feature = "alloc",
20 feature = "serde",
21 feature = "borrow"
22))]
23use alloc::borrow::ToOwned;
24
25use const_macros::{const_early, const_ok, const_quick};
26
27#[cfg(feature = "static")]
28use into_static::IntoStatic;
29
30#[cfg(feature = "serde")]
31use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
32
33#[cfg(all(feature = "serde", feature = "borrow"))]
34use serde::de::Visitor;
35
36use crate::{empty::Empty, owned::OwnedStr, str::Str};
37
38#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
40pub struct CowStr<'s> {
41 value: Cow<'s, str>,
42}
43
44#[cfg(feature = "serde")]
45impl Serialize for CowStr<'_> {
46 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
47 self.get().serialize(serializer)
48 }
49}
50
51#[cfg(all(feature = "serde", feature = "borrow"))]
52struct CowStrVisitor;
53
54#[cfg(all(feature = "serde", feature = "borrow"))]
55impl<'de> Visitor<'de> for CowStrVisitor {
56 type Value = CowStr<'de>;
57
58 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
59 formatter.write_str("non-empty string")
60 }
61
62 fn visit_borrowed_str<E: Error>(self, value: &'de str) -> Result<Self::Value, E> {
63 CowStr::borrowed(value).map_err(Error::custom)
64 }
65
66 fn visit_str<E: Error>(self, value: &str) -> Result<Self::Value, E> {
67 self.visit_string(value.to_owned())
68 }
69
70 fn visit_string<E: Error>(self, value: String) -> Result<Self::Value, E> {
71 CowStr::owned(value).map_err(Error::custom)
72 }
73}
74
75#[cfg(all(feature = "serde", feature = "borrow"))]
76impl<'de: 'c, 'c> Deserialize<'de> for CowStr<'c> {
77 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
78 deserializer.deserialize_str(CowStrVisitor)
79 }
80}
81
82#[cfg(all(feature = "serde", not(feature = "borrow")))]
83impl<'de> Deserialize<'de> for CowStr<'_> {
84 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
85 let value = Cow::deserialize(deserializer)?;
86
87 Self::new(value).map_err(Error::custom)
88 }
89}
90
91impl fmt::Display for CowStr<'_> {
92 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
93 self.get().fmt(formatter)
94 }
95}
96
97impl AsRef<str> for CowStr<'_> {
98 fn as_ref(&self) -> &str {
99 self.get()
100 }
101}
102
103impl Deref for CowStr<'_> {
104 type Target = str;
105
106 fn deref(&self) -> &Self::Target {
107 self.get()
108 }
109}
110
111impl<'s> TryFrom<Cow<'s, str>> for CowStr<'s> {
112 type Error = Empty;
113
114 fn try_from(value: Cow<'s, str>) -> Result<Self, Self::Error> {
115 Self::new(value)
116 }
117}
118
119impl<'s> TryFrom<&'s str> for CowStr<'s> {
120 type Error = Empty;
121
122 fn try_from(value: &'s str) -> Result<Self, Self::Error> {
123 Self::borrowed(value)
124 }
125}
126
127impl TryFrom<String> for CowStr<'_> {
128 type Error = Empty;
129
130 fn try_from(value: String) -> Result<Self, Self::Error> {
131 Self::owned(value)
132 }
133}
134
135impl<'s> From<Str<'s>> for CowStr<'s> {
136 fn from(string: Str<'s>) -> Self {
137 Self::from_str(string)
138 }
139}
140
141impl From<OwnedStr> for CowStr<'_> {
142 fn from(string: OwnedStr) -> Self {
143 Self::from_owned_str(string)
144 }
145}
146
147impl<'s> From<CowStr<'s>> for Cow<'s, str> {
148 fn from(value: CowStr<'s>) -> Self {
149 value.take()
150 }
151}
152
153impl<'s> CowStr<'s> {
154 pub fn new(value: Cow<'s, str>) -> Result<Self, Empty> {
160 const_early!(value.is_empty() => Empty);
161
162 Ok(unsafe { Self::new_unchecked(value) })
164 }
165
166 pub fn new_ok(value: Cow<'s, str>) -> Option<Self> {
170 const_ok!(Self::new(value))
171 }
172
173 pub const unsafe fn new_unchecked(value: Cow<'s, str>) -> Self {
179 Self { value }
180 }
181
182 pub const fn borrowed(value: &'s str) -> Result<Self, Empty> {
190 const_early!(value.is_empty() => Empty);
191
192 Ok(unsafe { Self::borrowed_unchecked(value) })
194 }
195
196 pub const fn borrowed_ok(value: &'s str) -> Option<Self> {
200 const_quick!(value.is_empty());
201
202 Some(unsafe { Self::borrowed_unchecked(value) })
204 }
205
206 pub const unsafe fn borrowed_unchecked(value: &'s str) -> Self {
214 unsafe { Self::new_unchecked(Cow::Borrowed(value)) }
216 }
217
218 pub fn owned(value: String) -> Result<Self, Empty> {
226 const_early!(value.is_empty() => Empty);
227
228 Ok(unsafe { Self::owned_unchecked(value) })
230 }
231
232 pub fn owned_ok(value: String) -> Option<Self> {
236 const_ok!(Self::owned(value))
237 }
238
239 pub const unsafe fn owned_unchecked(value: String) -> Self {
247 unsafe { Self::new_unchecked(Cow::Owned(value)) }
249 }
250
251 #[cfg(feature = "unsafe-assert")]
252 fn assert_non_empty(&self) {
253 unsafe {
255 assert_unchecked(!self.value.is_empty());
256 }
257 }
258
259 pub fn take(self) -> Cow<'s, str> {
261 #[cfg(feature = "unsafe-assert")]
262 self.assert_non_empty();
263
264 self.value
265 }
266
267 pub const fn from_str(string: Str<'s>) -> Self {
269 unsafe { Self::borrowed_unchecked(string.take()) }
271 }
272
273 pub fn from_owned_str(string: OwnedStr) -> Self {
275 unsafe { Self::owned_unchecked(string.take()) }
277 }
278}
279
280impl CowStr<'_> {
281 pub fn get(&self) -> &str {
283 #[cfg(feature = "unsafe-assert")]
284 self.assert_non_empty();
285
286 self.value.as_ref()
287 }
288}
289
290#[cfg(feature = "static")]
292pub type StaticCowStr = CowStr<'static>;
293
294#[cfg(feature = "static")]
295impl IntoStatic for CowStr<'_> {
296 type Static = StaticCowStr;
297
298 fn into_static(self) -> Self::Static {
299 unsafe { Self::Static::new_unchecked(self.take().into_static()) }
301 }
302}