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_try;
18
19#[cfg(feature = "serde")]
20use serde::{
21    Deserialize, Deserializer, Serialize, Serializer,
22    de::{Error, Visitor},
23};
24
25use crate::empty::{Empty, check_str};
26
27/// Represents non-empty clone-on-write strings.
28#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
29pub struct CowStr<'s> {
30    value: Cow<'s, str>,
31}
32
33impl fmt::Display for CowStr<'_> {
34    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
35        self.get().fmt(formatter)
36    }
37}
38
39#[cfg(feature = "serde")]
40struct CowStrVisitor;
41
42#[cfg(feature = "serde")]
43impl<'de> Visitor<'de> for CowStrVisitor {
44    type Value = CowStr<'de>;
45
46    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
47        formatter.write_str("non-empty string")
48    }
49
50    fn visit_borrowed_str<E: Error>(self, string: &'de str) -> Result<Self::Value, E> {
51        Self::Value::borrowed(string).map_err(E::custom)
52    }
53
54    fn visit_str<E: Error>(self, string: &str) -> Result<Self::Value, E> {
55        self.visit_string(string.to_owned())
56    }
57
58    fn visit_string<E: Error>(self, string: String) -> Result<Self::Value, E> {
59        Self::Value::owned(string).map_err(E::custom)
60    }
61}
62
63#[cfg(feature = "serde")]
64impl Serialize for CowStr<'_> {
65    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
66        self.get().serialize(serializer)
67    }
68}
69
70#[cfg(feature = "serde")]
71impl<'de> Deserialize<'de> for CowStr<'de> {
72    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
73        deserializer.deserialize_string(CowStrVisitor)
74    }
75}
76
77impl AsRef<str> for CowStr<'_> {
78    fn as_ref(&self) -> &str {
79        self.get()
80    }
81}
82
83impl Deref for CowStr<'_> {
84    type Target = str;
85
86    fn deref(&self) -> &Self::Target {
87        self.get()
88    }
89}
90
91impl<'s> CowStr<'s> {
92    /// Constructs [`Self`], provided that the value is non-empty.
93    ///
94    /// # Errors
95    ///
96    /// Returns [`Empty`] if the string is empty.
97    pub fn new(value: Cow<'s, str>) -> Result<Self, Empty> {
98        const_try!(check_str(value.as_ref()));
99
100        Ok(unsafe { Self::new_unchecked(value) })
101    }
102
103    /// Constructs [`Self`] without checking if the value is non-empty.
104    ///
105    /// # Safety
106    ///
107    /// The caller must ensure that the value is non-empty.
108    pub const unsafe fn new_unchecked(value: Cow<'s, str>) -> Self {
109        Self { value }
110    }
111
112    /// Similar to [`new`], but accepts borrowed strings.
113    ///
114    /// # Errors
115    ///
116    /// Returns [`Empty`] if the string is empty.
117    ///
118    /// [`new`]: Self::new
119    pub fn borrowed(value: &'s str) -> Result<Self, Empty> {
120        Self::new(Cow::Borrowed(value))
121    }
122
123    /// Similar to [`new_unchecked`], but accepts borrowed strings.
124    ///
125    /// # Safety
126    ///
127    /// The caller must ensure that the value is non-empty.
128    ///
129    /// [`new_unchecked`]: Self::new_unchecked
130    pub const unsafe fn borrowed_unchecked(value: &'s str) -> Self {
131        // SAFETY: the caller must ensure that the value is non-empty
132        unsafe { Self::new_unchecked(Cow::Borrowed(value)) }
133    }
134
135    /// Similar to [`new`], but accepts owned strings.
136    ///
137    /// # Errors
138    ///
139    /// Returns [`Empty`] if the string is empty.
140    ///
141    /// [`new`]: Self::new
142    pub fn owned(value: String) -> Result<Self, Empty> {
143        Self::new(Cow::Owned(value))
144    }
145
146    /// Similar to [`new_unchecked`], but accepts owned strings.
147    ///
148    /// # Safety
149    ///
150    /// The caller must ensure that the value is non-empty.
151    ///
152    /// [`new_unchecked`]: Self::new_unchecked
153    pub const unsafe fn owned_unchecked(value: String) -> Self {
154        unsafe { Self::new_unchecked(Cow::Owned(value)) }
155    }
156
157    #[cfg(feature = "unsafe-assert")]
158    fn assert_non_empty(&self) {
159        unsafe { assert_unchecked(!self.value.is_empty()) }
160    }
161
162    /// Consumes [`Self`] and returns the wrapped string.
163    pub fn take(self) -> Cow<'s, str> {
164        #[cfg(feature = "unsafe-assert")]
165        self.assert_non_empty();
166
167        self.value
168    }
169}
170
171impl CowStr<'_> {
172    /// Returns the wrapped string reference.
173    pub fn get(&self) -> &str {
174        #[cfg(feature = "unsafe-assert")]
175        self.assert_non_empty();
176
177        self.value.as_ref()
178    }
179}