Open Mingun opened 1 year ago
I think this is behaving as intended / as documented in https://serde.rs/lifetimes.html#borrowing-data-in-a-derived-impl. You would need to write #[serde(borrow)] Variant(Vec<&'static str>)
if the intention is for the vec elements to be borrowed strings.
Yes, #[serde(borrow)]
solves the problem, but if you use Cow
instead of Vec
the things works without it: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=ffacb52410b19952ee12907ca2d4daf8
Is it intended that the behavior will be different in that two cases?
Yes.
Could you please be more rationale about this? I've not seen any special handling of Cow
s in the serde code, so why it works differently?
Deserializing Cow<'static, str>
from &'de str
does not require 'de
to outlive 'static
. It can just allocate Strings.
Deserializing Vec<&'static str>
from &'de str
would presumably require that 'de
outlives 'static
so you've gotta put the borrow attribute.
Ok, but this is not encoded in types, right? How serde knows that it will not store references? Here the implementation of FakeCow
, which does not store anything. Why it is required that 'de
outlives 'static
?
Cow<'static, str>
and Vec<&'static str>
behave differently from one another because their Deserialize
impls have different signatures. This is how the different lifetime requirement between output value and input data is encoded in types.
&'static str
implements Deserialize<'static>
. Vec<&'static str>
implements Deserialize<'static>
. Cow<'static, str>
implements for<'de> Deserialize<'de>
.
According to the Deserialize
impl that you have written for FakeCow
, FakeCow<'static, str>
implements Deserialize<'static>
. It does not implement for<'de> Deserialize<'de>
. So that lifetime behaves more like Vec<&'static str>
and less like serde's Cow<'static, str>
.
Interestingly enough, deserializing into a Vec<&'static str>
does work if there's another &'static
field:
use serde::Deserialize; // 1.0.156;
// This compiles just fine
#[derive(Deserialize)]
struct Struct {
field1: Vec<&'static str>,
#[serde(default)]
_fix: &'static str,
}
I guess it's because it's placing a 'static bound on the 'de lifetime, but I got surprised when it started erroring after removing an unrelated field...
On another note, by using this struct in another struct I cannot use #[serde(borrow)] as it doesn't expose any lifetime, so I have to use #[serde(bound = "'de: 'static")]
on the container, e.g.:
use serde::Deserialize; // 1.0.197
#[derive(Deserialize)]
#[serde(bound = "'de: 'static")]
struct WrapperStruct {
inner: Struct,
}
#[derive(Deserialize)]
struct Struct {
#[serde(borrow)]
field1: Vec<&'static str>,
}
I don't know if that's intentional or if it should be another bug, but it's a bit strange.
Deriving
Deserialize
for that struct:gives the following error:
At the same time, a variant without
Vec
compiled ok.Playground. In comment you can see derived code. Derived code for the
Enum2
variant is the same except that all occurrences of'de
is replaced by'static
.This is a problem also in 1.0.157, but playground did not have it yet at time of writing.