wasmtime_internal_core/alloc/
try_cow.rs1use super::*;
2use core::{cmp, fmt, hash, ops::Deref};
3use std_alloc::borrow::Borrow;
4
5pub trait TryToOwned {
8 type Owned: Borrow<Self>;
10
11 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
51pub enum TryCow<'a, B>
54where
55 B: 'a + TryToOwned + ?Sized,
56{
57 Borrowed(&'a B),
59
60 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 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 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}