use std::char;
use crate::utils::compare_stack_reader;
use {serde::de::DeserializeOwned, std::io::Read};
pub struct JsonSeqIterator<'a, R, O> {
state: State<'a>,
reader: R,
output_type: std::marker::PhantomData<O>,
}
enum State<'a> {
NotStarted { path_to_look_for: PrefixPath<'a> },
Started,
Ended,
}
type PrefixPath<'a> = &'a [u8];
impl<'a, R: Read, O: DeserializeOwned> JsonSeqIterator<'a, R, O> {
pub fn new(reader: R, path_to_look_for: &'a [u8]) -> Self {
Self {
state: State::NotStarted { path_to_look_for },
reader,
output_type: std::marker::PhantomData,
}
}
fn next_char(&mut self) -> Result<u8, JsonItError> {
let mut buf = [0_u8; 1];
self.reader.read_exact(&mut buf).map_err(JsonItError::IoError)?;
Ok(buf[0])
}
fn deserialize_one_item(&mut self, maybe_byte: Option<u8>) -> Result<O, JsonItError> {
match maybe_byte {
Some(w) => {
let r = &[w][..];
O::deserialize(&mut serde_json::Deserializer::from_reader(
&mut r.chain(self.reader.by_ref()),
))
}
None => O::deserialize(&mut serde_json::Deserializer::from_reader(&mut self.reader)),
}
.map_err(JsonItError::SerdeError)
}
}
#[derive(PartialEq, Debug, Copy, Clone)]
enum ParseValueType {
String,
Number,
Null,
Map,
Array,
}
#[derive(PartialEq, Debug)]
enum NotStartedState {
ParseObjectKey,
ParseObject,
ParseValue(ParseValueType),
ExpectValue,
ExpectPoints,
None,
}
impl<R: Read, O: DeserializeOwned> Iterator for JsonSeqIterator<'_, R, O> {
type Item = Result<O, JsonItError>;
fn next(&mut self) -> Option<Self::Item> {
match self.state {
State::NotStarted { path_to_look_for } => {
let mut key_stack: Vec<Vec<u8>> = vec![];
let mut current_key: Vec<u8> = vec![];
let mut state = NotStartedState::None;
let mut stack_dirty = false;
let mut escape = false;
loop {
match self.next_char() {
Err(e) => return Some(Err(e)),
Ok(c) => {
if stack_dirty {
stack_dirty = false;
if compare_stack_reader(&key_stack, path_to_look_for) {
self.state = State::Started;
let r = loop {
match self.next_char() {
Err(e) => {
break Err(e);
}
Ok(c) => match c {
b'[' => break Ok(()),
_ => {
continue;
}
},
};
};
if let Ok(next) = self.next_char() {
if next == b']' {
return None;
}
if r.is_ok() {
return Some(self.deserialize_one_item(Some(next)));
}
}
}
}
match state {
NotStartedState::ParseObjectKey => {
if c == b'\"' && !escape {
state = NotStartedState::ExpectPoints;
key_stack.push(std::mem::take(&mut current_key));
stack_dirty = true;
} else {
current_key.push(c);
}
}
NotStartedState::ParseValue(t) => {
match t {
ParseValueType::String => {
if c == b'\"' && !escape {
state = NotStartedState::ParseObject;
key_stack.pop();
stack_dirty = true;
}
if escape {
escape = false;
}
}
ParseValueType::Array => {
if c == b']' {
state = NotStartedState::ParseObject;
key_stack.pop();
stack_dirty = true;
}
}
ParseValueType::Number => {
if c == b',' {
state = NotStartedState::ParseObject;
key_stack.pop();
stack_dirty = true;
}
}
ParseValueType::Null => {
if c == b',' {
state = NotStartedState::ParseObject;
key_stack.pop();
stack_dirty = true;
}
}
ParseValueType::Map => {
state = NotStartedState::ParseObject;
}
};
}
NotStartedState::ExpectValue => {
if c == b'\"' {
state = NotStartedState::ParseValue(ParseValueType::String);
} else if c == b'n' {
state = NotStartedState::ParseValue(ParseValueType::Null);
} else if c == b'{' {
state = NotStartedState::ParseValue(ParseValueType::Map);
} else if c == b'[' {
state = NotStartedState::ParseValue(ParseValueType::Array);
} else if c == b' ' {
} else {
state = NotStartedState::ParseValue(ParseValueType::Number);
}
}
NotStartedState::ExpectPoints => {
if c == b':' {
state = NotStartedState::ExpectValue;
}
}
NotStartedState::ParseObject => {
if c == b'\"' {
state = NotStartedState::ParseObjectKey;
}
if c == b'}' {
key_stack.pop();
stack_dirty = true;
}
}
NotStartedState::None => {
if c == b'{' {
state = NotStartedState::ParseObject;
} else if c == b'[' {
todo!("arrays are unsupported for now");
} else if c != b' ' {
panic!("malformed");
}
}
};
}
}
}
}
State::Started => loop {
break match self.next_char() {
Err(e) => Some(Err(e)),
Ok(c) => match c {
b']' => {
self.state = State::Ended;
None
}
b',' => {
Some(self.deserialize_one_item(None))
}
w => {
if w.is_ascii_whitespace() {
continue;
} else if w.is_ascii_digit() || w == b'n' {
Some(self.deserialize_one_item(Some(w)))
} else if w == b'}' || w == b']' {
None
} else {
Some(Err(JsonItError::InvalidJsonCharacter(char::from(w))))
}
}
},
};
},
State::Ended => None,
}
}
}
#[derive(Debug)]
pub enum JsonItError {
SerdeError(serde_json::Error),
IoError(std::io::Error),
InvalidJsonCharacter(char),
}