Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions json/src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::char;
use std::i32;
use std::io;
use std::str;
use std::marker::PhantomData;

use serde::de;
use serde::iter::LineColIterator;
Expand Down Expand Up @@ -828,3 +829,48 @@ pub fn from_str<T>(s: &str) -> Result<T>
{
from_slice(s.as_bytes())
}

/// Iterator over parsed JSON values
pub struct JSONStream<T, Iter>
where Iter: Iterator<Item=io::Result<u8>>,
T: de::Deserialize
{
deser: Deserializer<Iter>,
_marker: PhantomData<T>,
}

/// Iterator over parsed JSON values
impl <T, Iter> JSONStream<T, Iter>
where Iter:Iterator<Item=io::Result<u8>>,
T: de::Deserialize {
/// Returns Iterator of decoded JSON value from an iterator over
/// `Iterator<Item=io::Result<u8>>`.
pub fn new(i: Iter) -> JSONStream<T, Iter> {
JSONStream {
deser: Deserializer::new(i),
_marker: PhantomData
}
}
}

impl <T, Iter> Iterator for JSONStream<T, Iter>
where Iter:Iterator<Item=io::Result<u8>>,
T: de::Deserialize {
type Item = Result<T>;
fn next(&mut self) -> Option<Result<T>> {
// skip whitespaces, if any
// this helps with trailing whitespaces, since whitespaces between
// values are handled for us.
if let Err(e) = self.deser.parse_whitespace() {
return Some(Err(e))
};
match self.deser.eof() {
Ok(true) => None,
Ok(false) => match de::Deserialize::deserialize(&mut self.deser) {
Ok(v) => Some(Ok(v)),
Err(e) => Some(Err(e))
},
Err(e) => Some(Err(e))
}
}
}
7 changes: 4 additions & 3 deletions json/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@
//! Address: Address,
//! PhoneNumbers: Vec<String>
//! }
//!
//!
//! #[derive(Serialize, Deserialize)]
//! struct Address {
//! Street: String,
//! City: String,
//! Country: String
//! }
//! ```
//! ```
//!
//! # Type-based Serialization and Deserialization
//!
Expand Down Expand Up @@ -115,12 +115,13 @@
//! ```

#![deny(missing_docs)]

extern crate num;
extern crate core;
extern crate serde;

pub use self::de::{
Deserializer,
JSONStream,
from_iter,
from_reader,
from_slice,
Expand Down
46 changes: 46 additions & 0 deletions json_tests/tests/test_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use serde::bytes::{ByteBuf, Bytes};
use serde_json::{
self,
Value,
JSONStream,
from_str,
from_value,
to_value,
Expand Down Expand Up @@ -1393,3 +1394,48 @@ fn test_byte_buf_de() {
let v: ByteBuf = serde_json::from_str("[1, 2, 3]").unwrap();
assert_eq!(v, bytes);
}

#[test]
fn test_json_stream_newlines() {
let stream = "{\"x\":39} {\"x\":40}{\"x\":41}\n{\"x\":42}".to_string();
let mut parsed:JSONStream<Value, _> = JSONStream::new(
stream.as_bytes().iter().map(|byte| Ok(*byte)));
assert_eq!(parsed.next().unwrap().ok().unwrap().lookup("x").unwrap(),
&Value::U64(39));
assert_eq!(parsed.next().unwrap().ok().unwrap().lookup("x").unwrap(),
&Value::U64(40));
assert_eq!(parsed.next().unwrap().ok().unwrap().lookup("x").unwrap(),
&Value::U64(41));
assert_eq!(parsed.next().unwrap().ok().unwrap().lookup("x").unwrap(),
&Value::U64(42));
assert!(parsed.next().is_none());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also add a test that check that handles if the last record is truncated, and make sure it returns an error?

}

#[test]
fn test_json_stream_trailing_whitespaces() {
let stream = "{\"x\":42} \t\n".to_string();
let mut parsed:JSONStream<Value, _> = JSONStream::new(
stream.as_bytes().iter().map(|byte| Ok(*byte)));
assert_eq!(parsed.next().unwrap().ok().unwrap().lookup("x").unwrap(),
&Value::U64(42));
assert!(parsed.next().is_none());
}

#[test]
fn test_json_stream_truncated() {
let stream = "{\"x\":40}\n{\"x\":".to_string();
let mut parsed:JSONStream<Value, _> = JSONStream::new(
stream.as_bytes().iter().map(|byte| Ok(*byte)));
assert_eq!(parsed.next().unwrap().ok().unwrap().lookup("x").unwrap(),
&Value::U64(40));
assert!(parsed.next().unwrap().is_err());
assert!(parsed.next().is_none());
}

#[test]
fn test_json_stream_empty() {
let stream = "".to_string();
let mut parsed:JSONStream<Value, _> = JSONStream::new(
stream.as_bytes().iter().map(|byte| Ok(*byte)));
assert!(parsed.next().is_none());
}