I am trying to use erased-serde in a library where I don't know the type of the deserializer and the type of the target value at the same time, so I want to wrap the deserializer in a dynamic trait object. Unfortunately, I am encountering an issue with lifetimes that I don't know how to resolve. The playground code (with the relevant erased-serde API mocked out): https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=84c521751f97fb5f465066cbb5db805f
The error is in Deserialize::deserialize(), which would be executed in an implementation of some object-safe trait that does not know in advance what deserializer the user wants to employ. So Deserializer must necessarily stay generic-free. The compiler says that deserializer does not live long enough to call get_erased(), which I do not understand - 's in get_erased would take value of the lifetime of the local scope, and erased does not outlive it. Any ideas of how this can be fixed?
Thank you! It seems to be working. I agree, I messed around with lifetimes quite a bit in this example, so the result I posted was kind of weird, but the key change was the introduction of the for<'any> &'any mut D: serde::Deserializer<'de> bound. It actually worries me a little, wouldn't 'de have to also outlive 'any for that to be the case? Or is it already implied because you can't have an &'any reference on something whose lifetime doesn't outlive 'any?
It's implied for the latter reason, if and only if D contains the lifetime 'de.
D: 'de is implied by &'any mut D being present; if 'de is part of D, that in turn implies 'de: 'any
'de is a trait parameter; types can implement Deserializer<'de> regardless of any lifetimes they do (or don't) have in their own types, be they longer or shorter. So it's not implied if D doesn't contain 'de (it's not implied by &'any mut D: Trait<'de>).
The actual D you care about in the code is a
serde_json::Deserializer<SliceRead<'de>>
so it it implied in that case. But that's not a problem.
impl<'de, R: Read<'de>> Deserializer<'de> for &mut Deserializer<R>
Note how it's implemented for all valid lifetimes on the &mut (implicitly, by eliding the lifetime). When R = SliceRead<'de>, the 'de: 'lifetime_on_the_mut bound is implied here too. They don't implement for &'de mut Deserizer<R>. That's good -- it would require borrowing forever, and thus probably not be at all usable, when R = SliceRead<'de>.
No, they're not equivalent. &'de mut D where 'de is part of D forces the &mut borrow of D to be for the rest of D's validity. You need the flexibility for the lifetimes to be different to avoid borrowing forever in that case. for<'any> &'any mut D allows the &mut borrow to be arbitrarily short.