Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Streaming serialize and deserialize packets #1107

Closed
dtolnay opened this issue Dec 1, 2017 · 3 comments
Closed

Streaming serialize and deserialize packets #1107

dtolnay opened this issue Dec 1, 2017 · 3 comments
Labels

Comments

@dtolnay
Copy link
Member

dtolnay commented Dec 1, 2017

From IRC:

<lu_zero> I have some multimedia format I want to write down in a sort of readable form, so I have some global information that can fit a json itself and then for each packet/frame I'd have 1 json each
<lu_zero> initially I wanted to assemble the array of packets/frames as they come but looks not so plausible
<lu_zero> so I'd just concatenate the multiple json (and that works)
<lu_zero> but then I couldn't find a way to tell serde on the deserializing side that's ok to have trailing data

@dtolnay dtolnay added the support label Dec 1, 2017
@dtolnay
Copy link
Member Author

dtolnay commented Dec 1, 2017

Streaming serialization and deserialization of concatenated JSON objects

#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug)]
struct Index {
    len: usize,
    name: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct Packet {
    name: String,
    data: Vec<u8>,
}

fn main() {
    try_main().unwrap();
}

fn try_main() -> Result<(), serde_json::Error> {
    let mut out = Vec::new();

    {
        let mut ser = serde_json::Serializer::new(&mut out);
        let npackets = 4;
        Index { len: npackets, name: "index".to_owned() }.serialize(&mut ser)?;
        for i in 0..npackets {
            Packet { name: "packet".to_owned(), data: vec![i as u8] }.serialize(&mut ser)?;
        }
    }

    println!("{}", String::from_utf8_lossy(&out));

    {
        let mut de = serde_json::Deserializer::from_slice(&out);
        let index = Index::deserialize(&mut de)?;
        println!("{:?}", index);
        for _ in 0..index.len {
            let packet = Packet::deserialize(&mut de)?;
            println!("{:?}", packet);
        }
    }

    Ok(())
}

@dtolnay
Copy link
Member Author

dtolnay commented Dec 1, 2017

Streaming serialization and deserialization of a single top-level array

#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;

use serde::ser::{Serializer, SerializeSeq};
use serde::de::{self, Deserializer, Visitor, SeqAccess};

use std::fmt;
use std::io::{self, Write};

#[derive(Serialize, Deserialize, Debug)]
struct Index {
    len: usize,
    name: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct Packet {
    name: String,
    data: Vec<u8>,
}

fn main() {
    try_main().unwrap();
}

fn try_main() -> Result<(), serde_json::Error> {
    let mut out = Vec::new();

    {
        let mut ser = serde_json::Serializer::pretty(&mut out);
        let npackets = 4;
        let mut seq = ser.serialize_seq(Some(1 + npackets as usize))?; // or None if unknown
        seq.serialize_element(&Index { len: npackets, name: "index".to_owned() })?;
        for i in 0..npackets {
            seq.serialize_element(&Packet { name: "packet".to_owned(), data: vec![i as u8] })?;
        }
        seq.end()?;
    }

    println!("{}", String::from_utf8_lossy(&out));

    {
        let mut de = serde_json::Deserializer::from_slice(&out);
        let action = DebugPackets { out: io::stdout() };
        de.deserialize_seq(action)?;
    }

    Ok(())
}

struct DebugPackets<W> {
    out: W,
}

impl<'de, W> Visitor<'de> for DebugPackets<W>
    where W: Write
{
    type Value = ();

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("array of index + packets")
    }

    fn visit_seq<A>(mut self, mut seq: A) -> Result<Self::Value, A::Error>
        where A: SeqAccess<'de>
    {
        let index = match seq.next_element::<Index>()? {
            Some(index) => index,
            None => {
                return Err(de::Error::custom("index was missing"));
            }
        };
        let _ = writeln!(self.out, "{:?}", index);

        for _ in 0..index.len {
            match seq.next_element::<Packet>()? {
                Some(packet) => {
                    let _ = writeln!(self.out, "{:?}", packet);
                }
                None => {
                    return Err(de::Error::custom("fewer packets than expected"));
                }
            }
        }

        Ok(())
    }
}

@rofrol
Copy link

rofrol commented Jul 30, 2018

Same with string and without index:

#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;

use serde::de::{self, Deserializer, SeqAccess, Visitor};

use std::fmt;
use std::io::{self, Write};

#[derive(Serialize, Deserialize, Debug)]
struct Packet {
    name: String,
    data: Vec<u8>,
}

fn main() -> std::io::Result<()> {
    let out = r#"
[
  {
    "name": "packet",
    "data": [
      0
    ]
  },
  {
    "name": "packet",
    "data": [
      1
    ]
  },
  {
    "name": "packet",
    "data": [
      2
    ]
  },
  {
    "name": "packet",
    "data": [
      3
    ]
  }
]
"#;

    {
        let mut de = serde_json::Deserializer::from_str(&out);
        let action = DebugPackets { out: io::stdout() };
        de.deserialize_seq(action)?;
    }

    Ok(())
}

struct DebugPackets<W> {
    out: W,
}

impl<'de, W> Visitor<'de> for DebugPackets<W>
where
    W: Write,
{
    type Value = ();

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("array of packets")
    }

    fn visit_seq<A>(mut self, mut seq: A) -> Result<Self::Value, A::Error>
    where
        A: SeqAccess<'de>,
    {
        while let Some(packet) = seq.next_element::<Packet>()? {
            let _ = writeln!(self.out, "{:?}", packet);
        }
        Ok(())
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

2 participants