use crate::error::JsonError;
use serde_json::Value;
use std::io::Read;
use std::str;
pub struct JsonStream<R: Read> {
reader: R,
buffer: Vec<u8>,
temp: String, in_string: bool,
brace_count: u16,
inside_array: bool,
object_buffer: String, }
impl<R: Read> JsonStream<R> {
pub fn new(reader: R) -> Self {
JsonStream {
reader,
buffer: vec![0; 1024],
temp: String::new(),
in_string: false,
brace_count: 0,
inside_array: false,
object_buffer: String::new(),
}
}
pub fn find_object_in_buffer(&mut self) -> Option<Result<Value, JsonError>> {
let mut chars = self.temp.chars().peekable();
while let Some(c) = chars.next() {
if self.brace_count > 0 || (c == '{' && !self.in_string) {
self.object_buffer.push(c);
}
match c {
'"' => {
let mut backslashes = 0;
while self.object_buffer.chars().rev().nth(backslashes) == Some('\\') {
backslashes += 1;
}
if backslashes % 2 == 0 {
self.in_string = !self.in_string;
}
}
'[' if !self.in_string && !self.inside_array => {
self.inside_array = true;
self.object_buffer.clear(); continue;
}
'{' if !self.in_string => {
self.brace_count += 1;
}
'}' if !self.in_string => {
self.brace_count -= 1;
if self.brace_count == 0 {
if self.object_buffer.trim().is_empty() {
self.object_buffer.clear();
continue;
}
let obj_str = self.object_buffer.clone();
self.object_buffer.clear();
while let Some(next_ch) = chars.peek() {
if next_ch.is_whitespace() || *next_ch == ',' {
chars.next();
} else {
break;
}
}
self.temp = chars.collect();
return Some(serde_json::from_str(&obj_str).map_err(JsonError::from));
}
}
_ => {}
}
}
self.temp = chars.collect();
None
}
}
impl<R: Read> Iterator for JsonStream<R> {
type Item = Result<Value, JsonError>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(obj) = self.find_object_in_buffer() {
return Some(obj);
}
while let Ok(n) = self.reader.read(&mut self.buffer) {
if n == 0 {
return None;
}
let chunk = str::from_utf8(&self.buffer[..n]).unwrap(); self.temp.push_str(chunk);
return self.find_object_in_buffer();
}
Some(Err(JsonError::Parser))
}
}