From 0b37b2325bf037629ff52fc1144677c342d6b8d1 Mon Sep 17 00:00:00 2001 From: Laszlo Nagy Date: Wed, 16 Aug 2023 21:26:02 +1000 Subject: [PATCH] stop consuming wrong inputs --- src/iterator.rs | 69 +++++++++++++++++++++++++++++++++---------------- tests/test.rs | 11 +------- 2 files changed, 48 insertions(+), 32 deletions(-) diff --git a/src/iterator.rs b/src/iterator.rs index 6b97a1f..656b3d9 100644 --- a/src/iterator.rs +++ b/src/iterator.rs @@ -10,34 +10,57 @@ pub fn iter_json_array(mut reader: R) -> impl Iterator> T: DeserializeOwned, R: io::Read, { - let mut at_start = false; + let mut at_start = State::AtStart; std::iter::from_fn(move || yield_next_obj(&mut reader, &mut at_start).transpose()) } -fn yield_next_obj(mut reader: R, at_start: &mut bool) -> Result> +enum State { + AtStart, + AtMiddle, + Finished, + Failed, +} + +fn yield_next_obj(mut reader: R, state: &mut State) -> Result> where T: DeserializeOwned, R: io::Read, { - if !*at_start { - *at_start = true; - if read_skipping_ws(&mut reader)? == b'[' { - // read the next char to see if the array is empty - let peek = read_skipping_ws(&mut reader)?; - if peek == b']' { - Ok(None) + match state { + State::AtStart => { + if read_skipping_ws(&mut reader)? == b'[' { + // read the next char to see if the array is empty + let peek = read_skipping_ws(&mut reader)?; + if peek == b']' { + *state = State::Finished; + Ok(None) + } else { + *state = State::AtMiddle; + deserialize_single(io::Cursor::new([peek]).chain(reader)).map(Some) + } } else { - deserialize_single(io::Cursor::new([peek]).chain(reader)).map(Some) + *state = State::Failed; + Err(serde::de::Error::custom("expected `[`")) } - } else { - Err(serde::de::Error::custom("expected `[`")) - } - } else { - match read_skipping_ws(&mut reader)? { - b',' => deserialize_single(reader).map(Some), - b']' => Ok(None), - _ => Err(serde::de::Error::custom("expected `,` or `]`")), - } + }, + State::AtMiddle => { + match read_skipping_ws(&mut reader)? { + b',' => + deserialize_single(reader).map(Some), + b']' => { + *state = State::Finished; + Ok(None) + }, + _ => { + *state = State::Failed; + Err(serde::de::Error::custom("expected `,` or `]`")) + }, + } + }, + State::Finished => + Ok(None), + State::Failed => + Ok(None), } } @@ -48,8 +71,10 @@ fn deserialize_single(reader: R) -> Result { let next_obj = Deserializer::from_reader(reader).into_iter::().next(); match next_obj { - Some(result) => result.map_err(Into::into), - None => Err(serde::de::Error::custom("premature EOF")), + Some(result) => + result, + None => + Err(serde::de::Error::custom("premature EOF")), } } @@ -57,7 +82,7 @@ fn read_skipping_ws(mut reader: impl io::Read) -> Result { loop { let mut byte = 0u8; if let Err(io) = reader.read_exact(std::slice::from_mut(&mut byte)) { - return Err(Error::io(io)) + return Err(Error::io(io)); } if !byte.is_ascii_whitespace() { return Ok(byte); diff --git a/tests/test.rs b/tests/test.rs index 984a109..81a39b6 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -8,15 +8,6 @@ use json_compilation_db::*; mod failures { use super::*; - macro_rules! assert_syntax_error { - ($x:expr) => { - match $x { - Some(Err(error)) => assert_eq!(error.classify(), Category::Syntax), - _ => assert!(false, "shout be syntax error"), - } - }; - } - macro_rules! assert_semantic_error { ($x:expr) => { match $x { @@ -31,7 +22,7 @@ mod failures { let content = r#"this is not json"#; let mut result = read(content.as_bytes()); - assert_syntax_error!(result.next()); + assert_semantic_error!(result.next()); assert!(result.next().is_none()); }