Skip to main content

wasmtime_internal_core/alloc/
try_cow.rs

1use super::*;
2use core::{cmp, fmt, hash, ops::Deref};
3use std_alloc::borrow::Borrow;
4
5/// Like [`std::borrow::ToOwned`] but returns an [`OutOfMemory`] error on
6/// allocation failure.
7pub trait TryToOwned {
8    /// The owned version of this type.
9    type Owned: Borrow<Self>;
10
11    /// Try to allocate an owned version of `self`.
12    fn try_to_owned(&self) -> Result<Self::Owned, OutOfMemory>;
13}
14
15impl TryToOwned for str {
16    type Owned = TryString;
17
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
25impl<T> TryToOwned for [T]
26where
27    T: TryClone,
28{
29    type Owned = Vec<T>;
30
31    fn try_to_owned(&self) -> Result<Self::Owned, OutOfMemory> {
32        let mut v = Vec::with_capacity(self.len())?;
33        for x in self {
34            v.push(x.try_clone()?)?;
35        }
36        Ok(v)
37    }
38}
39
40impl<T> TryToOwned for T
41where
42    T: TryClone,
43{
44    type Owned = Self;
45
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.
53pub enum TryCow<'a, B>
54where
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
64impl<'a, B> From<&'a B> for TryCow<'a, B>
65where
66    B: 'a + ?Sized + TryToOwned,
67{
68    fn from(b: &'a B) -> Self {
69        Self::Borrowed(b)
70    }
71}
72
73impl<B> Default for TryCow<'_, B>
74where
75    B: ?Sized + TryToOwned<Owned: Default>,
76{
77    fn default() -> Self {
78        Self::Owned(<B as TryToOwned>::Owned::default())
79    }
80}
81
82impl<B> fmt::Debug for TryCow<'_, B>
83where
84    B: ?Sized + fmt::Debug + TryToOwned<Owned: fmt::Debug>,
85{
86    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
94impl<B> TryClone for TryCow<'_, B>
95where
96    B: ?Sized + TryToOwned,
97{
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
109impl<B> Deref for TryCow<'_, B>
110where
111    B: ?Sized + TryToOwned,
112{
113    type Target = B;
114
115    fn deref(&self) -> &B {
116        match self {
117            Self::Borrowed(b) => b,
118            Self::Owned(o) => o.borrow(),
119        }
120    }
121}
122
123impl<B> AsRef<B> for TryCow<'_, B>
124where
125    B: ?Sized + TryToOwned,
126{
127    fn as_ref(&self) -> &B {
128        self
129    }
130}
131
132impl<'a, B> Borrow<B> for TryCow<'a, B>
133where
134    B: ?Sized + TryToOwned,
135{
136    fn borrow(&self) -> &B {
137        &**self
138    }
139}
140
141impl<B> hash::Hash for TryCow<'_, B>
142where
143    B: ?Sized + hash::Hash + TryToOwned,
144{
145    fn hash<H>(&self, state: &mut H)
146    where
147        H: hash::Hasher,
148    {
149        hash::Hash::hash(&**self, state)
150    }
151}
152
153impl<B> PartialEq for TryCow<'_, B>
154where
155    B: ?Sized + PartialEq + TryToOwned,
156{
157    fn eq(&self, other: &Self) -> bool {
158        PartialEq::eq(&**self, &**other)
159    }
160}
161
162impl<B> Eq for TryCow<'_, B> where B: ?Sized + Eq + TryToOwned {}
163
164impl<B> PartialOrd for TryCow<'_, B>
165where
166    B: ?Sized + PartialOrd + TryToOwned,
167{
168    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
169        PartialOrd::partial_cmp(&**self, &**other)
170    }
171}
172
173impl<B> Ord for TryCow<'_, B>
174where
175    B: ?Sized + Ord + TryToOwned,
176{
177    fn cmp(&self, other: &Self) -> cmp::Ordering {
178        Ord::cmp(&**self, &**other)
179    }
180}
181
182impl<'a, B> TryCow<'a, B>
183where
184    B: TryToOwned + ?Sized,
185{
186    /// Same as [`std::borrow::Cow::to_mut`] but returns an [`OutOfMemory`]
187    /// error on allocation failure.
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.
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)]
209mod tests {
210    use super::*;
211    use crate::error::Result;
212
213    #[test]
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]
223    fn into_owned() -> Result<()> {
224        let v = TryCow::Borrowed(&[42u8, 36][..]);
225        let v: Vec<u8> = v.into_owned()?;
226        assert_eq!(&*v, &[42, 36]);
227        Ok(())
228    }
229}