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