I ran into some trouble while working on zero-copy deserialization for Serde: serde-rs/serde#492.
We have a trait Deserialize<'de>
that behaves like the Put<'a>
trait below. Importantly, I need a function that requires T: Put<'static>
to be callable with any T: Put<'a>
which is the inverse of the usual relationship for lifetimes. Rust seems to handle this great for struct lifetimes but not trait lifetimes as demonstrated in the following code.
I found this relevant sentence in the Rustonomicon:
Traits don't have inferred variance, so
Fn(T)
is invariant inT
.
Has anyone encountered this limitation in other contexts or developed any approaches for working around it?
#![allow(dead_code, unused_variables)]
// Covariance / contravariance is inferred correctly for struct lifetimes.
mod with_struct {
struct Get<'a> {
get: fn() -> &'a str,
}
fn get_any<'a>(x: Get<'a>) {
fn get_static(x: Get<'static>) {
let _: &'static str = (x.get)();
}
// Not allowed. Makes sense.
//get_static(x);
}
struct Put<'a> {
put: fn(&'a str),
}
fn put_any<'a>(x: Put<'a>) {
fn put_static(x: Put<'static>) {
(x.put)("static");
}
// Allowed. Perfect.
put_static(x);
}
}
// Not for trait lifetimes.
mod with_trait {
trait Get<'a> {
fn get() -> &'a str;
}
fn get_any<'a, T: Get<'a>>() {
fn get_static<T: Get<'static>>() {
let _: &'static str = T::get();
}
// Not allowed. Makes sense.
//get_static::<T>();
}
trait Put<'a> {
fn put(&'a str);
}
fn put_any<'a, T: Put<'a>>() {
fn put_static<T: Put<'static>>() {
T::put("static");
}
// Not allowed. But should be?
put_static::<T>();
}
}