#[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};
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,
value: Option<Value>,
frame_column: usize,
}
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;
state.frame_column = crate::parser::advance_column(state.parser.column(), &input[..start]);
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 = input[state.pos..]
.iter()
.position(|&b| b == b'\n')
.map(|index| state.pos + index);
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;
let consumed = (end + 1).min(input.len());
match skip_whitespace(&input[..end], 0, true) {
(start, _) if start < end => {
state.frame_column = 0;
Frame::Value {
start,
end,
consumed,
}
}
_ if consumed == 0 => Frame::End,
_ => Frame::Incomplete { consumed },
}
}
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(),
}
}
#[derive(Debug)]
struct Value {
start: usize,
parser: Parser,
parsed: usize,
}
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) => {
state.parser.advance(&input[..consumed]);
return Frame::Incomplete { consumed };
}
};
state.value.insert(Value {
start,
parser: Parser::default(),
parsed: 0,
})
}
};
let start = value.start;
let pos = start + value.parsed;
let options = Options {
validate_utf8: true,
exact_numbers: false,
};
let mut discard = Discard(State::new());
let end = match value
.parser
.parse(&input[pos..], 0, eof, 0, options, &mut discard)
{
Ok(ParseProgress::Done(end)) => pos + end,
Ok(ParseProgress::NeedMore(consumed)) => {
value.parsed += consumed;
value.start = 0;
state.parser.advance(&input[..start]);
return Frame::Incomplete { consumed: start };
}
Err(err) => error_end(&err, input, pos),
};
state.value = None;
state.frame_column = crate::parser::advance_column(state.parser.column(), &input[..start]);
state.parser.advance(&input[..end]);
Frame::Value {
start,
end,
consumed: end,
}
}
#[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) {
state.parser.advance(&input[..pos]);
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.set_column(self.state.frame_column);
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;
state.parser.advance(&input[..end]);
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) => {
self.state.parser.advance(&input[..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)
}