tiny_str/
cow.rs

1//! Cow implementation for TinyVec
2
3use core::fmt::Debug;
4use core::ops::{Add, AddAssign, Deref};
5
6#[cfg(feature = "alloc")]
7use alloc::{
8    boxed::Box,
9    string::String,
10};
11
12use crate::{TinyString, TinyVec};
13
14/// A Copy-on-Write struct for a TinyVec
15///
16/// This struct contains either a borrowed reference of `[T]`,
17/// or an owned TinyVec
18///
19/// # Example
20/// ```
21/// use tiny_str::{TinyString, Cow};
22///
23/// let string = TinyString::<5>::from("Hello, wo");
24/// let string = Cow::from(string);
25/// assert_eq!(&string, "Hello, wo");
26/// assert!(string.is_owned());
27///
28/// let mut borrowed_cow = Cow::from(&string);
29/// assert_eq!(borrowed_cow.as_str(), "Hello, wo");
30/// assert!(borrowed_cow.is_borrowed());
31///
32/// borrowed_cow.to_mut().push_str("rld!");
33/// assert_eq!(&string, "Hello, wo");
34/// assert_eq!(borrowed_cow.as_str(), "Hello, world!");
35/// assert!(borrowed_cow.is_owned());
36/// ```
37pub enum Cow<'borrow, const N: usize> {
38    Borrowed(&'borrow str),
39    Owned(TinyString<N>),
40}
41
42impl<'borrow, const N: usize> Cow<'borrow, N> {
43    /// Converts this [Cow] into an [Owned](Cow::Owned) variant
44    pub fn to_owned(&mut self) {
45        if let Cow::Borrowed(b) = self {
46            unsafe {
47                let utf8 = TinyVec::from_slice_copied(b.as_bytes());
48                let tv = TinyString::<N>::from_utf8_unchecked(utf8);
49                *self = Cow::Owned(tv)
50            }
51        }
52    }
53
54    /// Consumes this [Cow] and returns an [Owned](Cow::Owned) variant
55    pub fn into_owned(mut self) -> TinyString<N> {
56        self.to_owned();
57        match self {
58            Cow::Owned(w) => w,
59            Cow::Borrowed(_) => unreachable!("Self::to_owned must've turn self into an Owned variant"),
60        }
61    }
62
63    /// Gets a mutable reference to the [Owned] variant.
64    /// If this `Cow` is borrowed, it turns it into an [Owned]
65    /// variant first
66    ///
67    /// [Owned]: Cow::Owned
68    pub fn to_mut(&mut self) -> &mut TinyString<N> {
69        self.to_owned();
70        match self {
71            Cow::Owned(w) => w,
72            Cow::Borrowed(_) => unreachable!("Self::to_owned must've turn self into an Owned variant"),
73        }
74    }
75
76    /// Returns true if `self` is a [Borrowed](Cow::Borrowed) variant
77    pub const fn is_borrowed(&self) -> bool {
78        matches!(self, Cow::Borrowed(_))
79    }
80
81    /// Returns true if `self` is an [Owned](Cow::Owned) variant
82    pub const fn is_owned(&self) -> bool {
83        matches!(self, Cow::Owned(_))
84    }
85
86    /// Returns true if this [Cow] lives on the stack.
87    /// This is:
88    /// - It is a [Borrowed](Cow::Borrowed) variant
89    /// - It is an [Owned](Cow::Owned) variant that lives on the stack
90    pub const fn lives_on_stack(&self) -> bool {
91        match self {
92            Cow::Borrowed(_) => true,
93            Cow::Owned(v) => v.lives_on_stack(),
94        }
95    }
96
97    /// Returns `self` as a string reference
98    pub const fn as_str(&self) -> &str {
99        match self {
100            Cow::Borrowed(items) => items,
101            Cow::Owned(tiny_string) => tiny_string.as_str()
102        }
103    }
104
105    /// Returns `self` as a byte slice
106    pub const fn as_bytes(&self) -> &[u8] {
107        match self {
108            Cow::Borrowed(b) => b.as_bytes(),
109            Cow::Owned(s) => s.as_bytes(),
110        }
111    }
112}
113
114impl<'borrow, const N: usize> Deref for Cow<'borrow, N> {
115    type Target = str;
116
117    fn deref(&self) -> &Self::Target {
118        self.as_str()
119    }
120}
121
122impl<'borrow, const N: usize> From<&'borrow str> for Cow<'borrow, N> {
123    fn from(value: &'borrow str) -> Self {
124        Self::Borrowed(value)
125    }
126}
127
128impl<'borrow, 'b2, const N: usize> From<&'b2 Cow<'borrow, N>> for Cow<'b2, N> {
129    fn from(value: &'b2 Cow<'borrow, N>) -> Self {
130        Cow::Borrowed(value.as_str())
131    }
132}
133
134impl<'borrow, const N: usize> From<TinyString<N>> for Cow<'borrow, N> {
135    fn from(value: TinyString<N>) -> Self {
136        Self::Owned(value)
137    }
138}
139
140impl<'borrow, const N: usize> From<&'borrow TinyString<N>> for Cow<'borrow, N> {
141    fn from(value: &'borrow TinyString<N>) -> Self {
142        Self::Borrowed(value)
143    }
144}
145
146#[cfg(feature = "alloc")]
147impl<'borrow, const N: usize> From<String> for Cow<'borrow, N> {
148    fn from(value: String) -> Self {
149        Self::Owned(TinyString::from(value))
150    }
151}
152
153#[cfg(feature = "alloc")]
154impl<'borrow, const N: usize> From<Box<str>> for Cow<'borrow, N> {
155    fn from(value: Box<str>) -> Self {
156        Self::Owned(TinyString::from(value))
157    }
158}
159
160impl<'borrow, const N: usize> Debug for Cow<'borrow, N> {
161    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
162        match self {
163            Self::Borrowed(arg0) => f.debug_tuple("Borrowed").field(arg0).finish(),
164            Self::Owned(arg0) => f.debug_tuple("Owned").field(arg0).finish(),
165        }
166    }
167}
168
169impl<'borrow, const N: usize> Eq for Cow<'borrow, N> {}
170impl<'borrow, const N: usize> Ord for Cow<'borrow, N> {
171    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
172        self.as_bytes().cmp(other.as_bytes())
173    }
174}
175
176impl<'borrow, const N: usize> PartialEq<Cow<'borrow, N>> for Cow<'borrow, N> {
177    fn eq(&self, other: &Cow<'borrow, N>) -> bool {
178        other.as_bytes() == self.as_bytes()
179    }
180}
181
182impl<'borrow, const N: usize> PartialOrd<Cow<'borrow, N>> for Cow<'borrow, N> {
183    fn partial_cmp(&self, other: &Cow<'borrow, N>) -> Option<core::cmp::Ordering> {
184        Some(self.cmp(other))
185    }
186}
187
188impl<'borrow, const N: usize> PartialEq<str> for Cow<'borrow, N> {
189    fn eq(&self, other: &str) -> bool {
190        self.as_str() == other
191    }
192}
193
194impl<'borrow, const N: usize> PartialEq<Cow<'borrow, N>> for str {
195    fn eq(&self, other: &Cow<'borrow, N>) -> bool {
196        other.as_str() == self
197    }
198}
199
200impl<'borrow, const N: usize> PartialEq<&str> for Cow<'borrow, N> {
201    fn eq(&self, other: &&str) -> bool {
202        self.as_str() == *other
203    }
204}
205
206impl<'borrow, const N: usize> PartialEq<Cow<'borrow, N>> for &str {
207    fn eq(&self, other: &Cow<'borrow, N>) -> bool {
208        other.as_str() == *self
209    }
210}
211
212impl<'borrow, const N: usize> PartialEq<[u8]> for Cow<'borrow, N> {
213    fn eq(&self, other: &[u8]) -> bool {
214        self.as_bytes() == other
215    }
216}
217
218impl<'borrow, const N: usize> PartialEq<Cow<'borrow, N>> for [u8]{
219    fn eq(&self, other: &Cow<'borrow, N>) -> bool {
220        other.as_bytes() == self
221    }
222}
223
224impl<'borrow, const N: usize> PartialOrd<[u8]> for Cow<'borrow, N> {
225    fn partial_cmp(&self, other: &[u8]) -> Option<core::cmp::Ordering> {
226        self.as_bytes().partial_cmp(other)
227    }
228}
229
230impl<'borrow, const N: usize> PartialOrd<Cow<'borrow, N>> for [u8]{
231    fn partial_cmp(&self, other: &Cow<'borrow, N>) -> Option<core::cmp::Ordering> {
232        self.partial_cmp(other.as_bytes())
233    }
234}
235
236impl<'borrow, const N: usize> PartialOrd<str> for Cow<'borrow, N> {
237    fn partial_cmp(&self, other: &str) -> Option<core::cmp::Ordering> {
238        self.as_str().partial_cmp(other)
239    }
240}
241
242impl<'borrow, const N: usize> PartialOrd<Cow<'borrow, N>> for str {
243    fn partial_cmp(&self, other: &Cow<'borrow, N>) -> Option<core::cmp::Ordering> {
244        self.partial_cmp(other.as_str())
245    }
246}
247
248impl<'borrow, const N: usize> PartialOrd<&str> for Cow<'borrow, N> {
249    fn partial_cmp(&self, other: &&str) -> Option<core::cmp::Ordering> {
250        self.as_str().partial_cmp(*other)
251    }
252}
253
254impl<'borrow, const N: usize> PartialOrd<Cow<'borrow, N>> for &str {
255    fn partial_cmp(&self, other: &Cow<'borrow, N>) -> Option<core::cmp::Ordering> {
256        self.partial_cmp(&other.as_str())
257    }
258}
259
260impl<'borrow, const N: usize> Clone for Cow<'borrow, N> {
261    fn clone(&self) -> Self {
262        match self {
263            Self::Borrowed(arg0) => Self::Borrowed(arg0),
264            Self::Owned(arg0) => Self::Owned(arg0.clone()),
265        }
266    }
267}
268
269impl<'borrow, const N: usize> Default for Cow<'borrow, N> {
270    fn default() -> Self {
271        Self::Borrowed("")
272    }
273}
274
275impl<'borrow, const N: usize> Add for Cow<'borrow, N> {
276    type Output = Cow<'borrow, N>;
277
278    fn add(mut self, rhs: Self) -> Self::Output {
279        self += rhs;
280        self
281    }
282}
283
284impl<'borrow, const N: usize> Add<&'borrow str> for Cow<'borrow, N> {
285    type Output = Cow<'borrow, N>;
286
287    fn add(mut self, rhs: &'borrow str) -> Self::Output {
288        self += rhs;
289        self
290    }
291}
292
293impl<'borrow, const N: usize> AddAssign<&'borrow str> for Cow<'borrow, N> {
294    fn add_assign(&mut self, rhs: &'borrow str) {
295        if self.is_empty() {
296            *self = Cow::Borrowed(rhs)
297        } else if !rhs.is_empty() {
298            if let Cow::Borrowed(b) = self {
299                let mut s = TinyString::with_capacity(b.len() + rhs.len());
300                s.push_str(b);
301                *self = Cow::Owned(s);
302            }
303            self.to_mut().push_str(rhs);
304        }
305    }
306}
307
308impl<'borrow, const N: usize> AddAssign<Cow<'borrow, N>> for Cow<'borrow, N> {
309    fn add_assign(&mut self, rhs: Cow<'borrow, N>) {
310        if self.is_empty() {
311            *self = rhs;
312        } else if !rhs.is_empty() {
313            if let Cow::Borrowed(b) = self {
314                let mut s = TinyString::with_capacity(b.len() + rhs.len());
315                s.push_str(b);
316                *self = Cow::Owned(s);
317            }
318            self.to_mut().push_str(&rhs);
319        }
320    }
321}
322
323#[cfg(test)]
324mod test {
325    use super::*;
326
327    #[test]
328    fn partial_eq() {
329        let s = TinyString::<10>::from("ABCDEF");
330        let cow = Cow::from(s);
331
332        assert_eq!("ABCDEF", cow);
333    }
334}