]> git.proxmox.com Git - rustc.git/blob - vendor/yoke/src/is_covariant.rs
New upstream version 1.67.1+dfsg1
[rustc.git] / vendor / yoke / src / is_covariant.rs
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::{
7 borrow::{Cow, ToOwned},
8 boxed::Box,
9 rc::Rc,
10 string::String,
11 };
12
13 /// A type implementing `IsCovariant<'a>` is covariant with respect to lifetime `'a`.
14 ///
15 /// Lifetime parameters that are safely cast in [`Yokeable`] are also valid for `IsCovariant`.
16 ///
17 /// `IsCovariant` exists primarily to serve in trait bounds. The primary use case is to safely
18 /// perform lifetime casting on trait objects (`dyn Trait`). This enables a type-erased [`Yoke`]
19 /// consisting of only trait objects. See the examples.
20 ///
21 /// `IsCovariant` is auto-implemented in [`#[derive(Yokeable)]`](macro@crate::Yokeable).
22 ///
23 /// # Safety
24 ///
25 /// This trait is safe to implement on types with a _covariant_ lifetime parameter. This will
26 /// occur when the lifetime parameter is used within references, but not in the arguments of
27 /// function pointers or in mutable positions (either in `&mut` or via interior mutability).
28 ///
29 /// If a struct has multiple lifetime parameters, only the one used in `IsCovariant<'a>` needs to
30 /// be covariant.
31 ///
32 /// # Examples
33 ///
34 /// Implementing on a simple struct with a single covariant lifetime:
35 ///
36 /// ```
37 /// # use yoke::*;
38 /// struct MyStruct<'a>(&'a str);
39 ///
40 /// // This is safe because 'a is covariant
41 /// unsafe impl<'a> IsCovariant<'a> for MyStruct<'a> {}
42 /// ```
43 ///
44 /// By constraining the trait `ExampleTrait<'a>` on `IsCovariant<'a>`, we can safely implement
45 /// [`Yokeable`] and [`ZeroFrom`] on its trait object:
46 ///
47 /// ```
48 /// # use yoke::*;
49 /// # use zerofrom::*;
50 /// # use core::mem;
51 /// trait ExampleTrait<'a>: IsCovariant<'a> {
52 /// fn get_message(&self) -> &'a str;
53 /// }
54 ///
55 /// // This wrapper is required because of the blanket Yokeable impl on &'static T
56 /// pub struct ExampleTraitDynRef<'a>(pub &'a dyn ExampleTrait<'a>);
57 ///
58 /// // The following impl is safe because the trait object requires IsCovariant.
59 /// unsafe impl<'a> Yokeable<'a> for ExampleTraitDynRef<'static> {
60 /// type Output = ExampleTraitDynRef<'a>;
61 /// fn transform(&'a self) -> &'a Self::Output {
62 /// unsafe { mem::transmute(self) }
63 /// }
64 ///
65 /// fn transform_owned(self) -> Self::Output {
66 /// unsafe { mem::transmute(self) }
67 /// }
68 ///
69 /// unsafe fn make(from: Self::Output) -> Self {
70 /// unsafe { mem::transmute(from) }
71 /// }
72 ///
73 /// fn transform_mut<F>(&'a mut self, f: F)
74 /// where
75 /// F: 'static + FnOnce(&'a mut Self::Output),
76 /// {
77 /// unsafe { f(mem::transmute::<&mut Self, &mut Self::Output>(self)) }
78 /// }
79 /// }
80 ///
81 /// impl<'zf, 'a> ZeroFrom<'zf, dyn ExampleTrait<'a> + 'a> for ExampleTraitDynRef<'zf> {
82 /// fn zero_from(this: &'zf (dyn ExampleTrait<'a> + 'a)) -> ExampleTraitDynRef<'zf> {
83 /// // This is safe because the trait object requires IsCovariant.
84 /// ExampleTraitDynRef(unsafe { core::mem::transmute(this) })
85 /// }
86 /// }
87 ///
88 /// // Implement ExampleTrait on the struct from the previous example
89 /// # struct MyStruct<'a>(&'a str);
90 /// # unsafe impl<'a> IsCovariant<'a> for MyStruct<'a> {}
91 /// impl<'a> ExampleTrait<'a> for MyStruct<'a> {
92 /// fn get_message(&self) -> &'a str {
93 /// self.0
94 /// }
95 /// }
96 ///
97 /// // Example usage: a Yoke of a trait object
98 /// let s = "Hello World".to_string();
99 /// let yoke: Yoke<ExampleTraitDynRef<'static>, Box<dyn ExampleTrait>> =
100 /// Yoke::attach_to_zero_copy_cart(Box::new(MyStruct(&s)));
101 ///
102 /// assert_eq!(yoke.get().0.get_message(), "Hello World");
103 /// ```
104 ///
105 /// [`Yoke`]: crate::Yoke
106 /// [`Yokeable`]: crate::Yokeable
107 /// [`ZeroFrom`]: crate::ZeroFrom
108 pub unsafe trait IsCovariant<'a>: 'a {}
109
110 // IsCovariant is implemented on the standard library Copy types in macro_impls.rs
111
112 // The following impls are safe because there is only one lifetime, 'a, and 'a is covariant
113
114 unsafe impl<'a> IsCovariant<'a> for () {}
115
116 unsafe impl<'a> IsCovariant<'a> for str {}
117 #[cfg(feature = "alloc")]
118 unsafe impl<'a> IsCovariant<'a> for String {}
119
120 unsafe impl<'a, T: IsCovariant<'a>> IsCovariant<'a> for Option<T> {}
121
122 unsafe impl<'a, T1: IsCovariant<'a>, T2: IsCovariant<'a>> IsCovariant<'a> for (T1, T2) {}
123
124 unsafe impl<'a, T: IsCovariant<'a>> IsCovariant<'a> for [T] {}
125
126 unsafe impl<'a, T: IsCovariant<'a>, const N: usize> IsCovariant<'a> for [T; N] {}
127
128 #[cfg(feature = "alloc")]
129 unsafe impl<'a, T: IsCovariant<'a> + ?Sized> IsCovariant<'a> for Box<T> {}
130
131 #[cfg(feature = "alloc")]
132 unsafe impl<'a, T: IsCovariant<'a> + ?Sized> IsCovariant<'a> for Rc<T> {}
133
134 // This is safe because T has a covariant lifetime, and Cow's lifetime is also covariant
135 #[cfg(feature = "alloc")]
136 unsafe impl<'a, T: IsCovariant<'a> + ToOwned + ?Sized> IsCovariant<'a> for Cow<'a, T> where
137 <T as ToOwned>::Owned: Sized
138 {
139 }
140
141 // This is safe because T has a covariant lifetime, and the reference lifetime is also covariant
142 unsafe impl<'a, T: IsCovariant<'a> + ?Sized> IsCovariant<'a> for &'a T {}