Trait yoke::IsCovariant
source · [−]pub unsafe trait IsCovariant<'a>: 'a { }
Expand description
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)]
.
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:
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 ZeroCopyFrom
on its trait object:
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<'zcf, 'a> ZeroCopyFrom<'zcf, dyn ExampleTrait<'a> + 'a> for ExampleTraitDynRef<'zcf> {
fn zero_copy_from(this: &'zcf (dyn ExampleTrait<'a> + 'a)) -> ExampleTraitDynRef<'zcf> {
// This is safe because the trait object requires IsCovariant.
ExampleTraitDynRef(unsafe { core::mem::transmute(this) })
}
}
// Implement ExampleTrait on the struct from the previous example
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");