non_empty_str/
cow.rs

1//! Non-empty [`Cow<'_, str>`].
2//!
3//! [`Cow<'_, str>`]: Cow
4
5#[cfg(not(any(feature = "std", feature = "alloc")))]
6compile_error!("expected either `std` or `alloc` to be enabled");
7
8#[cfg(feature = "unsafe-assert")]
9use core::hint::assert_unchecked;
10
11use core::{fmt, ops::Deref};
12
13#[cfg(feature = "std")]
14use std::borrow::Cow;
15
16#[cfg(all(not(feature = "std"), feature = "alloc"))]
17use alloc::{borrow::Cow, string::String};
18
19#[cfg(all(
20    not(feature = "std"),
21    feature = "alloc",
22    feature = "serde",
23    feature = "borrow"
24))]
25use alloc::borrow::ToOwned;
26
27use const_macros::{const_early, const_ok, const_quick};
28
29#[cfg(feature = "into-static")]
30use into_static::IntoStatic;
31
32#[cfg(feature = "serde")]
33use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
34
35#[cfg(all(feature = "serde", feature = "borrow"))]
36use serde::de::Visitor;
37
38use crate::{empty::Empty, owned::OwnedStr, str::Str};
39
40/// Represents non-empty clone-on-write strings.
41#[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 From<OwnedStr> for CowStr<'_> {
144    fn from(string: OwnedStr) -> Self {
145        Self::from_owned_str(string)
146    }
147}
148
149impl<'s> From<CowStr<'s>> for Cow<'s, str> {
150    fn from(value: CowStr<'s>) -> Self {
151        value.take()
152    }
153}
154
155impl<'s> CowStr<'s> {
156    /// Constructs [`Self`], provided that the value is non-empty.
157    ///
158    /// # Errors
159    ///
160    /// Returns [`Empty`] if the string is empty.
161    pub fn new(value: Cow<'s, str>) -> Result<Self, Empty> {
162        const_early!(value.is_empty() => Empty);
163
164        // SAFETY: the value is non-empty at this point
165        Ok(unsafe { Self::new_unchecked(value) })
166    }
167
168    /// Similar to [`new`], except the error is discarded.
169    ///
170    /// [`new`]: Self::new
171    pub fn new_ok(value: Cow<'s, str>) -> Option<Self> {
172        const_ok!(Self::new(value))
173    }
174
175    /// Constructs [`Self`] without checking if the value is non-empty.
176    ///
177    /// # Safety
178    ///
179    /// The caller must ensure that the value is non-empty.
180    pub const unsafe fn new_unchecked(value: Cow<'s, str>) -> Self {
181        Self { value }
182    }
183
184    /// Similar to [`new`], but accepts borrowed strings.
185    ///
186    /// # Errors
187    ///
188    /// Returns [`Empty`] if the string is empty.
189    ///
190    /// [`new`]: Self::new
191    pub const fn borrowed(value: &'s str) -> Result<Self, Empty> {
192        const_early!(value.is_empty() => Empty);
193
194        // SAFETY: the value is non-empty at this point
195        Ok(unsafe { Self::borrowed_unchecked(value) })
196    }
197
198    /// Similar to [`borrowed`], but the error is discarded.
199    ///
200    /// [`borrowed`]: Self::borrowed
201    pub const fn borrowed_ok(value: &'s str) -> Option<Self> {
202        const_quick!(value.is_empty());
203
204        // SAFETY: the value is non-empty at this point
205        Some(unsafe { Self::borrowed_unchecked(value) })
206    }
207
208    /// Similar to [`new_unchecked`], but accepts borrowed strings.
209    ///
210    /// # Safety
211    ///
212    /// The caller must ensure that the value is non-empty.
213    ///
214    /// [`new_unchecked`]: Self::new_unchecked
215    pub const unsafe fn borrowed_unchecked(value: &'s str) -> Self {
216        // SAFETY: the caller must ensure that the value is non-empty
217        unsafe { Self::new_unchecked(Cow::Borrowed(value)) }
218    }
219
220    /// Similar to [`new`], but accepts owned strings.
221    ///
222    /// # Errors
223    ///
224    /// Returns [`Empty`] if the string is empty.
225    ///
226    /// [`new`]: Self::new
227    pub fn owned(value: String) -> Result<Self, Empty> {
228        const_early!(value.is_empty() => Empty);
229
230        // SAFETY: the value is non-empty at this point
231        Ok(unsafe { Self::owned_unchecked(value) })
232    }
233
234    /// Similar to [`owned`], except the error is discarded.
235    ///
236    /// [`owned`]: Self::owned
237    pub fn owned_ok(value: String) -> Option<Self> {
238        const_ok!(Self::owned(value))
239    }
240
241    /// Similar to [`new_unchecked`], but accepts owned strings.
242    ///
243    /// # Safety
244    ///
245    /// The caller must ensure that the value is non-empty.
246    ///
247    /// [`new_unchecked`]: Self::new_unchecked
248    pub const unsafe fn owned_unchecked(value: String) -> Self {
249        // SAFETY: the caller must ensure that the value is non-empty
250        unsafe { Self::new_unchecked(Cow::Owned(value)) }
251    }
252
253    #[cfg(feature = "unsafe-assert")]
254    fn assert_non_empty(&self) {
255        // SAFETY: the value is non-empty by construction
256        unsafe {
257            assert_unchecked(!self.value.is_empty());
258        }
259    }
260
261    /// Consumes [`Self`] and returns the wrapped string.
262    pub fn take(self) -> Cow<'s, str> {
263        #[cfg(feature = "unsafe-assert")]
264        self.assert_non_empty();
265
266        self.value
267    }
268
269    /// Constructs [`Self`] from [`Str`].
270    pub const fn from_str(string: Str<'s>) -> Self {
271        // SAFETY: the contained string is non-empty
272        unsafe { Self::borrowed_unchecked(string.take()) }
273    }
274
275    /// Constructs [`Self`] from [`OwnedStr`].
276    pub fn from_owned_str(string: OwnedStr) -> Self {
277        // SAFETY: the contained string is non-empty
278        unsafe { Self::owned_unchecked(string.take()) }
279    }
280}
281
282impl CowStr<'_> {
283    /// Returns the wrapped string reference.
284    pub fn get(&self) -> &str {
285        #[cfg(feature = "unsafe-assert")]
286        self.assert_non_empty();
287
288        self.value.as_ref()
289    }
290}
291
292#[cfg(feature = "into-static")]
293impl IntoStatic for CowStr<'_> {
294    type Static = CowStr<'static>;
295
296    fn into_static(self) -> Self::Static {
297        // SAFETY: the contained string is non-empty
298        unsafe { Self::Static::new_unchecked(self.take().into_static()) }
299    }
300}