1 | // This file is part of ICU4X. For terms of use, please see the file |
2 | // called LICENSE at the top level of the ICU4X source tree |
3 | // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). |
4 | |
5 | #[cfg (feature = "alloc" )] |
6 | use alloc::borrow::{Cow, ToOwned}; |
7 | use core::mem; |
8 | |
9 | /// The `Yokeable<'a>` trait is implemented on the `'static` version of any zero-copy type; for |
10 | /// example, `Cow<'static, T>` implements `Yokeable<'a>` (for all `'a`). One can use |
11 | /// `Yokeable::Output` on this trait to obtain the "lifetime'd" value of the `Cow<'static, T>`, |
12 | /// e.g. `<Cow<'static, T> as Yokeable<'a>'>::Output` is `Cow<'a, T>`. |
13 | /// |
14 | /// A [`Yokeable`] type is essentially one with a covariant lifetime parameter, |
15 | /// matched to the parameter in the trait definition. The trait allows one to cast |
16 | /// the covariant lifetime to and from `'static`. |
17 | /// |
18 | /// **Most of the time, if you need to implement [`Yokeable`], you should be able to use the safe |
19 | /// [`#[derive(Yokeable)]`](yoke_derive::Yokeable) custom derive.** |
20 | /// |
21 | /// While Rust does not yet have GAT syntax, for the purpose of this documentation |
22 | /// we shall refer to "`Self` with a lifetime `'a`" with the syntax `Self<'a>`. |
23 | /// Self<'static> is a stand-in for the HKT Self<'_>: lifetime -> type. |
24 | /// |
25 | /// With this terminology, [`Yokeable`] exposes ways to cast between `Self<'static>` and `Self<'a>` generically. |
26 | /// This is useful for turning covariant lifetimes to _dynamic_ lifetimes, where `'static` is |
27 | /// used as a way to "erase" the lifetime. |
28 | /// |
29 | /// # Safety |
30 | /// |
31 | /// This trait is safe to implement on types with a _covariant_ lifetime parameter, i.e. one where |
32 | /// [`Self::transform()`]'s body can simply be `{ self }`. This will occur when the lifetime |
33 | /// parameter is used within references, but not in the arguments of function pointers or in mutable |
34 | /// positions (either in `&mut` or via interior mutability) |
35 | /// |
36 | /// This trait must be implemented on the `'static` version of such a type, e.g. one should |
37 | /// implement `Yokeable<'a>` (for all `'a`) on `Cow<'static, T>`. |
38 | /// |
39 | /// There are further constraints on implementation safety on individual methods. |
40 | /// |
41 | /// # Trait bounds |
42 | /// |
43 | /// [Compiler bug #85636](https://github.com/rust-lang/rust/issues/85636) makes it tricky to add |
44 | /// trait bounds on `Yokeable::Output`. For more information and for workarounds, see |
45 | /// [`crate::trait_hack`]. |
46 | /// |
47 | /// # Implementation example |
48 | /// |
49 | /// Implementing this trait manually is unsafe. Where possible, you should use the safe |
50 | /// [`#[derive(Yokeable)]`](yoke_derive::Yokeable) custom derive instead. We include an example |
51 | /// in case you have your own zero-copy abstractions you wish to make yokeable. |
52 | /// |
53 | /// ```rust |
54 | /// # use yoke::Yokeable; |
55 | /// # use std::borrow::Cow; |
56 | /// # use std::{mem, ptr}; |
57 | /// struct Bar<'a> { |
58 | /// numbers: Cow<'a, [u8]>, |
59 | /// string: Cow<'a, str>, |
60 | /// owned: Vec<u8>, |
61 | /// } |
62 | /// |
63 | /// unsafe impl<'a> Yokeable<'a> for Bar<'static> { |
64 | /// type Output = Bar<'a>; |
65 | /// fn transform(&'a self) -> &'a Bar<'a> { |
66 | /// // covariant lifetime cast, can be done safely |
67 | /// self |
68 | /// } |
69 | /// |
70 | /// fn transform_owned(self) -> Bar<'a> { |
71 | /// // covariant lifetime cast, can be done safely |
72 | /// self |
73 | /// } |
74 | /// |
75 | /// unsafe fn make(from: Bar<'a>) -> Self { |
76 | /// // We're just doing mem::transmute() here, however Rust is |
77 | /// // not smart enough to realize that Bar<'a> and Bar<'static> are of |
78 | /// // the same size, so instead we use transmute_copy |
79 | /// |
80 | /// // This assert will be optimized out, but is included for additional |
81 | /// // peace of mind as we are using transmute_copy |
82 | /// debug_assert!(mem::size_of::<Bar<'a>>() == mem::size_of::<Self>()); |
83 | /// let ptr: *const Self = (&from as *const Self::Output).cast(); |
84 | /// mem::forget(from); |
85 | /// ptr::read(ptr) |
86 | /// } |
87 | /// |
88 | /// fn transform_mut<F>(&'a mut self, f: F) |
89 | /// where |
90 | /// F: 'static + FnOnce(&'a mut Self::Output), |
91 | /// { |
92 | /// unsafe { f(mem::transmute::<&mut Self, &mut Self::Output>(self)) } |
93 | /// } |
94 | /// } |
95 | /// ``` |
96 | pub unsafe trait Yokeable<'a>: 'static { |
97 | /// This type MUST be `Self` with the `'static` replaced with `'a`, i.e. `Self<'a>` |
98 | type Output: 'a; |
99 | |
100 | /// This method must cast `self` between `&'a Self<'static>` and `&'a Self<'a>`. |
101 | /// |
102 | /// # Implementation safety |
103 | /// |
104 | /// If the invariants of [`Yokeable`] are being satisfied, the body of this method |
105 | /// should simply be `{ self }`, though it's acceptable to include additional assertions |
106 | /// if desired. |
107 | fn transform(&'a self) -> &'a Self::Output; |
108 | |
109 | /// This method must cast `self` between `Self<'static>` and `Self<'a>`. |
110 | /// |
111 | /// # Implementation safety |
112 | /// |
113 | /// If the invariants of [`Yokeable`] are being satisfied, the body of this method |
114 | /// should simply be `{ self }`, though it's acceptable to include additional assertions |
115 | /// if desired. |
116 | fn transform_owned(self) -> Self::Output; |
117 | |
118 | /// This method can be used to cast away `Self<'a>`'s lifetime. |
119 | /// |
120 | /// # Safety |
121 | /// |
122 | /// The returned value must be destroyed before the data `from` was borrowing from is. |
123 | /// |
124 | /// # Implementation safety |
125 | /// |
126 | /// A safe implementation of this method must be equivalent to a transmute between |
127 | /// `Self<'a>` and `Self<'static>` |
128 | unsafe fn make(from: Self::Output) -> Self; |
129 | |
130 | /// This method must cast `self` between `&'a mut Self<'static>` and `&'a mut Self<'a>`, |
131 | /// and pass it to `f`. |
132 | /// |
133 | /// # Implementation safety |
134 | /// |
135 | /// A safe implementation of this method must be equivalent to a pointer cast/transmute between |
136 | /// `&mut Self<'a>` and `&mut Self<'static>` being passed to `f` |
137 | /// |
138 | /// # Why is this safe? |
139 | /// |
140 | /// Typically covariant lifetimes become invariant when hidden behind an `&mut`, |
141 | /// which is why the implementation of this method cannot just be `f(self)`. |
142 | /// The reason behind this is that while _reading_ a covariant lifetime that has been cast to a shorter |
143 | /// one is always safe (this is roughly the definition of a covariant lifetime), writing |
144 | /// may not necessarily be safe since you could write a smaller reference to it. For example, |
145 | /// the following code is unsound because it manages to stuff a `'a` lifetime into a `Cow<'static>` |
146 | /// |
147 | /// ```rust,compile_fail |
148 | /// # use std::borrow::Cow; |
149 | /// # use yoke::Yokeable; |
150 | /// struct Foo { |
151 | /// str: String, |
152 | /// cow: Cow<'static, str>, |
153 | /// } |
154 | /// |
155 | /// fn unsound<'a>(foo: &'a mut Foo) { |
156 | /// let a: &str = &foo.str; |
157 | /// foo.cow.transform_mut(|cow| *cow = Cow::Borrowed(a)); |
158 | /// } |
159 | /// ``` |
160 | /// |
161 | /// However, this code will not compile because [`Yokeable::transform_mut()`] requires `F: 'static`. |
162 | /// This enforces that while `F` may mutate `Self<'a>`, it can only mutate it in a way that does |
163 | /// not insert additional references. For example, `F` may call `to_owned()` on a `Cow` and mutate it, |
164 | /// but it cannot insert a new _borrowed_ reference because it has nowhere to borrow _from_ -- |
165 | /// `f` does not contain any borrowed references, and while we give it `Self<'a>` (which contains borrowed |
166 | /// data), that borrowed data is known to be valid |
167 | /// |
168 | /// Note that the `for<'b>` is also necessary, otherwise the following code would compile: |
169 | /// |
170 | /// ```rust,compile_fail |
171 | /// # use std::borrow::Cow; |
172 | /// # use yoke::Yokeable; |
173 | /// # use std::mem; |
174 | /// # |
175 | /// // also safely implements Yokeable<'a> |
176 | /// struct Bar<'a> { |
177 | /// num: u8, |
178 | /// cow: Cow<'a, u8>, |
179 | /// } |
180 | /// |
181 | /// fn unsound<'a>(bar: &'a mut Bar<'static>) { |
182 | /// bar.transform_mut(move |bar| bar.cow = Cow::Borrowed(&bar.num)); |
183 | /// } |
184 | /// # |
185 | /// # unsafe impl<'a> Yokeable<'a> for Bar<'static> { |
186 | /// # type Output = Bar<'a>; |
187 | /// # fn transform(&'a self) -> &'a Bar<'a> { |
188 | /// # self |
189 | /// # } |
190 | /// # |
191 | /// # fn transform_owned(self) -> Bar<'a> { |
192 | /// # // covariant lifetime cast, can be done safely |
193 | /// # self |
194 | /// # } |
195 | /// # |
196 | /// # unsafe fn make(from: Bar<'a>) -> Self { |
197 | /// # let ret = mem::transmute_copy(&from); |
198 | /// # mem::forget(from); |
199 | /// # ret |
200 | /// # } |
201 | /// # |
202 | /// # fn transform_mut<F>(&'a mut self, f: F) |
203 | /// # where |
204 | /// # F: 'static + FnOnce(&'a mut Self::Output), |
205 | /// # { |
206 | /// # unsafe { f(mem::transmute(self)) } |
207 | /// # } |
208 | /// # } |
209 | /// ``` |
210 | /// |
211 | /// which is unsound because `bar` could be moved later, and we do not want to be able to |
212 | /// self-insert references to it. |
213 | /// |
214 | /// The `for<'b>` enforces this by stopping the author of the closure from matching up the input |
215 | /// `&'b Self::Output` lifetime with `'a` and borrowing directly from it. |
216 | /// |
217 | /// Thus the only types of mutations allowed are ones that move around already-borrowed data, or |
218 | /// introduce new owned data: |
219 | /// |
220 | /// ```rust |
221 | /// # use std::borrow::Cow; |
222 | /// # use yoke::Yokeable; |
223 | /// struct Foo { |
224 | /// str: String, |
225 | /// cow: Cow<'static, str>, |
226 | /// } |
227 | /// |
228 | /// fn sound<'a>(foo: &'a mut Foo) { |
229 | /// foo.cow.transform_mut(move |cow| cow.to_mut().push('a' )); |
230 | /// } |
231 | /// ``` |
232 | fn transform_mut<F>(&'a mut self, f: F) |
233 | where |
234 | // be VERY CAREFUL changing this signature, it is very nuanced (see above) |
235 | F: 'static + for<'b> FnOnce(&'b mut Self::Output); |
236 | } |
237 | |
238 | #[cfg (feature = "alloc" )] |
239 | unsafe impl<'a, T: 'static + ToOwned + ?Sized> Yokeable<'a> for Cow<'static, T> |
240 | where |
241 | <T as ToOwned>::Owned: Sized, |
242 | { |
243 | type Output = Cow<'a, T>; |
244 | #[inline ] |
245 | fn transform(&'a self) -> &'a Cow<'a, T> { |
246 | // Doesn't need unsafe: `'a` is covariant so this lifetime cast is always safe |
247 | self |
248 | } |
249 | #[inline ] |
250 | fn transform_owned(self) -> Cow<'a, T> { |
251 | // Doesn't need unsafe: `'a` is covariant so this lifetime cast is always safe |
252 | self |
253 | } |
254 | #[inline ] |
255 | unsafe fn make(from: Cow<'a, T>) -> Self { |
256 | // i hate this |
257 | // unfortunately Rust doesn't think `mem::transmute` is possible since it's not sure the sizes |
258 | // are the same |
259 | debug_assert!(mem::size_of::<Cow<'a, T>>() == mem::size_of::<Self>()); |
260 | let ptr: *const Self = (&from as *const Self::Output).cast(); |
261 | mem::forget(from); |
262 | core::ptr::read(ptr) |
263 | } |
264 | #[inline ] |
265 | fn transform_mut<F>(&'a mut self, f: F) |
266 | where |
267 | F: 'static + for<'b> FnOnce(&'b mut Self::Output), |
268 | { |
269 | // Cast away the lifetime of Self |
270 | unsafe { f(mem::transmute::<&'a mut Self, &'a mut Self::Output>(self)) } |
271 | } |
272 | } |
273 | |
274 | unsafe impl<'a, T: 'static + ?Sized> Yokeable<'a> for &'static T { |
275 | type Output = &'a T; |
276 | #[inline ] |
277 | fn transform(&'a self) -> &'a &'a T { |
278 | // Doesn't need unsafe: `'a` is covariant so this lifetime cast is always safe |
279 | self |
280 | } |
281 | #[inline ] |
282 | fn transform_owned(self) -> &'a T { |
283 | // Doesn't need unsafe: `'a` is covariant so this lifetime cast is always safe |
284 | self |
285 | } |
286 | #[inline ] |
287 | unsafe fn make(from: &'a T) -> Self { |
288 | mem::transmute(from) |
289 | } |
290 | #[inline ] |
291 | fn transform_mut<F>(&'a mut self, f: F) |
292 | where |
293 | F: 'static + for<'b> FnOnce(&'b mut Self::Output), |
294 | { |
295 | // Cast away the lifetime of Self |
296 | unsafe { f(mem::transmute::<&'a mut Self, &'a mut Self::Output>(self)) } |
297 | } |
298 | } |
299 | |
300 | #[cfg (feature = "alloc" )] |
301 | unsafe impl<'a, T: 'static> Yokeable<'a> for alloc::vec::Vec<T> { |
302 | type Output = alloc::vec::Vec<T>; |
303 | #[inline ] |
304 | fn transform(&'a self) -> &'a alloc::vec::Vec<T> { |
305 | // Doesn't need unsafe: `'a` is covariant so this lifetime cast is always safe |
306 | self |
307 | } |
308 | #[inline ] |
309 | fn transform_owned(self) -> alloc::vec::Vec<T> { |
310 | // Doesn't need unsafe: `'a` is covariant so this lifetime cast is always safe |
311 | self |
312 | } |
313 | #[inline ] |
314 | unsafe fn make(from: alloc::vec::Vec<T>) -> Self { |
315 | from |
316 | } |
317 | #[inline ] |
318 | fn transform_mut<F>(&'a mut self, f: F) |
319 | where |
320 | F: 'static + for<'b> FnOnce(&'b mut Self::Output), |
321 | { |
322 | // Doesn't need unsafe: `'a` is covariant so this lifetime cast is always safe |
323 | f(self) |
324 | } |
325 | } |
326 | |