How to conditionally create a serializer and sequence? (Option<SerializeSeq>)

Viewed 70

I'm trying to process data from a channel, so the whole structure can't be serialized at once. In fact it won't all fit in memory. The trouble I'm running into is that I can't create an Option<SerializeSeq> because that object depends on Serializer (which doesn't live long enough). I'd like to initialize them both together, or not at all:

use serde::ser::{SerializeSeq, Serializer};
fn process_stream(output: bool) -> serde_json::Result<()> {
    let rows = /* whatever iterator */ "serde".chars();

    let mut seq = if output {
        let out = std::io::stdout();
        let mut ser = serde_json::Serializer::new(out);
        let seq = ser.serialize_seq(None)?
        Some(Ok(seq))
    } else {
        None
    }.transpose()?;

    for row in rows {
        //process_data(row);
        if let Some(seq) = &mut seq {
            seq.serialize_element(&row)?;
        }
    }

    if let Some(seq) = seq {
        seq.end()?;
    }
    Ok(())
}

(Original code snippet from here.)

The problem is: ser does not live long enough. But I don't want to initialize ser in the outer scope because it may not be enabled (and its writer would create or truncate a file that should not be created). I tried returning ser and seq as a tuple. I tried putting them together in a helper struct, but I couldn't figure out all the template parameters and lifetimes.

How can serde serializer and sequence be initialized based on a condition and stored in Option?

1 Answers

Make sure that ser doesn't get dropped prematurely by declaring it outside the if body:

let mut ser;
let mut seq = if output {
    let out = std::io::stdout();
    ser = serde_json::Serializer::new(out);
    let seq = ser.serialize_seq(None)?;
    Some(Ok(seq))
} else {
    None
}.transpose()?;
Related