Trait Yokeable
pub unsafe trait Yokeable<'a>: 'static {
type Output: 'a;
// Required methods
fn transform(&'a self) -> &'a Self::Output;
fn transform_owned(self) -> Self::Output;
unsafe fn make(from: Self::Output) -> Self;
fn transform_mut<F>(&'a mut self, f: F)
where F: 'static + for<'b> FnOnce(&'b mut Self::Output);
}
Expand description
The Yokeable<'a>
trait is implemented on the 'static
version of any zero-copy type; for
example, Cow<'static, T>
implements Yokeable<'a>
(for all 'a
).
One can use
Yokeable::Output
on this trait to obtain the “lifetime’d” value of the Cow<'static, T>
,
e.g. <Cow<'static, T> as Yokeable<'a>'>::Output
is Cow<'a, T>
.
A Yokeable
type is essentially one with a covariant lifetime parameter,
matched to the parameter in the trait definition. The trait allows one to cast
the covariant lifetime to and from 'static
.
Most of the time, if you need to implement Yokeable
, you should be able to use the safe
#[derive(Yokeable)]
custom derive.
While Rust does not yet have GAT syntax, for the purpose of this documentation
we shall refer to “Self
with a lifetime 'a
” with the syntax Self<'a>
.
Self<‘static> is a stand-in for the HKT Self<’_>: lifetime -> type.
With this terminology, Yokeable
exposes ways to cast between Self<'static>
and Self<'a>
generically.
This is useful for turning covariant lifetimes to dynamic lifetimes, where 'static
is
used as a way to “erase” the lifetime.
§Safety
This trait is safe to implement on types with a covariant lifetime parameter, i.e. one where
Self::transform()
’s body can simply be { self }
. 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)
This trait must be implemented on the 'static
version of such a type, e.g. one should
implement Yokeable<'a>
(for all 'a
) on Cow<'static, T>
.
This trait is also safe to implement on types that do not borrow memory.
There are further constraints on implementation safety on individual methods.
§Implementation example
Implementing this trait manually is unsafe. Where possible, you should use the safe
#[derive(Yokeable)]
custom derive instead. We include an example
in case you have your own zero-copy abstractions you wish to make yokeable.
struct Bar<'a> {
numbers: Cow<'a, [u8]>,
string: Cow<'a, str>,
owned: Vec<u8>,
}
unsafe impl<'a> Yokeable<'a> for Bar<'static> {
type Output = Bar<'a>;
fn transform(&'a self) -> &'a Bar<'a> {
// covariant lifetime cast, can be done safely
self
}
fn transform_owned(self) -> Bar<'a> {
// covariant lifetime cast, can be done safely
self
}
unsafe fn make(from: Bar<'a>) -> Self {
// We're just doing mem::transmute() here, however Rust is
// not smart enough to realize that Bar<'a> and Bar<'static> are of
// the same size, so instead we use transmute_copy
// This assert will be optimized out, but is included for additional
// peace of mind as we are using transmute_copy
debug_assert!(mem::size_of::<Bar<'a>>() == mem::size_of::<Self>());
let ptr: *const Self = (&from as *const Self::Output).cast();
mem::forget(from);
ptr::read(ptr)
}
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)) }
}
}
Required Associated Types§
type Output: 'a
type Output: 'a
This type MUST be Self
with the 'static
replaced with 'a
, i.e. Self<'a>
Required Methods§
fn transform_owned(self) -> Self::Output
fn transform_owned(self) -> Self::Output
fn transform_mut<F>(&'a mut self, f: F)
fn transform_mut<F>(&'a mut self, f: F)
This method must cast self
between &'a mut Self<'static>
and &'a mut Self<'a>
,
and pass it to f
.
§Implementation safety
A safe implementation of this method must be equivalent to a pointer cast/transmute between
&mut Self<'a>
and &mut Self<'static>
being passed to f
§Why is this safe?
Typically covariant lifetimes become invariant when hidden behind an &mut
,
which is why the implementation of this method cannot just be f(self)
.
The reason behind this is that while reading a covariant lifetime that has been cast to a shorter
one is always safe (this is roughly the definition of a covariant lifetime), writing
may not necessarily be safe since you could write a smaller reference to it. For example,
the following code is unsound because it manages to stuff a 'a
lifetime into a Cow<'static>
struct Foo {
str: String,
cow: Cow<'static, str>,
}
fn unsound<'a>(foo: &'a mut Foo) {
let a: &str = &foo.str;
foo.cow.transform_mut(|cow| *cow = Cow::Borrowed(a));
}
However, this code will not compile because Yokeable::transform_mut()
requires F: 'static
.
This enforces that while F
may mutate Self<'a>
, it can only mutate it in a way that does
not insert additional references. For example, F
may call to_owned()
on a Cow
and mutate it,
but it cannot insert a new borrowed reference because it has nowhere to borrow from –
f
does not contain any borrowed references, and while we give it Self<'a>
(which contains borrowed
data), that borrowed data is known to be valid
Note that the for<'b>
is also necessary, otherwise the following code would compile:
// also safely implements Yokeable<'a>
struct Bar<'a> {
num: u8,
cow: Cow<'a, u8>,
}
fn unsound<'a>(bar: &'a mut Bar<'static>) {
bar.transform_mut(move |bar| bar.cow = Cow::Borrowed(&bar.num));
}
which is unsound because bar
could be moved later, and we do not want to be able to
self-insert references to it.
The for<'b>
enforces this by stopping the author of the closure from matching up the input
&'b Self::Output
lifetime with 'a
and borrowing directly from it.
Thus the only types of mutations allowed are ones that move around already-borrowed data, or introduce new owned data:
struct Foo {
str: String,
cow: Cow<'static, str>,
}
fn sound<'a>(foo: &'a mut Foo) {
foo.cow.transform_mut(move |cow| cow.to_mut().push('a'));
}
More formally, a reference to an object that f
assigns to a reference
in Self<’a> could be obtained from:
- a local variable: the compiler rejects the assignment because ’a certainly outlives local variables in f.
- a field in its argument: because of the for<’b> bound, the call to
f
must be valid for a particular ’b that is strictly shorter than ’a. Thus, the compiler rejects the assignment. - a reference field in Self<’a>: this does not extend the set of non-static lifetimes reachable from Self<’a>, so this is fine.
- one of f’s captures: since F: ’static, the resulting reference must refer to ’static data.
- a static or thread_local variable: ditto.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.
Implementations on Foreign Types§
§impl<'a> Yokeable<'a> for bool
impl<'a> Yokeable<'a> for bool
§impl<'a> Yokeable<'a> for char
impl<'a> Yokeable<'a> for char
§impl<'a> Yokeable<'a> for i16
impl<'a> Yokeable<'a> for i16
§impl<'a> Yokeable<'a> for i32
impl<'a> Yokeable<'a> for i32
§impl<'a> Yokeable<'a> for i64
impl<'a> Yokeable<'a> for i64
§impl<'a> Yokeable<'a> for i128
impl<'a> Yokeable<'a> for i128
§impl<'a> Yokeable<'a> for isize
impl<'a> Yokeable<'a> for isize
§impl<'a> Yokeable<'a> for u16
impl<'a> Yokeable<'a> for u16
§impl<'a> Yokeable<'a> for u32
impl<'a> Yokeable<'a> for u32
§impl<'a> Yokeable<'a> for u64
impl<'a> Yokeable<'a> for u64
§impl<'a> Yokeable<'a> for u128
impl<'a> Yokeable<'a> for u128
§impl<'a> Yokeable<'a> for usize
impl<'a> Yokeable<'a> for usize
§impl<'a> Yokeable<'a> for ExportBoxwhere
ExportBox: Sized,
impl<'a> Yokeable<'a> for ExportBoxwhere
ExportBox: Sized,
§impl<'a> Yokeable<'a> for HelloWorld<'static>
impl<'a> Yokeable<'a> for HelloWorld<'static>
type Output = HelloWorld<'a>
fn transform(&'a self) -> &'a <HelloWorld<'static> as Yokeable<'a>>::Output
fn transform_owned(self) -> <HelloWorld<'static> as Yokeable<'a>>::Output
unsafe fn make( this: <HelloWorld<'static> as Yokeable<'a>>::Output, ) -> HelloWorld<'static>
fn transform_mut<F>(&'a mut self, f: F)
§impl<'a, K0, K1, V> Yokeable<'a> for ZeroMap2d<'static, K0, K1, V>where
K0: 'static + for<'b> ZeroMapKV<'b> + ?Sized,
K1: 'static + for<'b> ZeroMapKV<'b> + ?Sized,
V: 'static + for<'b> ZeroMapKV<'b> + ?Sized,
<K0 as ZeroMapKV<'static>>::Container: for<'b> Yokeable<'b>,
<K1 as ZeroMapKV<'static>>::Container: for<'b> Yokeable<'b>,
<V as ZeroMapKV<'static>>::Container: for<'b> Yokeable<'b>,
This impl requires enabling the optional yoke
Cargo feature of the zerovec
crate
impl<'a, K0, K1, V> Yokeable<'a> for ZeroMap2d<'static, K0, K1, V>where
K0: 'static + for<'b> ZeroMapKV<'b> + ?Sized,
K1: 'static + for<'b> ZeroMapKV<'b> + ?Sized,
V: 'static + for<'b> ZeroMapKV<'b> + ?Sized,
<K0 as ZeroMapKV<'static>>::Container: for<'b> Yokeable<'b>,
<K1 as ZeroMapKV<'static>>::Container: for<'b> Yokeable<'b>,
<V as ZeroMapKV<'static>>::Container: for<'b> Yokeable<'b>,
This impl requires enabling the optional yoke
Cargo feature of the zerovec
crate
type Output = ZeroMap2d<'a, K0, K1, V>
fn transform( &'a self, ) -> &'a <ZeroMap2d<'static, K0, K1, V> as Yokeable<'a>>::Output
fn transform_owned( self, ) -> <ZeroMap2d<'static, K0, K1, V> as Yokeable<'a>>::Output
unsafe fn make( from: <ZeroMap2d<'static, K0, K1, V> as Yokeable<'a>>::Output, ) -> ZeroMap2d<'static, K0, K1, V>
fn transform_mut<F>(&'a mut self, f: F)
§impl<'a, K0, K1, V> Yokeable<'a> for ZeroMap2dBorrowed<'static, K0, K1, V>where
K0: 'static + for<'b> ZeroMapKV<'b> + ?Sized,
K1: 'static + for<'b> ZeroMapKV<'b> + ?Sized,
V: 'static + for<'b> ZeroMapKV<'b> + ?Sized,
&'static <K0 as ZeroMapKV<'static>>::Slice: for<'b> Yokeable<'b>,
&'static <K1 as ZeroMapKV<'static>>::Slice: for<'b> Yokeable<'b>,
&'static <V as ZeroMapKV<'static>>::Slice: for<'b> Yokeable<'b>,
This impl requires enabling the optional yoke
Cargo feature of the zerovec
crate
impl<'a, K0, K1, V> Yokeable<'a> for ZeroMap2dBorrowed<'static, K0, K1, V>where
K0: 'static + for<'b> ZeroMapKV<'b> + ?Sized,
K1: 'static + for<'b> ZeroMapKV<'b> + ?Sized,
V: 'static + for<'b> ZeroMapKV<'b> + ?Sized,
&'static <K0 as ZeroMapKV<'static>>::Slice: for<'b> Yokeable<'b>,
&'static <K1 as ZeroMapKV<'static>>::Slice: for<'b> Yokeable<'b>,
&'static <V as ZeroMapKV<'static>>::Slice: for<'b> Yokeable<'b>,
This impl requires enabling the optional yoke
Cargo feature of the zerovec
crate
type Output = ZeroMap2dBorrowed<'a, K0, K1, V>
fn transform( &'a self, ) -> &'a <ZeroMap2dBorrowed<'static, K0, K1, V> as Yokeable<'a>>::Output
fn transform_owned( self, ) -> <ZeroMap2dBorrowed<'static, K0, K1, V> as Yokeable<'a>>::Output
unsafe fn make( from: <ZeroMap2dBorrowed<'static, K0, K1, V> as Yokeable<'a>>::Output, ) -> ZeroMap2dBorrowed<'static, K0, K1, V>
fn transform_mut<F>(&'a mut self, f: F)
§impl<'a, K, V> Yokeable<'a> for ZeroMap<'static, K, V>
This impl requires enabling the optional yoke
Cargo feature of the zerovec
crate
impl<'a, K, V> Yokeable<'a> for ZeroMap<'static, K, V>
This impl requires enabling the optional yoke
Cargo feature of the zerovec
crate
type Output = ZeroMap<'a, K, V>
fn transform(&'a self) -> &'a <ZeroMap<'static, K, V> as Yokeable<'a>>::Output
fn transform_owned(self) -> <ZeroMap<'static, K, V> as Yokeable<'a>>::Output
unsafe fn make( from: <ZeroMap<'static, K, V> as Yokeable<'a>>::Output, ) -> ZeroMap<'static, K, V>
fn transform_mut<F>(&'a mut self, f: F)
§impl<'a, K, V> Yokeable<'a> for ZeroMapBorrowed<'static, K, V>
This impl requires enabling the optional yoke
Cargo feature of the zerovec
crate
impl<'a, K, V> Yokeable<'a> for ZeroMapBorrowed<'static, K, V>
This impl requires enabling the optional yoke
Cargo feature of the zerovec
crate
type Output = ZeroMapBorrowed<'a, K, V>
fn transform( &'a self, ) -> &'a <ZeroMapBorrowed<'static, K, V> as Yokeable<'a>>::Output
fn transform_owned( self, ) -> <ZeroMapBorrowed<'static, K, V> as Yokeable<'a>>::Output
unsafe fn make( from: <ZeroMapBorrowed<'static, K, V> as Yokeable<'a>>::Output, ) -> ZeroMapBorrowed<'static, K, V>
fn transform_mut<F>(&'a mut self, f: F)
§impl<'a, K, V, S> Yokeable<'a> for LiteMap<K, V, S>
impl<'a, K, V, S> Yokeable<'a> for LiteMap<K, V, S>
§impl<'a, Store> Yokeable<'a> for ZeroTrie<Store>where
Store: 'static,
ZeroTrie<Store>: Sized,
impl<'a, Store> Yokeable<'a> for ZeroTrie<Store>where
Store: 'static,
ZeroTrie<Store>: Sized,
§impl<'a, T1, T2> Yokeable<'a> for (T1, T2)
impl<'a, T1, T2> Yokeable<'a> for (T1, T2)
type Output = (<T1 as Yokeable<'a>>::Output, <T2 as Yokeable<'a>>::Output)
fn transform(&'a self) -> &'a <(T1, T2) as Yokeable<'a>>::Output
fn transform_owned(self) -> <(T1, T2) as Yokeable<'a>>::Output
unsafe fn make(from: <(T1, T2) as Yokeable<'a>>::Output) -> (T1, T2)
fn transform_mut<F>(&'a mut self, f: F)
§impl<'a, T> Yokeable<'a> for Option<T>where
T: 'static + for<'b> Yokeable<'b>,
impl<'a, T> Yokeable<'a> for Option<T>where
T: 'static + for<'b> Yokeable<'b>,
§impl<'a, T> Yokeable<'a> for &'static Twhere
T: 'static + ?Sized,
impl<'a, T> Yokeable<'a> for &'static Twhere
T: 'static + ?Sized,
type Output = &'a T
fn transform(&'a self) -> &'a &'a T
fn transform_owned(self) -> &'a T
unsafe fn make(from: &'a T) -> &'static T
fn transform_mut<F>(&'a mut self, f: F)
§impl<'a, T> Yokeable<'a> for PhantomData<T>where
T: 'static + ?Sized,
impl<'a, T> Yokeable<'a> for PhantomData<T>where
T: 'static + ?Sized,
type Output = PhantomData<T>
fn transform(&'a self) -> &'a <PhantomData<T> as Yokeable<'a>>::Output
fn transform_owned(self) -> <PhantomData<T> as Yokeable<'a>>::Output
unsafe fn make(from: <PhantomData<T> as Yokeable<'a>>::Output) -> PhantomData<T>
fn transform_mut<F>(&'a mut self, f: F)
§impl<'a, T> Yokeable<'a> for VarZeroCow<'static, T>where
T: 'static + ?Sized,
This impl requires enabling the optional yoke
Cargo feature of the zerovec
crate
impl<'a, T> Yokeable<'a> for VarZeroCow<'static, T>where
T: 'static + ?Sized,
This impl requires enabling the optional yoke
Cargo feature of the zerovec
crate
type Output = VarZeroCow<'a, T>
fn transform(&'a self) -> &'a <VarZeroCow<'static, T> as Yokeable<'a>>::Output
fn transform_owned(self) -> <VarZeroCow<'static, T> as Yokeable<'a>>::Output
unsafe fn make( from: <VarZeroCow<'static, T> as Yokeable<'a>>::Output, ) -> VarZeroCow<'static, T>
fn transform_mut<F>(&'a mut self, f: F)
§impl<'a, T> Yokeable<'a> for VarZeroVec<'static, T>where
T: 'static + VarULE + ?Sized,
This impl requires enabling the optional yoke
Cargo feature of the zerovec
crate
impl<'a, T> Yokeable<'a> for VarZeroVec<'static, T>where
T: 'static + VarULE + ?Sized,
This impl requires enabling the optional yoke
Cargo feature of the zerovec
crate
type Output = VarZeroVec<'a, T>
fn transform(&'a self) -> &'a <VarZeroVec<'static, T> as Yokeable<'a>>::Output
fn transform_owned(self) -> <VarZeroVec<'static, T> as Yokeable<'a>>::Output
unsafe fn make( from: <VarZeroVec<'static, T> as Yokeable<'a>>::Output, ) -> VarZeroVec<'static, T>
fn transform_mut<F>(&'a mut self, f: F)
§impl<'a, T> Yokeable<'a> for ZeroVec<'static, T>where
T: 'static + AsULE,
This impl requires enabling the optional yoke
Cargo feature of the zerovec
crate
impl<'a, T> Yokeable<'a> for ZeroVec<'static, T>where
T: 'static + AsULE,
This impl requires enabling the optional yoke
Cargo feature of the zerovec
crate