non_empty_str/
cow.rs

1//! Non-empty [`Cow<'_, str>`](Cow).
2
3#[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/// Represents non-empty clone-on-write strings.
39#[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    /// Constructs [`Self`], provided that the value is non-empty.
155    ///
156    /// # Errors
157    ///
158    /// Returns [`Empty`] if the string is empty.
159    pub fn new(value: Cow<'s, str>) -> Result<Self, Empty> {
160        const_early!(value.is_empty() => Empty);
161
162        // SAFETY: the value is non-empty at this point
163        Ok(unsafe { Self::new_unchecked(value) })
164    }
165
166    /// Similar to [`new`], except the error is discarded.
167    ///
168    /// [`new`]: Self::new
169    pub fn new_ok(value: Cow<'s, str>) -> Option<Self> {
170        const_ok!(Self::new(value))
171    }
172
173    /// Constructs [`Self`] without checking if the value is non-empty.
174    ///
175    /// # Safety
176    ///
177    /// The caller must ensure that the value is non-empty.
178    pub const unsafe fn new_unchecked(value: Cow<'s, str>) -> Self {
179        Self { value }
180    }
181
182    /// Similar to [`new`], but accepts borrowed strings.
183    ///
184    /// # Errors
185    ///
186    /// Returns [`Empty`] if the string is empty.
187    ///
188    /// [`new`]: Self::new
189    pub const fn borrowed(value: &'s str) -> Result<Self, Empty> {
190        const_early!(value.is_empty() => Empty);
191
192        // SAFETY: the value is non-empty at this point
193        Ok(unsafe { Self::borrowed_unchecked(value) })
194    }
195
196    /// Similar to [`borrowed`], but the error is discarded.
197    ///
198    /// [`borrowed`]: Self::borrowed
199    pub const fn borrowed_ok(value: &'s str) -> Option<Self> {
200        const_quick!(value.is_empty());
201
202        // SAFETY: the value is non-empty at this point
203        Some(unsafe { Self::borrowed_unchecked(value) })
204    }
205
206    /// Similar to [`new_unchecked`], but accepts borrowed strings.
207    ///
208    /// # Safety
209    ///
210    /// The caller must ensure that the value is non-empty.
211    ///
212    /// [`new_unchecked`]: Self::new_unchecked
213    pub const unsafe fn borrowed_unchecked(value: &'s str) -> Self {
214        // SAFETY: the caller must ensure that the value is non-empty
215        unsafe { Self::new_unchecked(Cow::Borrowed(value)) }
216    }
217
218    /// Similar to [`new`], but accepts owned strings.
219    ///
220    /// # Errors
221    ///
222    /// Returns [`Empty`] if the string is empty.
223    ///
224    /// [`new`]: Self::new
225    pub fn owned(value: String) -> Result<Self, Empty> {
226        const_early!(value.is_empty() => Empty);
227
228        // SAFETY: the value is non-empty at this point
229        Ok(unsafe { Self::owned_unchecked(value) })
230    }
231
232    /// Similar to [`owned`], except the error is discarded.
233    ///
234    /// [`owned`]: Self::owned
235    pub fn owned_ok(value: String) -> Option<Self> {
236        const_ok!(Self::owned(value))
237    }
238
239    /// Similar to [`new_unchecked`], but accepts owned strings.
240    ///
241    /// # Safety
242    ///
243    /// The caller must ensure that the value is non-empty.
244    ///
245    /// [`new_unchecked`]: Self::new_unchecked
246    pub const unsafe fn owned_unchecked(value: String) -> Self {
247        // SAFETY: the caller must ensure that the value is non-empty
248        unsafe { Self::new_unchecked(Cow::Owned(value)) }
249    }
250
251    #[cfg(feature = "unsafe-assert")]
252    fn assert_non_empty(&self) {
253        // SAFETY: the value is non-empty by construction
254        unsafe {
255            assert_unchecked(!self.value.is_empty());
256        }
257    }
258
259    /// Consumes [`Self`] and returns the wrapped string.
260    pub fn take(self) -> Cow<'s, str> {
261        #[cfg(feature = "unsafe-assert")]
262        self.assert_non_empty();
263
264        self.value
265    }
266
267    /// Constructs [`Self`] from [`Str`].
268    pub const fn from_str(string: Str<'s>) -> Self {
269        // SAFETY: the contained string is non-empty
270        unsafe { Self::borrowed_unchecked(string.take()) }
271    }
272
273    /// Constructs [`Self`] from [`OwnedStr`].
274    pub fn from_owned_str(string: OwnedStr) -> Self {
275        // SAFETY: the contained string is non-empty
276        unsafe { Self::owned_unchecked(string.take()) }
277    }
278}
279
280impl CowStr<'_> {
281    /// Returns the wrapped string reference.
282    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/// An alias for [`CowStr<'static>`](CowStr).
291#[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        // SAFETY: the contained string is non-empty
300        unsafe { Self::Static::new_unchecked(self.take().into_static()) }
301    }
302}