non_empty_str/
cow.rs

1//! Non-empty [`Cow<'_, str>`].
2//!
3//! [`Cow<'_, str>`]: Cow
4
5#[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/// 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<'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    /// Constructs [`Self`], provided that the value is non-empty.
151    ///
152    /// # Errors
153    ///
154    /// Returns [`Empty`] if the string is empty.
155    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    /// Similar to [`new`], except the error is discarded.
162    ///
163    /// [`new`]: Self::new
164    pub fn new_ok(value: Cow<'s, str>) -> Option<Self> {
165        const_ok!(Self::new(value))
166    }
167
168    /// Constructs [`Self`] without checking if the value is non-empty.
169    ///
170    /// # Safety
171    ///
172    /// The caller must ensure that the value is non-empty.
173    pub const unsafe fn new_unchecked(value: Cow<'s, str>) -> Self {
174        Self { value }
175    }
176
177    /// Similar to [`new`], but accepts borrowed strings.
178    ///
179    /// # Errors
180    ///
181    /// Returns [`Empty`] if the string is empty.
182    ///
183    /// [`new`]: Self::new
184    pub const fn borrowed(value: &'s str) -> Result<Self, Empty> {
185        const_try!(check_str(value));
186
187        // SAFETY: the value is non-empty at this point
188        Ok(unsafe { Self::borrowed_unchecked(value) })
189    }
190
191    /// Similar to [`borrowed`], but the error is discarded.
192    ///
193    /// [`borrowed`]: Self::borrowed
194    pub const fn borrowed_ok(value: &'s str) -> Option<Self> {
195        // NOTE: we can not use `const_ok!(Self::borrowed(value))` currently
196
197        const_none!(const_ok!(check_str(value)));
198
199        Some(unsafe { Self::borrowed_unchecked(value) })
200    }
201
202    /// Similar to [`new_unchecked`], but accepts borrowed strings.
203    ///
204    /// # Safety
205    ///
206    /// The caller must ensure that the value is non-empty.
207    ///
208    /// [`new_unchecked`]: Self::new_unchecked
209    pub const unsafe fn borrowed_unchecked(value: &'s str) -> Self {
210        // SAFETY: the caller must ensure that the value is non-empty
211        unsafe { Self::new_unchecked(Cow::Borrowed(value)) }
212    }
213
214    /// Similar to [`new`], but accepts owned strings.
215    ///
216    /// # Errors
217    ///
218    /// Returns [`Empty`] if the string is empty.
219    ///
220    /// [`new`]: Self::new
221    pub fn owned(value: String) -> Result<Self, Empty> {
222        const_try!(check_str(value.as_str()));
223
224        // SAFETY: the value is non-empty at this point
225        Ok(unsafe { Self::owned_unchecked(value) })
226    }
227
228    /// Similar to [`owned`], except the error is discarded.
229    ///
230    /// [`owned`]: Self::owned
231    pub fn owned_ok(value: String) -> Option<Self> {
232        const_ok!(Self::owned(value))
233    }
234
235    /// Similar to [`new_unchecked`], but accepts owned strings.
236    ///
237    /// # Safety
238    ///
239    /// The caller must ensure that the value is non-empty.
240    ///
241    /// [`new_unchecked`]: Self::new_unchecked
242    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    /// Consumes [`Self`] and returns the wrapped string.
252    pub fn take(self) -> Cow<'s, str> {
253        #[cfg(feature = "unsafe-assert")]
254        self.assert_non_empty();
255
256        self.value
257    }
258
259    /// Constructs [`Self`] from [`Str`].
260    pub const fn from_str(string: Str<'s>) -> Self {
261        // SAFETY: the contained string is non-empty
262        unsafe { Self::borrowed_unchecked(string.take()) }
263    }
264}
265
266impl CowStr<'_> {
267    /// Returns the wrapped string reference.
268    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        // SAFETY: the contained string is non-empty
282        unsafe { Self::Static::new_unchecked(self.take().into_static()) }
283    }
284}