Open ia0 opened 1 month ago
Actually, I think I have a concrete example where it is beneficial (and not just more expressive) to be able to choose the Deserialize
lifetime parameter from the impl
parameters. When having a very large enum Api<'a, 'de: 'a, T: Flavor>
where each variant is of the form Foo(T::Type<'a, 'de, Foo>)
because otherwise serde will add a bound T::<'a, 'de, Foo>: Deserialize<'x>
for each variant Foo
(possibly increasing compilation time).
#[derive(Deserialize)]
#[serde(bound = "", lifetime = 'de)]
enum Api<'a, 'de: 'a, T: Flavor> {
Foo(T::Type<'a, 'de, Foo>),
// many similar lines replacing Foo with something else
}
trait Flavor {
type Type<'a, 'de: 'a, T: Variant>: 'a + Deserialize<'de>;
}
I'll try to come up with concrete code today. The idea is that Api
is only meant to be a view into serialized data. So it doesn't need any bound, it is statically always deserializable.
Here's a concrete example: https://github.com/ia0/wasefire/blob/96c8e4e29d554346b71b297668b2b7337dbf3455/crates/protocol/src/lib.rs#L64
That said, I'm not convinced it's something I like. Ideally I want to use for<'de: 'a> Deserialize<'de>
as a bound but it's not possible in Rust, which forces to have 'de
explicit everywhere.
This PR is for discussion and related to #2190. As discussed there, the benefit is not obvious (except for providing more control to the user).
With this PR, a user can use
#[serde(lifetime = 'a)]
to control the lifetime of the implementation ofDeserialize
. In particular, the user is now able to control all the implementation parameters when using#[serde(bound = "", lifetime = 'a)]
.See https://github.com/ia0/wasefire/blob/ccf7bc30ac8440b30981b2f39b734de10d1a037c/crates/protocol/src/lib.rs#L65 for an example in real code which gives
impl<'a, T: Direction<'a>> _serde::Deserialize<'a> for Api<'a, T>
when looking withcargo expand
. The preceding commented line is the solution without this PR.