non_empty_str/
cow.rs

1//! Non-empty [`Cow<'_, str>`].
2
3#[cfg(feature = "unsafe-assert")]
4use core::hint::assert_unchecked;
5
6use core::{fmt, ops::Deref};
7
8#[cfg(feature = "std")]
9use std::borrow::Cow;
10
11#[cfg(all(not(feature = "std"), feature = "alloc"))]
12use alloc::{borrow::Cow, string::String};
13
14#[cfg(all(not(feature = "std"), feature = "alloc", feature = "serde"))]
15use alloc::borrow::ToOwned;
16
17use const_macros::{const_none, const_ok, const_try};
18
19#[cfg(feature = "serde")]
20use serde::{
21    Deserialize, Deserializer, Serialize, Serializer,
22    de::{Error, Visitor},
23};
24
25use crate::{
26    empty::{Empty, check_str},
27    str::Str,
28};
29
30/// Represents non-empty clone-on-write strings.
31#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
32pub struct CowStr<'s> {
33    value: Cow<'s, str>,
34}
35
36impl fmt::Display for CowStr<'_> {
37    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
38        self.get().fmt(formatter)
39    }
40}
41
42#[cfg(feature = "serde")]
43struct CowStrVisitor;
44
45#[cfg(feature = "serde")]
46impl<'de> Visitor<'de> for CowStrVisitor {
47    type Value = CowStr<'de>;
48
49    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
50        formatter.write_str("non-empty string")
51    }
52
53    fn visit_borrowed_str<E: Error>(self, string: &'de str) -> Result<Self::Value, E> {
54        Self::Value::borrowed(string).map_err(E::custom)
55    }
56
57    fn visit_str<E: Error>(self, string: &str) -> Result<Self::Value, E> {
58        self.visit_string(string.to_owned())
59    }
60
61    fn visit_string<E: Error>(self, string: String) -> Result<Self::Value, E> {
62        Self::Value::owned(string).map_err(E::custom)
63    }
64}
65
66#[cfg(feature = "serde")]
67impl Serialize for CowStr<'_> {
68    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
69        self.get().serialize(serializer)
70    }
71}
72
73#[cfg(feature = "serde")]
74impl<'de> Deserialize<'de> for CowStr<'de> {
75    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
76        deserializer.deserialize_string(CowStrVisitor)
77    }
78}
79
80impl AsRef<str> for CowStr<'_> {
81    fn as_ref(&self) -> &str {
82        self.get()
83    }
84}
85
86impl Deref for CowStr<'_> {
87    type Target = str;
88
89    fn deref(&self) -> &Self::Target {
90        self.get()
91    }
92}
93
94impl<'s> TryFrom<Cow<'s, str>> for CowStr<'s> {
95    type Error = Empty;
96
97    fn try_from(value: Cow<'s, str>) -> Result<Self, Self::Error> {
98        Self::new(value)
99    }
100}
101
102impl<'s> TryFrom<&'s str> for CowStr<'s> {
103    type Error = Empty;
104
105    fn try_from(value: &'s str) -> Result<Self, Self::Error> {
106        Self::borrowed(value)
107    }
108}
109
110impl TryFrom<String> for CowStr<'_> {
111    type Error = Empty;
112
113    fn try_from(value: String) -> Result<Self, Self::Error> {
114        Self::owned(value)
115    }
116}
117
118impl<'s> From<Str<'s>> for CowStr<'s> {
119    fn from(string: Str<'s>) -> Self {
120        Self::from_str(string)
121    }
122}
123
124impl<'s> From<CowStr<'s>> for Cow<'s, str> {
125    fn from(value: CowStr<'s>) -> Self {
126        value.take()
127    }
128}
129
130impl<'s> CowStr<'s> {
131    /// Constructs [`Self`], provided that the value is non-empty.
132    ///
133    /// # Errors
134    ///
135    /// Returns [`Empty`] if the string is empty.
136    pub fn new(value: Cow<'s, str>) -> Result<Self, Empty> {
137        const_try!(check_str(value.as_ref()));
138
139        Ok(unsafe { Self::new_unchecked(value) })
140    }
141
142    /// Similar to [`new`], except the error is discarded.
143    ///
144    /// [`new`]: Self::new
145    pub fn new_ok(value: Cow<'s, str>) -> Option<Self> {
146        const_ok!(Self::new(value))
147    }
148
149    /// Constructs [`Self`] without checking if the value is non-empty.
150    ///
151    /// # Safety
152    ///
153    /// The caller must ensure that the value is non-empty.
154    pub const unsafe fn new_unchecked(value: Cow<'s, str>) -> Self {
155        Self { value }
156    }
157
158    /// Similar to [`new`], but accepts borrowed strings.
159    ///
160    /// # Errors
161    ///
162    /// Returns [`Empty`] if the string is empty.
163    ///
164    /// [`new`]: Self::new
165    pub const fn borrowed(value: &'s str) -> Result<Self, Empty> {
166        const_try!(check_str(value));
167
168        // SAFETY: the value is non-empty at this point
169        Ok(unsafe { Self::borrowed_unchecked(value) })
170    }
171
172    /// Similar to [`borrowed`], but the error is discarded.
173    ///
174    /// [`borrowed`]: Self::borrowed
175    pub const fn borrowed_ok(value: &'s str) -> Option<Self> {
176        // NOTE: we can not use `const_ok!(Self::borrowed(value))` currently
177
178        const_none!(const_ok!(check_str(value)));
179
180        Some(unsafe { Self::borrowed_unchecked(value) })
181    }
182
183    /// Similar to [`new_unchecked`], but accepts borrowed strings.
184    ///
185    /// # Safety
186    ///
187    /// The caller must ensure that the value is non-empty.
188    ///
189    /// [`new_unchecked`]: Self::new_unchecked
190    pub const unsafe fn borrowed_unchecked(value: &'s str) -> Self {
191        // SAFETY: the caller must ensure that the value is non-empty
192        unsafe { Self::new_unchecked(Cow::Borrowed(value)) }
193    }
194
195    /// Similar to [`new`], but accepts owned strings.
196    ///
197    /// # Errors
198    ///
199    /// Returns [`Empty`] if the string is empty.
200    ///
201    /// [`new`]: Self::new
202    pub fn owned(value: String) -> Result<Self, Empty> {
203        const_try!(check_str(value.as_str()));
204
205        // SAFETY: the value is non-empty at this point
206        Ok(unsafe { Self::owned_unchecked(value) })
207    }
208
209    /// Similar to [`owned`], except the error is discarded.
210    ///
211    /// [`owned`]: Self::owned
212    pub fn owned_ok(value: String) -> Option<Self> {
213        const_ok!(Self::owned(value))
214    }
215
216    /// Similar to [`new_unchecked`], but accepts owned strings.
217    ///
218    /// # Safety
219    ///
220    /// The caller must ensure that the value is non-empty.
221    ///
222    /// [`new_unchecked`]: Self::new_unchecked
223    pub const unsafe fn owned_unchecked(value: String) -> Self {
224        unsafe { Self::new_unchecked(Cow::Owned(value)) }
225    }
226
227    #[cfg(feature = "unsafe-assert")]
228    fn assert_non_empty(&self) {
229        unsafe { assert_unchecked(!self.value.is_empty()) }
230    }
231
232    /// Consumes [`Self`] and returns the wrapped string.
233    pub fn take(self) -> Cow<'s, str> {
234        #[cfg(feature = "unsafe-assert")]
235        self.assert_non_empty();
236
237        self.value
238    }
239
240    /// Constructs [`Self`] from [`Str`].
241    pub const fn from_str(string: Str<'s>) -> Self {
242        // SAFETY: the contained string is non-empty
243        unsafe { Self::borrowed_unchecked(string.take()) }
244    }
245}
246
247impl CowStr<'_> {
248    /// Returns the wrapped string reference.
249    pub fn get(&self) -> &str {
250        #[cfg(feature = "unsafe-assert")]
251        self.assert_non_empty();
252
253        self.value.as_ref()
254    }
255}