1 use super::*;
2 use core::{cmp, fmt, hash, ops::Deref};
3 use std_alloc::borrow::Borrow;
4 
5 /// Like [`std::borrow::ToOwned`] but returns an [`OutOfMemory`] error on
6 /// allocation failure.
7 pub trait TryToOwned {
8     /// The owned version of this type.
9     type Owned: Borrow<Self>;
10 
11     /// Try to allocate an owned version of `self`.
try_to_owned(&self) -> Result<Self::Owned, OutOfMemory>12     fn try_to_owned(&self) -> Result<Self::Owned, OutOfMemory>;
13 }
14 
15 impl TryToOwned for str {
16     type Owned = TryString;
17 
try_to_owned(&self) -> Result<Self::Owned, OutOfMemory>18     fn try_to_owned(&self) -> Result<Self::Owned, OutOfMemory> {
19         let mut s = TryString::new();
20         s.push_str(self)?;
21         Ok(s)
22     }
23 }
24 
25 impl<T> TryToOwned for [T]
26 where
27     T: TryClone,
28 {
29     type Owned = TryVec<T>;
30 
try_to_owned(&self) -> Result<Self::Owned, OutOfMemory>31     fn try_to_owned(&self) -> Result<Self::Owned, OutOfMemory> {
32         let mut v = TryVec::with_capacity(self.len())?;
33         for x in self {
34             v.push(x.try_clone()?)?;
35         }
36         Ok(v)
37     }
38 }
39 
40 impl<T> TryToOwned for T
41 where
42     T: TryClone,
43 {
44     type Owned = Self;
45 
try_to_owned(&self) -> Result<Self::Owned, OutOfMemory>46     fn try_to_owned(&self) -> Result<Self::Owned, OutOfMemory> {
47         self.try_clone()
48     }
49 }
50 
51 /// Like [`std::borrow::Cow`] but returns [`OutOfMemory`] errors for various
52 /// APIs that force allocation of an owned copy.
53 pub enum TryCow<'a, B>
54 where
55     B: 'a + TryToOwned + ?Sized,
56 {
57     /// Borrowed data.
58     Borrowed(&'a B),
59 
60     /// Owned data.
61     Owned(<B as TryToOwned>::Owned),
62 }
63 
64 impl<'a, B> From<&'a B> for TryCow<'a, B>
65 where
66     B: 'a + ?Sized + TryToOwned,
67 {
from(b: &'a B) -> Self68     fn from(b: &'a B) -> Self {
69         Self::Borrowed(b)
70     }
71 }
72 
73 impl<B> Default for TryCow<'_, B>
74 where
75     B: ?Sized + TryToOwned<Owned: Default>,
76 {
default() -> Self77     fn default() -> Self {
78         Self::Owned(<B as TryToOwned>::Owned::default())
79     }
80 }
81 
82 impl<B> fmt::Debug for TryCow<'_, B>
83 where
84     B: ?Sized + fmt::Debug + TryToOwned<Owned: fmt::Debug>,
85 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result86     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87         match self {
88             Self::Borrowed(b) => fmt::Debug::fmt(b, f),
89             Self::Owned(o) => fmt::Debug::fmt(o, f),
90         }
91     }
92 }
93 
94 impl<B> TryClone for TryCow<'_, B>
95 where
96     B: ?Sized + TryToOwned,
97 {
try_clone(&self) -> Result<Self, OutOfMemory>98     fn try_clone(&self) -> Result<Self, OutOfMemory> {
99         match self {
100             Self::Borrowed(b) => Ok(Self::Borrowed(b)),
101             Self::Owned(o) => {
102                 let b: &B = o.borrow();
103                 Ok(Self::Owned(b.try_to_owned()?))
104             }
105         }
106     }
107 }
108 
109 impl<B> Deref for TryCow<'_, B>
110 where
111     B: ?Sized + TryToOwned,
112 {
113     type Target = B;
114 
deref(&self) -> &B115     fn deref(&self) -> &B {
116         match self {
117             Self::Borrowed(b) => b,
118             Self::Owned(o) => o.borrow(),
119         }
120     }
121 }
122 
123 impl<B> AsRef<B> for TryCow<'_, B>
124 where
125     B: ?Sized + TryToOwned,
126 {
as_ref(&self) -> &B127     fn as_ref(&self) -> &B {
128         self
129     }
130 }
131 
132 impl<'a, B> Borrow<B> for TryCow<'a, B>
133 where
134     B: ?Sized + TryToOwned,
135 {
borrow(&self) -> &B136     fn borrow(&self) -> &B {
137         &**self
138     }
139 }
140 
141 impl<B> hash::Hash for TryCow<'_, B>
142 where
143     B: ?Sized + hash::Hash + TryToOwned,
144 {
hash<H>(&self, state: &mut H) where H: hash::Hasher,145     fn hash<H>(&self, state: &mut H)
146     where
147         H: hash::Hasher,
148     {
149         hash::Hash::hash(&**self, state)
150     }
151 }
152 
153 impl<B> PartialEq for TryCow<'_, B>
154 where
155     B: ?Sized + PartialEq + TryToOwned,
156 {
eq(&self, other: &Self) -> bool157     fn eq(&self, other: &Self) -> bool {
158         PartialEq::eq(&**self, &**other)
159     }
160 }
161 
162 impl<B> Eq for TryCow<'_, B> where B: ?Sized + Eq + TryToOwned {}
163 
164 impl<B> PartialOrd for TryCow<'_, B>
165 where
166     B: ?Sized + PartialOrd + TryToOwned,
167 {
partial_cmp(&self, other: &Self) -> Option<cmp::Ordering>168     fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
169         PartialOrd::partial_cmp(&**self, &**other)
170     }
171 }
172 
173 impl<B> Ord for TryCow<'_, B>
174 where
175     B: ?Sized + Ord + TryToOwned,
176 {
cmp(&self, other: &Self) -> cmp::Ordering177     fn cmp(&self, other: &Self) -> cmp::Ordering {
178         Ord::cmp(&**self, &**other)
179     }
180 }
181 
182 impl<'a, B> TryCow<'a, B>
183 where
184     B: TryToOwned + ?Sized,
185 {
186     /// Same as [`std::borrow::Cow::to_mut`] but returns an [`OutOfMemory`]
187     /// error on allocation failure.
to_mut(&mut self) -> Result<&mut <B as TryToOwned>::Owned, OutOfMemory>188     pub fn to_mut(&mut self) -> Result<&mut <B as TryToOwned>::Owned, OutOfMemory> {
189         if let Self::Borrowed(b) = self {
190             *self = Self::Owned(b.try_to_owned()?);
191         }
192         match self {
193             TryCow::Owned(x) => Ok(x),
194             TryCow::Borrowed(_) => unreachable!(),
195         }
196     }
197 
198     /// Same as [`std::borrow::Cow::into_owned`] but returns an [`OutOfMemory`]
199     /// error on allocation failure.
into_owned(self) -> Result<<B as TryToOwned>::Owned, OutOfMemory>200     pub fn into_owned(self) -> Result<<B as TryToOwned>::Owned, OutOfMemory> {
201         match self {
202             TryCow::Borrowed(b) => b.try_to_owned(),
203             TryCow::Owned(x) => Ok(x),
204         }
205     }
206 }
207 
208 #[cfg(test)]
209 mod tests {
210     use super::*;
211     use crate::error::Result;
212 
213     #[test]
to_mut() -> Result<()>214     fn to_mut() -> Result<()> {
215         let mut s = TryCow::Borrowed("hello");
216         s.to_mut()?.push_str(", world!")?;
217         assert!(matches!(s, TryCow::Owned(_)));
218         assert_eq!(&*s, "hello, world!");
219         Ok(())
220     }
221 
222     #[test]
into_owned() -> Result<()>223     fn into_owned() -> Result<()> {
224         let v = TryCow::Borrowed(&[42u8, 36][..]);
225         let v: TryVec<u8> = v.into_owned()?;
226         assert_eq!(&*v, &[42, 36]);
227         Ok(())
228     }
229 }
230