Coverage Report

Created: 2026-05-16 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}