Coverage Report

Created: 2025-08-26 06:41

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