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 = "into-static")]
27use into_static::IntoStatic;
28
29#[cfg(feature = "serde")]
30use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
31
32#[cfg(all(feature = "serde", feature = "borrow"))]
33use serde::de::Visitor;
34
35use crate::{
36 empty::{Empty, check_str},
37 str::Str,
38};
39
40#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
42pub struct CowStr<'s> {
43 value: Cow<'s, str>,
44}
45
46#[cfg(feature = "serde")]
47impl Serialize for CowStr<'_> {
48 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
49 self.get().serialize(serializer)
50 }
51}
52
53#[cfg(all(feature = "serde", feature = "borrow"))]
54struct CowStrVisitor;
55
56#[cfg(all(feature = "serde", feature = "borrow"))]
57impl<'de> Visitor<'de> for CowStrVisitor {
58 type Value = CowStr<'de>;
59
60 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
61 formatter.write_str("non-empty string")
62 }
63
64 fn visit_borrowed_str<E: Error>(self, value: &'de str) -> Result<Self::Value, E> {
65 CowStr::borrowed(value).map_err(Error::custom)
66 }
67
68 fn visit_str<E: Error>(self, value: &str) -> Result<Self::Value, E> {
69 self.visit_string(value.to_owned())
70 }
71
72 fn visit_string<E: Error>(self, value: String) -> Result<Self::Value, E> {
73 CowStr::owned(value).map_err(Error::custom)
74 }
75}
76
77#[cfg(all(feature = "serde", feature = "borrow"))]
78impl<'de: 'c, 'c> Deserialize<'de> for CowStr<'c> {
79 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
80 deserializer.deserialize_str(CowStrVisitor)
81 }
82}
83
84#[cfg(all(feature = "serde", not(feature = "borrow")))]
85impl<'de> Deserialize<'de> for CowStr<'_> {
86 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
87 let value = Cow::deserialize(deserializer)?;
88
89 Self::new(value).map_err(Error::custom)
90 }
91}
92
93impl fmt::Display for CowStr<'_> {
94 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
95 self.get().fmt(formatter)
96 }
97}
98
99impl AsRef<str> for CowStr<'_> {
100 fn as_ref(&self) -> &str {
101 self.get()
102 }
103}
104
105impl Deref for CowStr<'_> {
106 type Target = str;
107
108 fn deref(&self) -> &Self::Target {
109 self.get()
110 }
111}
112
113impl<'s> TryFrom<Cow<'s, str>> for CowStr<'s> {
114 type Error = Empty;
115
116 fn try_from(value: Cow<'s, str>) -> Result<Self, Self::Error> {
117 Self::new(value)
118 }
119}
120
121impl<'s> TryFrom<&'s str> for CowStr<'s> {
122 type Error = Empty;
123
124 fn try_from(value: &'s str) -> Result<Self, Self::Error> {
125 Self::borrowed(value)
126 }
127}
128
129impl TryFrom<String> for CowStr<'_> {
130 type Error = Empty;
131
132 fn try_from(value: String) -> Result<Self, Self::Error> {
133 Self::owned(value)
134 }
135}
136
137impl<'s> From<Str<'s>> for CowStr<'s> {
138 fn from(string: Str<'s>) -> Self {
139 Self::from_str(string)
140 }
141}
142
143impl<'s> From<CowStr<'s>> for Cow<'s, str> {
144 fn from(value: CowStr<'s>) -> Self {
145 value.take()
146 }
147}
148
149impl<'s> CowStr<'s> {
150 pub fn new(value: Cow<'s, str>) -> Result<Self, Empty> {
156 const_try!(check_str(value.as_ref()));
157
158 Ok(unsafe { Self::new_unchecked(value) })
159 }
160
161 pub fn new_ok(value: Cow<'s, str>) -> Option<Self> {
165 const_ok!(Self::new(value))
166 }
167
168 pub const unsafe fn new_unchecked(value: Cow<'s, str>) -> Self {
174 Self { value }
175 }
176
177 pub const fn borrowed(value: &'s str) -> Result<Self, Empty> {
185 const_try!(check_str(value));
186
187 Ok(unsafe { Self::borrowed_unchecked(value) })
189 }
190
191 pub const fn borrowed_ok(value: &'s str) -> Option<Self> {
195 const_none!(const_ok!(check_str(value)));
198
199 Some(unsafe { Self::borrowed_unchecked(value) })
200 }
201
202 pub const unsafe fn borrowed_unchecked(value: &'s str) -> Self {
210 unsafe { Self::new_unchecked(Cow::Borrowed(value)) }
212 }
213
214 pub fn owned(value: String) -> Result<Self, Empty> {
222 const_try!(check_str(value.as_str()));
223
224 Ok(unsafe { Self::owned_unchecked(value) })
226 }
227
228 pub fn owned_ok(value: String) -> Option<Self> {
232 const_ok!(Self::owned(value))
233 }
234
235 pub const unsafe fn owned_unchecked(value: String) -> Self {
243 unsafe { Self::new_unchecked(Cow::Owned(value)) }
244 }
245
246 #[cfg(feature = "unsafe-assert")]
247 fn assert_non_empty(&self) {
248 unsafe { assert_unchecked(!self.value.is_empty()) }
249 }
250
251 pub fn take(self) -> Cow<'s, str> {
253 #[cfg(feature = "unsafe-assert")]
254 self.assert_non_empty();
255
256 self.value
257 }
258
259 pub const fn from_str(string: Str<'s>) -> Self {
261 unsafe { Self::borrowed_unchecked(string.take()) }
263 }
264}
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
276#[cfg(feature = "into-static")]
277impl IntoStatic for CowStr<'_> {
278 type Static = CowStr<'static>;
279
280 fn into_static(self) -> Self::Static {
281 unsafe { Self::Static::new_unchecked(self.take().into_static()) }
283 }
284}