summaryrefslogtreecommitdiffstats
path: root/vendor/yoke/src/is_covariant.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/yoke/src/is_covariant.rs')
-rw-r--r--vendor/yoke/src/is_covariant.rs142
1 files changed, 142 insertions, 0 deletions
diff --git a/vendor/yoke/src/is_covariant.rs b/vendor/yoke/src/is_covariant.rs
new file mode 100644
index 000000000..75d123c84
--- /dev/null
+++ b/vendor/yoke/src/is_covariant.rs
@@ -0,0 +1,142 @@
+// This file is part of ICU4X. For terms of use, please see the file
+// called LICENSE at the top level of the ICU4X source tree
+// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
+
+#[cfg(feature = "alloc")]
+use alloc::{
+ borrow::{Cow, ToOwned},
+ boxed::Box,
+ rc::Rc,
+ string::String,
+};
+
+/// A type implementing `IsCovariant<'a>` is covariant with respect to lifetime `'a`.
+///
+/// Lifetime parameters that are safely cast in [`Yokeable`] are also valid for `IsCovariant`.
+///
+/// `IsCovariant` exists primarily to serve in trait bounds. The primary use case is to safely
+/// perform lifetime casting on trait objects (`dyn Trait`). This enables a type-erased [`Yoke`]
+/// consisting of only trait objects. See the examples.
+///
+/// `IsCovariant` is auto-implemented in [`#[derive(Yokeable)]`](macro@crate::Yokeable).
+///
+/// # Safety
+///
+/// This trait is safe to implement on types with a _covariant_ lifetime parameter. This will
+/// occur when the lifetime parameter is used within references, but not in the arguments of
+/// function pointers or in mutable positions (either in `&mut` or via interior mutability).
+///
+/// If a struct has multiple lifetime parameters, only the one used in `IsCovariant<'a>` needs to
+/// be covariant.
+///
+/// # Examples
+///
+/// Implementing on a simple struct with a single covariant lifetime:
+///
+/// ```
+/// # use yoke::*;
+/// struct MyStruct<'a>(&'a str);
+///
+/// // This is safe because 'a is covariant
+/// unsafe impl<'a> IsCovariant<'a> for MyStruct<'a> {}
+/// ```
+///
+/// By constraining the trait `ExampleTrait<'a>` on `IsCovariant<'a>`, we can safely implement
+/// [`Yokeable`] and [`ZeroFrom`] on its trait object:
+///
+/// ```
+/// # use yoke::*;
+/// # use zerofrom::*;
+/// # use core::mem;
+/// trait ExampleTrait<'a>: IsCovariant<'a> {
+/// fn get_message(&self) -> &'a str;
+/// }
+///
+/// // This wrapper is required because of the blanket Yokeable impl on &'static T
+/// pub struct ExampleTraitDynRef<'a>(pub &'a dyn ExampleTrait<'a>);
+///
+/// // The following impl is safe because the trait object requires IsCovariant.
+/// unsafe impl<'a> Yokeable<'a> for ExampleTraitDynRef<'static> {
+/// type Output = ExampleTraitDynRef<'a>;
+/// fn transform(&'a self) -> &'a Self::Output {
+/// unsafe { mem::transmute(self) }
+/// }
+///
+/// fn transform_owned(self) -> Self::Output {
+/// unsafe { mem::transmute(self) }
+/// }
+///
+/// unsafe fn make(from: Self::Output) -> Self {
+/// unsafe { mem::transmute(from) }
+/// }
+///
+/// fn transform_mut<F>(&'a mut self, f: F)
+/// where
+/// F: 'static + FnOnce(&'a mut Self::Output),
+/// {
+/// unsafe { f(mem::transmute::<&mut Self, &mut Self::Output>(self)) }
+/// }
+/// }
+///
+/// impl<'zf, 'a> ZeroFrom<'zf, dyn ExampleTrait<'a> + 'a> for ExampleTraitDynRef<'zf> {
+/// fn zero_from(this: &'zf (dyn ExampleTrait<'a> + 'a)) -> ExampleTraitDynRef<'zf> {
+/// // This is safe because the trait object requires IsCovariant.
+/// ExampleTraitDynRef(unsafe { core::mem::transmute(this) })
+/// }
+/// }
+///
+/// // Implement ExampleTrait on the struct from the previous example
+/// # struct MyStruct<'a>(&'a str);
+/// # unsafe impl<'a> IsCovariant<'a> for MyStruct<'a> {}
+/// impl<'a> ExampleTrait<'a> for MyStruct<'a> {
+/// fn get_message(&self) -> &'a str {
+/// self.0
+/// }
+/// }
+///
+/// // Example usage: a Yoke of a trait object
+/// let s = "Hello World".to_string();
+/// let yoke: Yoke<ExampleTraitDynRef<'static>, Box<dyn ExampleTrait>> =
+/// Yoke::attach_to_zero_copy_cart(Box::new(MyStruct(&s)));
+///
+/// assert_eq!(yoke.get().0.get_message(), "Hello World");
+/// ```
+///
+/// [`Yoke`]: crate::Yoke
+/// [`Yokeable`]: crate::Yokeable
+/// [`ZeroFrom`]: crate::ZeroFrom
+pub unsafe trait IsCovariant<'a>: 'a {}
+
+// IsCovariant is implemented on the standard library Copy types in macro_impls.rs
+
+// The following impls are safe because there is only one lifetime, 'a, and 'a is covariant
+
+unsafe impl<'a> IsCovariant<'a> for () {}
+
+unsafe impl<'a> IsCovariant<'a> for str {}
+#[cfg(feature = "alloc")]
+unsafe impl<'a> IsCovariant<'a> for String {}
+
+unsafe impl<'a, T: IsCovariant<'a>> IsCovariant<'a> for Option<T> {}
+
+unsafe impl<'a, T1: IsCovariant<'a>, T2: IsCovariant<'a>> IsCovariant<'a> for (T1, T2) {}
+
+unsafe impl<'a, T: IsCovariant<'a>> IsCovariant<'a> for [T] {}
+
+unsafe impl<'a, T: IsCovariant<'a>, const N: usize> IsCovariant<'a> for [T; N] {}
+
+#[cfg(feature = "alloc")]
+unsafe impl<'a, T: IsCovariant<'a> + ?Sized> IsCovariant<'a> for Box<T> {}
+
+#[cfg(feature = "alloc")]
+unsafe impl<'a, T: IsCovariant<'a> + ?Sized> IsCovariant<'a> for Rc<T> {}
+
+// This is safe because T has a covariant lifetime, and Cow's lifetime is also covariant
+#[cfg(feature = "alloc")]
+unsafe impl<'a, T: IsCovariant<'a> + ToOwned + ?Sized> IsCovariant<'a> for Cow<'a, T> where
+ <T as ToOwned>::Owned: Sized
+{
+}
+
+// This is safe because T has a covariant lifetime, and the reference lifetime is also covariant
+unsafe impl<'a, T: IsCovariant<'a> + ?Sized> IsCovariant<'a> for &'a T {}