Suppose we have an array of integers and we want to figure out the maximum value without holding the whole array in memory all at once. This approach can be adapted to handle a variety of other situations in which data needs to be processed while being deserialized instead of after.
extern crate serde;
extern crate serde_json;
#[macro_use] extern crate serde_derive;
use serde::{de, Deserialize, Deserializer};
use std::cmp;
use std::fmt;
use std::marker::PhantomData;
#[derive(Deserialize)]
struct Outer {
id: String,
// Deserialize this field by computing the maximum value of a sequence
// (JSON array) of values.
#[serde(deserialize_with = "deserialize_max")]
// Despite the struct field being named `max_value`, it is going to come
// from a JSON field called `values`.
#[serde(rename(deserialize = "values"))]
max_value: u64,
}
/// Deserialize the maximum of a sequence of values. The entire sequence
/// is not buffered into memory as it would be if we deserialize to Vec<T>
/// and then compute the maximum later.
///
/// This function is generic over T which can be any type that implements
/// Ord. Above, it is used with T=u64.
fn deserialize_max<T, D>(deserializer: D) -> Result<T, D::Error>
where T: Deserialize + Ord,
D: Deserializer
{
struct MaxVisitor<T>(PhantomData<T>);
impl<T> de::Visitor for MaxVisitor<T>
where T: Deserialize + Ord
{
/// Return type of this visitor. This visitor computes the max of a
/// sequence of values of type T, so the type of the maximum is T.
type Value = T;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a sequence of numbers")
}
fn visit_seq<V>(self, mut visitor: V) -> Result<T, V::Error>
where V: de::SeqVisitor
{
// Start with max equal to the first value in the seq.
let mut max = match visitor.visit()? {
Some(value) => value,
None => {
// Cannot take the maximum of an empty seq.
let msg = "no values in seq when looking for maximum";
return Err(de::Error::custom(msg));
}
};
// Update the max while there are additional values.
while let Some(value) = visitor.visit()? {
max = cmp::max(max, value);
}
Ok(max)
}
}
// Create the visitor and ask the deserializer to drive it. The
// deserializer will call visitor.visit_seq if a seq is present in
// the input data.
let visitor = MaxVisitor(PhantomData);
deserializer.deserialize_seq(visitor)
}
fn main() {
let j = r#"
{
"id": "demo-deserialize-max",
"values": [
256,
100,
384,
314,
271
]
}
"#;
let out: Outer = serde_json::from_str(j).unwrap();
// Prints "max value: 384"
println!("max value: {}", out.max_value);
}