cowvec/
lib.rs

1use std::ops::Deref;
2use std::{fmt, mem, ptr, slice, str};
3
4#[derive(Clone)]
5pub struct CowStr<'a>(CowVec<'a, u8>);
6
7impl<'a> CowStr<'a> {
8    #[inline]
9    pub fn borrowed(b: &'a str) -> Self {
10        CowStr(CowVec::borrowed(b.as_bytes()))
11    }
12
13    #[inline]
14    pub fn owned(v: String) -> Self {
15        CowStr(CowVec::owned(v.into_bytes()))
16    }
17
18    #[inline]
19    pub fn into_owned(self) -> String {
20        unsafe { String::from_utf8_unchecked(self.0.into_owned()) }
21    }
22
23    #[inline]
24    pub fn try_owned(self) -> Option<String> {
25        self.0
26            .try_owned()
27            .map(|v| unsafe { String::from_utf8_unchecked(v) })
28    }
29}
30
31impl<'a> PartialEq<&'a str> for CowStr<'a> {
32    fn eq(&self, other: &&str) -> bool {
33        self.as_ref() == *other
34    }
35}
36
37impl<'a> PartialEq<String> for CowStr<'a> {
38    fn eq(&self, other: &String) -> bool {
39        *self == &**other
40    }
41}
42
43impl<'a> PartialEq for CowStr<'a> {
44    fn eq(&self, other: &Self) -> bool {
45        *self == other.as_ref()
46    }
47}
48
49impl<'a> fmt::Debug for CowStr<'a> {
50    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
51        self.as_ref().fmt(f)
52    }
53}
54
55impl<'a> fmt::Display for CowStr<'a> {
56    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
57        self.as_ref().fmt(f)
58    }
59}
60
61impl<'a> From<&'a str> for CowStr<'a> {
62    fn from(other: &'a str) -> Self {
63        CowStr::borrowed(other)
64    }
65}
66
67impl From<String> for CowStr<'static> {
68    fn from(other: String) -> Self {
69        CowStr::owned(other)
70    }
71}
72
73impl<'a> AsRef<str> for CowStr<'a> {
74    #[inline]
75    fn as_ref(&self) -> &str {
76        unsafe { str::from_utf8_unchecked(self.0.as_ref()) }
77    }
78}
79
80impl<'a> Deref for CowStr<'a> {
81    type Target = str;
82
83    #[inline]
84    fn deref(&self) -> &str {
85        unsafe { str::from_utf8_unchecked(self.0.deref()) }
86    }
87}
88
89pub struct CowVec<'a, T: 'a> {
90    ptr: *const T,
91    len: usize,
92    cap: usize,
93    _marker: ::std::marker::PhantomData<&'a [T]>,
94}
95
96impl<'a, T> CowVec<'a, T> {
97    #[inline]
98    pub fn borrowed(b: &'a [T]) -> Self {
99        CowVec {
100            ptr: b.as_ptr(),
101            len: b.len(),
102            cap: 0,
103            _marker: Default::default(),
104        }
105    }
106
107    #[inline]
108    pub fn owned(v: Vec<T>) -> Self {
109        let out = CowVec {
110            ptr: v.as_ptr(),
111            len: v.len(),
112            cap: v.capacity(),
113            _marker: Default::default(),
114        };
115
116        mem::forget(v);
117
118        out
119    }
120
121    #[inline]
122    pub fn into_owned(self) -> Vec<T>
123    where
124        T: Clone,
125    {
126        self.owned_or(|x| x, |a: &_| Vec::from(a))
127    }
128
129    #[inline]
130    pub fn try_owned(self) -> Option<Vec<T>> {
131        self.owned_or(Some, |_: &_| None)
132    }
133
134    fn owned_or<Out, MF, OF>(self, map: MF, or: OF) -> Out
135    where
136        MF: FnOnce(Vec<T>) -> Out,
137        OF: FnOnce(&[T]) -> Out,
138    {
139        let out = if self.cap == 0 {
140            or(self.as_ref())
141        } else {
142            map(unsafe { Vec::from_raw_parts(self.ptr as *mut T, self.len, self.cap) })
143        };
144
145        mem::forget(self);
146
147        out
148    }
149}
150
151impl<'a, T> Clone for CowVec<'a, T>
152where
153    T: Clone,
154{
155    fn clone(&self) -> Self {
156        if self.cap == 0 {
157            CowVec { ..*self }
158        } else {
159            Vec::from(self.as_ref()).into()
160        }
161    }
162}
163
164impl<'a, T> PartialEq<&'a [T]> for CowVec<'a, T>
165where
166    for<'any> &'any [T]: PartialEq,
167{
168    fn eq(&self, other: &&[T]) -> bool {
169        self.as_ref() == *other
170    }
171}
172
173impl<'a, T> PartialEq<Vec<T>> for CowVec<'a, T>
174where
175    for<'any> &'any [T]: PartialEq,
176{
177    fn eq(&self, other: &Vec<T>) -> bool {
178        *self == &**other
179    }
180}
181
182impl<'a, T> PartialEq for CowVec<'a, T>
183where
184    for<'any> &'any [T]: PartialEq,
185{
186    fn eq(&self, other: &Self) -> bool {
187        *self == other.as_ref()
188    }
189}
190
191impl<'a, T> fmt::Debug for CowVec<'a, T>
192where
193    for<'any> &'any [T]: fmt::Debug,
194{
195    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
196        self.as_ref().fmt(f)
197    }
198}
199
200impl<'a, T> From<&'a [T]> for CowVec<'a, T> {
201    fn from(other: &'a [T]) -> Self {
202        CowVec::borrowed(other)
203    }
204}
205
206impl<'a, T> From<Vec<T>> for CowVec<'a, T> {
207    fn from(other: Vec<T>) -> Self {
208        CowVec::owned(other)
209    }
210}
211
212impl<'a, T> AsRef<[T]> for CowVec<'a, T> {
213    #[inline]
214    fn as_ref(&self) -> &[T] {
215        unsafe { slice::from_raw_parts(self.ptr, self.len) }
216    }
217}
218
219impl<'a, T> Drop for CowVec<'a, T> {
220    #[inline]
221    fn drop(&mut self) {
222        let _ = unsafe { ptr::read(self) }.try_owned();
223    }
224}
225
226impl<'a, T> Deref for CowVec<'a, T> {
227    type Target = [T];
228
229    #[inline]
230    fn deref(&self) -> &[T] {
231        self.as_ref()
232    }
233}
234
235#[cfg(test)]
236mod tests {
237    use super::{CowStr, CowVec};
238
239    #[test]
240    fn borrowed() {
241        let arr = &[1, 2, 3, 4, 5];
242        let v = CowVec::borrowed(arr);
243
244        assert_eq!(arr, &*v);
245    }
246
247    #[test]
248    fn owned() {
249        let arr = vec![1, 2, 3, 4, 5];
250        let v = CowVec::owned(arr.clone());
251
252        assert_eq!(arr, &*v);
253    }
254
255    #[test]
256    fn borrowed_str() {
257        let msg = "Hello, world!";
258        let v = CowStr::borrowed(msg);
259
260        assert_eq!(msg, &*v);
261    }
262
263    #[test]
264    fn owned_str() {
265        let msg = "Hello, world!".to_owned();
266        let v = CowStr::owned(msg.clone());
267
268        assert_eq!(msg, &*v);
269    }
270}