/rust/registry/src/index.crates.io-1949cf8c6b5b557f/yoke-0.8.2/src/yokeable.rs
Line | Count | Source |
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 | | #![allow(unused_qualifications)] |
6 | | |
7 | | #[cfg(feature = "alloc")] |
8 | | use alloc::borrow::{Cow, ToOwned}; |
9 | | use core::marker::PhantomData; |
10 | | |
11 | | /// The `Yokeable<'a>` trait is implemented on the `'static` version of any zero-copy type; for |
12 | | /// example, `Cow<'static, T>` implements `Yokeable<'a>` (for all `'a`). |
13 | | /// |
14 | | /// One can use |
15 | | /// `Yokeable::Output` on this trait to obtain the "lifetime'd" value of the `Cow<'static, T>`, |
16 | | /// e.g. `<Cow<'static, T> as Yokeable<'a>'>::Output` is `Cow<'a, T>`. |
17 | | /// |
18 | | /// A [`Yokeable`] type is essentially one with a covariant lifetime parameter, |
19 | | /// matched to the parameter in the trait definition. The trait allows one to cast |
20 | | /// the covariant lifetime to and from `'static`. |
21 | | /// |
22 | | /// **Most of the time, if you need to implement [`Yokeable`], you should be able to use the safe |
23 | | /// [`#[derive(Yokeable)]`](yoke_derive::Yokeable) custom derive.** |
24 | | /// |
25 | | /// While Rust does not yet have GAT syntax, for the purpose of this documentation |
26 | | /// we shall refer to "`Self` with a lifetime `'a`" with the syntax `Self<'a>`. |
27 | | /// Self<'static> is a stand-in for the HKT Self<'_>: lifetime -> type. |
28 | | /// |
29 | | /// With this terminology, [`Yokeable`] exposes ways to cast between `Self<'static>` and `Self<'a>` generically. |
30 | | /// This is useful for turning covariant lifetimes to _dynamic_ lifetimes, where `'static` is |
31 | | /// used as a way to "erase" the lifetime. |
32 | | /// |
33 | | /// # Safety |
34 | | /// |
35 | | /// This trait is safe to implement on types with a _covariant_ lifetime parameter, i.e. one where |
36 | | /// [`Self::transform()`]'s body can simply be `{ self }`. This will occur when the lifetime |
37 | | /// parameter is used within references, but not in the arguments of function pointers or in mutable |
38 | | /// positions (either in `&mut` or via interior mutability) |
39 | | /// |
40 | | /// This trait must be implemented on the `'static` version of such a type, e.g. one should |
41 | | /// implement `Yokeable<'a>` (for all `'a`) on `Cow<'static, T>`. |
42 | | /// |
43 | | /// This trait is also safe to implement on types that do not borrow memory. |
44 | | /// |
45 | | /// There are further constraints on implementation safety on individual methods. |
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 | | /// unsafe { mem::transmute::<Self::Output, Self>(from) } |
77 | | /// } |
78 | | /// |
79 | | /// fn transform_mut<F>(&'a mut self, f: F) |
80 | | /// where |
81 | | /// F: 'static + FnOnce(&'a mut Self::Output), |
82 | | /// { |
83 | | /// unsafe { f(mem::transmute::<&mut Self, &mut Self::Output>(self)) } |
84 | | /// } |
85 | | /// } |
86 | | /// ``` |
87 | | pub unsafe trait Yokeable<'a>: 'static { |
88 | | /// This type MUST be `Self` with the `'static` replaced with `'a`, i.e. `Self<'a>` |
89 | | type Output: 'a; |
90 | | |
91 | | /// This method must cast `self` between `&'a Self<'static>` and `&'a Self<'a>`. |
92 | | /// |
93 | | /// # Implementation safety |
94 | | /// |
95 | | /// If the invariants of [`Yokeable`] are being satisfied, the body of this method |
96 | | /// should simply be `{ self }`, though it's acceptable to include additional assertions |
97 | | /// if desired. |
98 | | fn transform(&'a self) -> &'a Self::Output; |
99 | | |
100 | | /// This method must cast `self` between `Self<'static>` and `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_owned(self) -> Self::Output; |
108 | | |
109 | | /// This method can be used to cast away `Self<'a>`'s lifetime. |
110 | | /// |
111 | | /// # Safety |
112 | | /// |
113 | | /// The returned value must be destroyed before the data `from` was borrowing from is. |
114 | | /// |
115 | | /// # Implementation safety |
116 | | /// |
117 | | /// A safe implementation of this method must be equivalent to a transmute between |
118 | | /// `Self<'a>` and `Self<'static>` |
119 | | unsafe fn make(from: Self::Output) -> Self; |
120 | | |
121 | | /// This method must cast `self` between `&'a mut Self<'static>` and `&'a mut Self<'a>`, |
122 | | /// and pass it to `f`. |
123 | | /// |
124 | | /// # Implementation safety |
125 | | /// |
126 | | /// A safe implementation of this method must be equivalent to a pointer cast/transmute between |
127 | | /// `&mut Self<'a>` and `&mut Self<'static>` being passed to `f` |
128 | | /// |
129 | | /// # Why is this safe? |
130 | | /// |
131 | | /// Typically covariant lifetimes become invariant when hidden behind an `&mut`, |
132 | | /// which is why the implementation of this method cannot just be `f(self)`. |
133 | | /// The reason behind this is that while _reading_ a covariant lifetime that has been cast to a shorter |
134 | | /// one is always safe (this is roughly the definition of a covariant lifetime), writing |
135 | | /// may not necessarily be safe since you could write a smaller reference to it. For example, |
136 | | /// the following code is unsound because it manages to stuff a `'a` lifetime into a `Cow<'static>` |
137 | | /// |
138 | | /// ```rust,compile_fail,E0521 |
139 | | /// # use std::borrow::Cow; |
140 | | /// # use yoke::Yokeable; |
141 | | /// struct Foo { |
142 | | /// str: String, |
143 | | /// cow: Cow<'static, str>, |
144 | | /// } |
145 | | /// |
146 | | /// fn unsound<'a>(foo: &'a mut Foo) { |
147 | | /// let a: &str = &foo.str; |
148 | | /// foo.cow.transform_mut(|cow| *cow = Cow::Borrowed(a)); |
149 | | /// } |
150 | | /// ``` |
151 | | /// |
152 | | /// However, this code will not compile because [`Yokeable::transform_mut()`] requires `F: 'static`. |
153 | | /// This enforces that while `F` may mutate `Self<'a>`, it can only mutate it in a way that does |
154 | | /// not insert additional references. For example, `F` may call `to_owned()` on a `Cow` and mutate it, |
155 | | /// but it cannot insert a new _borrowed_ reference because it has nowhere to borrow _from_ -- |
156 | | /// `f` does not contain any borrowed references, and while we give it `Self<'a>` (which contains borrowed |
157 | | /// data), that borrowed data is known to be valid |
158 | | /// |
159 | | /// Note that the `for<'b>` is also necessary, otherwise the following code would compile: |
160 | | /// |
161 | | /// ```rust,compile_fail,E0521 |
162 | | /// # use std::borrow::Cow; |
163 | | /// # use yoke::Yokeable; |
164 | | /// # use std::mem; |
165 | | /// # |
166 | | /// // also safely implements Yokeable<'a> |
167 | | /// struct Bar<'a> { |
168 | | /// num: u8, |
169 | | /// cow: Cow<'a, u8>, |
170 | | /// } |
171 | | /// |
172 | | /// fn unsound<'a>(bar: &'a mut Bar<'static>) { |
173 | | /// bar.transform_mut(move |bar| bar.cow = Cow::Borrowed(&bar.num)); |
174 | | /// } |
175 | | /// # |
176 | | /// # unsafe impl<'a> Yokeable<'a> for Bar<'static> { |
177 | | /// # type Output = Bar<'a>; |
178 | | /// # fn transform(&'a self) -> &'a Bar<'a> { |
179 | | /// # self |
180 | | /// # } |
181 | | /// # |
182 | | /// # fn transform_owned(self) -> Bar<'a> { |
183 | | /// # // covariant lifetime cast, can be done safely |
184 | | /// # self |
185 | | /// # } |
186 | | /// # |
187 | | /// # unsafe fn make(from: Bar<'a>) -> Self { |
188 | | /// # let ret = mem::transmute_copy(&from); |
189 | | /// # mem::forget(from); |
190 | | /// # ret |
191 | | /// # } |
192 | | /// # |
193 | | /// # fn transform_mut<F>(&'a mut self, f: F) |
194 | | /// # where |
195 | | /// # F: 'static + FnOnce(&'a mut Self::Output), |
196 | | /// # { |
197 | | /// # unsafe { f(mem::transmute(self)) } |
198 | | /// # } |
199 | | /// # } |
200 | | /// ``` |
201 | | /// |
202 | | /// which is unsound because `bar` could be moved later, and we do not want to be able to |
203 | | /// self-insert references to it. |
204 | | /// |
205 | | /// The `for<'b>` enforces this by stopping the author of the closure from matching up the input |
206 | | /// `&'b Self::Output` lifetime with `'a` and borrowing directly from it. |
207 | | /// |
208 | | /// Thus the only types of mutations allowed are ones that move around already-borrowed data, or |
209 | | /// introduce new owned data: |
210 | | /// |
211 | | /// ```rust |
212 | | /// # use std::borrow::Cow; |
213 | | /// # use yoke::Yokeable; |
214 | | /// struct Foo { |
215 | | /// str: String, |
216 | | /// cow: Cow<'static, str>, |
217 | | /// } |
218 | | /// |
219 | | /// fn sound(foo: &mut Foo) { |
220 | | /// foo.cow.transform_mut(move |cow| cow.to_mut().push('a')); |
221 | | /// } |
222 | | /// ``` |
223 | | /// |
224 | | /// More formally, a reference to an object that `f` assigns to a reference |
225 | | /// in Self<'a> could be obtained from: |
226 | | /// - a local variable: the compiler rejects the assignment because 'a certainly |
227 | | /// outlives local variables in f. |
228 | | /// - a field in its argument: because of the for<'b> bound, the call to `f` |
229 | | /// must be valid for a particular 'b that is strictly shorter than 'a. Thus, |
230 | | /// the compiler rejects the assignment. |
231 | | /// - a reference field in Self<'a>: this does not extend the set of |
232 | | /// non-static lifetimes reachable from Self<'a>, so this is fine. |
233 | | /// - one of f's captures: since F: 'static, the resulting reference must refer |
234 | | /// to 'static data. |
235 | | /// - a static or `thread_local` variable: ditto. |
236 | | fn transform_mut<F>(&'a mut self, f: F) |
237 | | where |
238 | | // be VERY CAREFUL changing this signature, it is very nuanced (see above) |
239 | | F: 'static + for<'b> FnOnce(&'b mut Self::Output); |
240 | | } |
241 | | |
242 | | #[cfg(feature = "alloc")] |
243 | | // Safety: Cow<'a, _> is covariant in 'a. |
244 | | unsafe impl<'a, T: 'static + ToOwned + ?Sized> Yokeable<'a> for Cow<'static, T> |
245 | | where |
246 | | <T as ToOwned>::Owned: Sized, |
247 | | { |
248 | | type Output = Cow<'a, T>; |
249 | | #[inline] |
250 | | fn transform(&'a self) -> &'a Cow<'a, T> { |
251 | | // Doesn't need unsafe: `'a` is covariant so this lifetime cast is always safe |
252 | | self |
253 | | } |
254 | | #[inline] |
255 | | fn transform_owned(self) -> Cow<'a, T> { |
256 | | // Doesn't need unsafe: `'a` is covariant so this lifetime cast is always safe |
257 | | self |
258 | | } |
259 | | #[inline] |
260 | | unsafe fn make(from: Cow<'a, T>) -> Self { |
261 | | core::mem::transmute::<Self::Output, Self>(from) |
262 | | } |
263 | | #[inline] |
264 | | fn transform_mut<F>(&'a mut self, f: F) |
265 | | where |
266 | | F: 'static + for<'b> FnOnce(&'b mut Self::Output), |
267 | | { |
268 | | // Cast away the lifetime of Self |
269 | | // Safety: this is equivalent to f(transmute(self)), and the documentation of the trait |
270 | | // method explains why doing so is sound. |
271 | | #[allow(clippy::unnecessary_cast)] // false positive, lifetimes differ |
272 | | let y = unsafe { &mut *(self as *mut Self as *mut Self::Output) }; |
273 | | f(y) |
274 | | } |
275 | | } |
276 | | |
277 | | // Safety: &'a T is covariant in 'a. |
278 | | unsafe impl<'a, T: 'static + ?Sized> Yokeable<'a> for &'static T { |
279 | | type Output = &'a T; |
280 | | #[inline] |
281 | 0 | fn transform(&'a self) -> &'a &'a T { |
282 | | // Doesn't need unsafe: `'a` is covariant so this lifetime cast is always safe |
283 | 0 | self |
284 | 0 | } |
285 | | #[inline] |
286 | 0 | fn transform_owned(self) -> &'a T { |
287 | | // Doesn't need unsafe: `'a` is covariant so this lifetime cast is always safe |
288 | 0 | self |
289 | 0 | } |
290 | | #[inline] |
291 | 0 | unsafe fn make(from: &'a T) -> Self { |
292 | | // Safety: function safety invariant guarantees that the returned reference |
293 | | // will never be used beyond its original lifetime. |
294 | 0 | &*(from as *const T) |
295 | 0 | } |
296 | | #[inline] |
297 | 0 | fn transform_mut<F>(&'a mut self, f: F) |
298 | 0 | where |
299 | 0 | F: 'static + for<'b> FnOnce(&'b mut Self::Output), |
300 | | { |
301 | | // Cast away the lifetime of Self |
302 | | // Safety: this is equivalent to f(transmute(self)), and the documentation of the trait |
303 | | // method explains why doing so is sound. |
304 | | #[allow(clippy::unnecessary_cast)] // false positive, lifetimes differ |
305 | 0 | let y = unsafe { &mut *(self as *mut Self as *mut Self::Output) }; |
306 | 0 | f(y) |
307 | 0 | } |
308 | | } |
309 | | |
310 | | #[cfg(feature = "alloc")] |
311 | | // Safety: Vec<T: 'static> never borrows. |
312 | | unsafe impl<'a, T: 'static> Yokeable<'a> for alloc::vec::Vec<T> { |
313 | | type Output = alloc::vec::Vec<T>; |
314 | | #[inline] |
315 | | fn transform(&'a self) -> &'a alloc::vec::Vec<T> { |
316 | | self |
317 | | } |
318 | | #[inline] |
319 | | fn transform_owned(self) -> alloc::vec::Vec<T> { |
320 | | self |
321 | | } |
322 | | #[inline] |
323 | | unsafe fn make(from: alloc::vec::Vec<T>) -> Self { |
324 | | from |
325 | | } |
326 | | #[inline] |
327 | | fn transform_mut<F>(&'a mut self, f: F) |
328 | | where |
329 | | F: 'static + for<'b> FnOnce(&'b mut Self::Output), |
330 | | { |
331 | | f(self) |
332 | | } |
333 | | } |
334 | | |
335 | | // Safety: PhantomData is a ZST. |
336 | | unsafe impl<'a, T: ?Sized + 'static> Yokeable<'a> for PhantomData<T> { |
337 | | type Output = PhantomData<T>; |
338 | | |
339 | 0 | fn transform(&'a self) -> &'a Self::Output { |
340 | 0 | self |
341 | 0 | } |
342 | | |
343 | 0 | fn transform_owned(self) -> Self::Output { |
344 | 0 | self |
345 | 0 | } |
346 | | |
347 | 0 | unsafe fn make(from: Self::Output) -> Self { |
348 | 0 | from |
349 | 0 | } |
350 | | |
351 | 0 | fn transform_mut<F>(&'a mut self, f: F) |
352 | 0 | where |
353 | 0 | // be VERY CAREFUL changing this signature, it is very nuanced (see above) |
354 | 0 | F: 'static + for<'b> FnOnce(&'b mut Self::Output), |
355 | | { |
356 | 0 | f(self) |
357 | 0 | } |
358 | | } |