#[cfg(feature = "io")]
use std::io::Read;
#[cfg(feature = "io")]
use deser_core::de::DeserializeOwned;
use deser_core::de::{self, DeserializeDriver, Frame, Progress};
use deser_core::{Error, ErrorKind, State};
use crate::Trailing;
use crate::de::{Deserializer, DeserializerConfig};
use crate::parser::Cursor;
use crate::parser::{Copying, Discard, Options, Parser, Progress as ParseProgress};
use crate::scan::LineScan;
use crate::scan::skip_to_escape;
use crate::scan::skip_to_escape_single;
fn skip_whitespace(input: &[u8], pos: usize, eof: bool) -> (usize, bool) {
let mut cursor = Cursor::new_partial(input, pos, eof);
let token = cursor.parse_whitespace().is_some();
(cursor.pos, token)
}
#[derive(Debug, Default)]
struct StreamState {
done: bool,
parser: Parser,
skipping: Option<usize>,
failed: bool,
ended: bool,
pos: usize,
line: LineScan,
value: Option<Value>,
}
#[derive(Debug)]
struct Value {
start: usize,
kind: ValueKind,
depth: usize,
in_string: bool,
single: bool,
}
#[derive(Debug)]
enum ValueKind {
Scalar { parser: Parser, parsed: usize },
Structure,
}
fn frame_all(state: &mut StreamState, input: &[u8], eof: bool) -> Result<Frame, Error> {
if state.done {
return trailing_whitespace(input, 0, eof).map(|progress| match progress {
Progress::End => Frame::End,
Progress::NeedMore { consumed } => Frame::Incomplete { consumed },
Progress::Done { .. } => unreachable!(),
});
}
if !eof {
return Ok(Frame::Incomplete { consumed: 0 });
}
let (start, _) = skip_whitespace(input, 0, eof);
Ok(if start < input.len() {
state.done = true;
Frame::Value {
start,
end: input.len(),
consumed: input.len(),
}
} else {
Frame::End
})
}
fn trailing_whitespace(input: &[u8], offset: usize, eof: bool) -> Result<Progress, Error> {
match skip_whitespace(input, 0, eof) {
(pos, _) if pos == input.len() && eof => Ok(Progress::End),
(pos, false) if !eof => Ok(Progress::NeedMore { consumed: pos }),
(pos, _) => Err(Error::with_offset(
ErrorKind::Syntax,
"garbage after input",
offset + pos,
)),
}
}
fn frame_line(state: &mut StreamState, input: &[u8], eof: bool) -> Frame {
if state.pos == 0 {
match skip_whitespace(input, 0, eof) {
(0, true) => {}
(start, true) => return Frame::Incomplete { consumed: start },
(_, false) if input.is_empty() && eof => return Frame::End,
(start, false) if eof && start < input.len() => {
return Frame::Value {
start,
end: input.len(),
consumed: input.len(),
};
}
(start, false) => return Frame::Incomplete { consumed: start },
}
}
let end = state.line.find_end(input, state.pos);
let end = match end {
Some(end) => end,
None if eof => input.len(),
None => {
state.pos = input.len();
return Frame::Incomplete { consumed: 0 };
}
};
state.pos = 0;
state.line = LineScan::default();
let consumed = (end + 1).min(input.len());
match skip_whitespace(&input[..end], 0, true) {
(start, _) if start < end => Frame::Value {
start,
end,
consumed,
},
_ if consumed == 0 => Frame::End,
_ => Frame::Incomplete { consumed },
}
}
fn frame_value(state: &mut StreamState, input: &[u8], eof: bool) -> Frame {
let value = match state.value {
Some(ref mut value) => value,
None => {
let start = match skip_whitespace(input, 0, eof) {
(start, true) => start,
(_, false) if input.is_empty() && eof => return Frame::End,
(consumed, false) => return Frame::Incomplete { consumed },
};
let (kind, depth, in_string) = match input[start] {
b'"' => (ValueKind::Structure, 0, true),
b'\'' => (ValueKind::Structure, 0, true),
b'{' | b'[' => (ValueKind::Structure, 1, false),
b'}' | b']' | b',' | b':' => {
return Frame::Value {
start,
end: start + 1,
consumed: start + 1,
};
}
_ => (
ValueKind::Scalar {
parser: Parser::default(),
parsed: 0,
},
0,
false,
),
};
state.pos = start + 1;
state.value.insert(Value {
start,
kind,
depth,
in_string,
single: input[start] == b'\'',
})
}
};
let end = match value.kind {
ValueKind::Scalar {
ref mut parser,
ref mut parsed,
} => {
let pos = value.start + *parsed;
let options = Options {
validate_utf8: true,
exact_numbers: false,
};
let mut discard = Discard(State::new());
match parser.parse(&input[pos..], 0, eof, 0, options, &mut discard) {
Ok(ParseProgress::Done(end)) => Some(pos + end),
Ok(ParseProgress::NeedMore(consumed)) => {
*parsed += consumed;
state.pos = input.len();
None
}
Err(err) => Some(error_end(&err, input, pos)),
}
}
ValueKind::Structure => scan_structure(input, &mut state.pos, value),
};
let start = value.start;
match end {
Some(end) => {
state.value = None;
state.pos = 0;
Frame::Value {
start,
end,
consumed: end,
}
}
None if eof => {
state.value = None;
state.pos = 0;
Frame::Value {
start,
end: input.len(),
consumed: input.len(),
}
}
None => {
value.start = 0;
state.pos -= start;
Frame::Incomplete { consumed: start }
}
}
}
fn error_end(err: &Error, input: &[u8], pos: usize) -> usize {
match err.offset() {
Some(offset) if err.kind() != ErrorKind::EndOfFile => (pos + offset + 1).min(input.len()),
_ => input.len(),
}
}
fn scan_structure(input: &[u8], pos: &mut usize, value: &mut Value) -> Option<usize> {
let mut index = *pos;
while index < input.len() {
if value.in_string {
index = if value.single {
skip_to_escape_single(input, index)
} else {
skip_to_escape(input, index)
};
let byte = input.get(index).copied();
let byte = if value.single && byte == Some(b'\'') {
Some(b'"')
} else {
byte
};
match byte {
Some(b'"') => {
value.in_string = false;
index += 1;
if value.depth == 0 {
return Some(index);
}
}
Some(b'\\') => {
if index + 1 >= input.len() {
break;
}
index += 2;
}
Some(_) => index += 1,
None => break,
}
} else {
match input[index] {
b'"' => {
value.in_string = true;
value.single = false;
}
b'\'' => {
value.in_string = true;
value.single = true;
}
b'/' => {
match skip_whitespace(input, index, false) {
(next, true) if next == index => index += 1,
(next, token) => {
index = next;
if !token && next < input.len() {
break;
}
}
}
continue;
}
b'{' | b'[' => value.depth += 1,
b'}' | b']' => {
value.depth -= 1;
if value.depth == 0 {
return Some(index + 1);
}
}
_ => {}
}
index += 1;
}
}
*pos = index;
None
}
#[derive(Debug)]
pub struct StreamDeserializer {
config: DeserializerConfig,
state: StreamState,
}
impl Default for StreamDeserializer {
fn default() -> StreamDeserializer {
StreamDeserializer::new()
}
}
impl StreamDeserializer {
pub fn new() -> StreamDeserializer {
StreamDeserializer::with_config(DeserializerConfig::new())
}
pub fn with_config(config: DeserializerConfig) -> StreamDeserializer {
StreamDeserializer {
config,
state: StreamState::default(),
}
}
pub fn config(&self) -> &DeserializerConfig {
&self.config
}
fn skip_to_value(
&mut self,
input: &[u8],
offset: usize,
eof: bool,
) -> Result<Result<usize, Progress>, Error> {
let options = self.options();
let state = &mut self.state;
if state.ended {
return Ok(Err(Progress::End));
}
if state.failed {
return Err(Error::new(
ErrorKind::InvalidState,
"cannot continue after an error",
));
}
let mut pos = 0;
if let Some(skip) = state.skipping {
let mut discard = Discard(State::new());
match state
.parser
.parse(input, skip, eof, offset, options, &mut discard)
{
Ok(ParseProgress::Done(end)) => {
state.skipping = None;
state.done = self.config.trailing_mode() == Trailing::Strict;
pos = end;
}
Ok(ParseProgress::NeedMore(consumed)) => {
state.skipping = Some(0);
return Ok(Err(Progress::NeedMore { consumed }));
}
Err(err) => {
state.parser.reset();
state.skipping = None;
state.failed = true;
return Err(err);
}
}
}
if !state.parser.is_idle() {
return Ok(Ok(pos));
}
if state.done {
return match trailing_whitespace(&input[pos..], offset + pos, eof)? {
Progress::NeedMore { consumed } => Ok(Err(Progress::NeedMore {
consumed: pos + consumed,
})),
progress => Ok(Err(progress)),
};
}
let token;
(pos, token) = skip_whitespace(input, pos, eof);
if !token && (pos == input.len() || !eof) {
return Ok(Err(if eof {
Progress::End
} else {
Progress::NeedMore { consumed: pos }
}));
}
Ok(Ok(pos))
}
fn options(&self) -> Options {
Options {
validate_utf8: true,
exact_numbers: self.config.exact_numbers_enabled(),
}
}
}
impl de::StreamDeserializer for StreamDeserializer {
fn context(&self) -> deser_core::Context {
self.config.context().clone()
}
fn frame(&mut self, input: &[u8], eof: bool) -> Result<Frame, Error> {
let state = &mut self.state;
match self.config.trailing_mode() {
Trailing::Strict => frame_all(state, input, eof),
Trailing::Newline => Ok(frame_line(state, input, eof)),
Trailing::Stop => Ok(frame_value(state, input, eof)),
}
}
fn drive_frame<'de>(
&mut self,
frame: &'de [u8],
driver: &mut DeserializeDriver<'_, 'de>,
) -> Result<(), Error> {
let mut de = Deserializer::from_frame(frame, &self.config);
de.drive(driver)
}
fn is_text(&self) -> bool {
true
}
fn supports_partial(&self) -> bool {
self.config.trailing_mode() != Trailing::Newline
}
fn drive_partial(
&mut self,
input: &[u8],
offset: usize,
eof: bool,
driver: &mut DeserializeDriver<'_, '_>,
) -> Result<Progress, Error> {
let pos = match self.skip_to_value(input, offset, eof)? {
Ok(pos) => pos,
Err(progress) => return Ok(progress),
};
let options = self.options();
let state = &mut self.state;
match state
.parser
.parse(input, pos, eof, offset, options, &mut Copying(driver))
{
Ok(ParseProgress::Done(end)) => {
state.done = self.config.trailing_mode() == Trailing::Strict;
Ok(Progress::Done { consumed: end })
}
Ok(ParseProgress::NeedMore(consumed)) => Ok(Progress::NeedMore { consumed }),
Err(err) => {
if let Some(resume) = state.parser.recoverable() {
state.skipping = Some(resume);
} else {
state.parser.reset();
state.ended = eof && err.kind() == ErrorKind::EndOfFile;
state.failed = true;
}
Err(err)
}
}
}
fn peek(&mut self, input: &[u8], eof: bool) -> Result<Option<Progress>, Error> {
if !de::StreamDeserializer::supports_partial(self) {
return Ok(None);
}
Ok(Some(match self.skip_to_value(input, 0, eof)? {
Ok(pos) => Progress::Done { consumed: pos },
Err(progress) => progress,
}))
}
}
#[cfg(feature = "io")]
impl DeserializerConfig {
pub fn reader<R: Read>(&self, reader: R) -> deser_core::io::Reader<R, StreamDeserializer> {
deser_core::io::Reader::new(reader, StreamDeserializer::with_config(self.clone()))
}
pub fn from_reader<T: DeserializeOwned, R: Read>(&self, reader: R) -> Result<T, Error> {
deser_core::io::from_reader(reader, StreamDeserializer::with_config(self.clone()))
}
}
#[cfg(feature = "io")]
pub fn from_reader<T: DeserializeOwned, R: Read>(reader: R) -> Result<T, Error> {
DeserializerConfig::new().from_reader(reader)
}