This works fine:
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
#[derive(Debug, Deserialize)]
struct Foo<'a> {
#[serde(borrow)]
bar: &'a str,
}
fn main() {
let deser: Foo = serde_json::from_str("{\"bar\": \"rab\"}").unwrap();
println!("{:?}", deser);
}
but fails to compile if main is swapped for:
fn main() {
let mut f = File::open("contents_as_above.json")?;
let mut reader = BufReader::new(f);
let deser: Foo = serde_json::from_reader(reader).unwrap();
println!("{:?}", deser);
}
The error message is:
error[E0279]: the requirement
for<'de> 'de :is not satisfied (expected bound lifetime parameter 'de, found concrete lifetime)
--> examples/one.rs:22:22
|
22 | let deser: Foo = serde_json::from_reader(reader).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= note: required because of the requirements on the impl offor<'de> _IMPL_DESERIALIZE_FOR_Foo::_serde::Deserialize<'de>forFoo<'_>
= note: required because of the requirements on the impl of_IMPL_DESERIALIZE_FOR_Foo::_serde::de::DeserializeOwnedforFoo<'_>
= note: required byserde_json::from_reader
where the red underlining (^^^) should be under serde_json::from_reader, stopping short of its argument.
Incidentally, E0279 is not yet in the error index, and I'm not sure I understand it fully (e.g. isn't for<'de> 'de : syntactically incorrect; the second 'de should be a type?) - so apologies if this is just due to my misuse.
Check out https://serde.rs/lifetimes.html where it explains what the two different possible Deserialize trait bounds mean. In serde_json, from_str and from_reader require different bounds.
fn from_str<'a, T>(s: &'a str) -> Result<T>
where T: Deserialize<'a>;
fn from_reader<R, T>(reader: R) -> Result<T>
where R: Read,
T: DeserializeOwned; // equivalent to T: for<'de> Deserialize<'de>
As explained on the site, the bound on from_str means that T can be deserialized from data of lifetime 'a, while the bound on from_reader means that T can be deserialized from data of any (even arbitrarily short) lifetime. The reason is data from a reader is not kept in memory so there is nothing to borrow from.
Your options are to change Foo to be able to deserialize from any lifetime (by not borrowing) or to memory-map the input file using memmap and use from_slice to deserialize from the resulting in-memory slice of the file.
Remember to thank Rust for catching this bug! The borrow checker saved you from successfully deserializing a Foo containing garbage data.
I understand now, thank you for your help!
Remember to thank Rust for catching this bug! The borrow checker saved you from successfully deserializing a Foo containing garbage data.
:green_heart: Rust
Most helpful comment
Check out https://serde.rs/lifetimes.html where it explains what the two different possible Deserialize trait bounds mean. In serde_json,
from_strandfrom_readerrequire different bounds.As explained on the site, the bound on
from_strmeans thatTcan be deserialized from data of lifetime'a, while the bound onfrom_readermeans thatTcan be deserialized from data of any (even arbitrarily short) lifetime. The reason is data from a reader is not kept in memory so there is nothing to borrow from.Your options are to change
Footo be able to deserialize from any lifetime (by not borrowing) or to memory-map the input file usingmemmapand usefrom_sliceto deserialize from the resulting in-memory slice of the file.Remember to thank Rust for catching this bug! The borrow checker saved you from successfully deserializing a
Foocontaining garbage data.