I have some function, here called request
, that returns a JSON string with some data. For example, an array with variable size. I can deserialize the JSON string into a Vec just fine with serde_json
, but I have to call the request
many times. I would like instead to reuse the Vec already created, instead of dropping and creating a new Vec every time deserialization happens.
Is there a way to deserialize a JSON string into an existing Vec? I had a look at the visitor and at this example, but I am not sure which I would have to implement. Either a custom visitor or a deserializer that wraps the serde_json::Deserializer
and has a reference to a Vec, or perhaps something else entirely.
Here is some code with an example. Thanks.
use serde_json;
fn request(i: usize) -> String {
let mut v = vec![0; i];
for n in 1..i {
v[n] = n
}
serde_json::to_string(&v).unwrap()
}
fn main() {
let mut bigvec = serde_json::from_str::<Vec<i32>>(&request(100)).unwrap();
println!("{:?}", &bigvec);
// - now we will rerun the request many times and we would like to reuse our vec
let many_iterations = 10;
for n in 1..many_iterations {
bigvec.clear();
let resp = request(n); // we receive a new request with a vec with different length
// - we would like something like the below, which does not exist
serde_json::from_str_into::<Vec<i32>>(&resp, &mut bigvec);
}
}
2
Answers
We can’t fully deserialize everything in place because
serde
is designed around returning the value as we deserialize it. However, it you just want to deserialize into a singleVec
, we can make a visitor to handle that situation. Here is roughly what that would look like.Now, one of the tricky parts of using this is that we need to construct our visitor with the buffer we want to push to. This is tricky that means we will not have access to our buffer within
serde::Deserialize::deserialize
. As a result, we must construct the deserializer ourselves. Not allserde
formats expose theirSerializer
andDeserializer
types so this solution won’t be possible for all data formats. Luckilyserde_json
does expose its deserializer, so we can implement a general function to use our visitor.With this, we are all set. However for convenience, you may still want to make some simple wrapper functions to handle creating the reader.
Rust Playground
There is a hidden
deserialize_in_place
method on theDeserialize
trait that can support this1. By default it would simply create a new value and assign it to the existing one, butVec
‘s impl does exactly what you want.So you just need to call it manually with the serde-json deserializer:
1. This is not a private API. The documentation says "This method is stable and an official public API, but hidden from the documentation because it is almost never what newbies are looking for."