use alloc::string::String;
use alloc::sync::Arc;
use core::marker::PhantomData;
use core::str;
use deser_core::de::{self, Deserialize, DeserializeDriver};
use deser_core::{BytesFormat, Error, ErrorKind, Source};
use crate::Trailing;
use crate::parser::{Borrowing, Cursor, Options, Parser, Progress};
use crate::scan::LineScan;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DeserializerConfig {
track_locations: bool,
exact_numbers: bool,
trailing: Trailing,
bytes: BytesFormat,
}
impl Default for DeserializerConfig {
fn default() -> DeserializerConfig {
DeserializerConfig::new()
}
}
impl DeserializerConfig {
pub const fn new() -> DeserializerConfig {
DeserializerConfig {
track_locations: false,
exact_numbers: true,
trailing: Trailing::Strict,
bytes: BytesFormat::BASE64,
}
}
pub const fn bytes(mut self, format: BytesFormat) -> DeserializerConfig {
self.bytes = format;
self
}
pub const fn trailing(mut self, trailing: Trailing) -> DeserializerConfig {
self.trailing = trailing;
self
}
pub(crate) fn trailing_mode(&self) -> Trailing {
self.trailing
}
pub(crate) fn bytes_format(&self) -> BytesFormat {
self.bytes
}
pub(crate) fn exact_numbers_enabled(&self) -> bool {
self.exact_numbers
}
pub const fn track_locations(mut self, yes: bool) -> DeserializerConfig {
self.track_locations = yes;
self
}
pub const fn exact_numbers(mut self, yes: bool) -> DeserializerConfig {
self.exact_numbers = yes;
self
}
pub fn from_str<'de, T: Deserialize<'de>>(&self, s: &'de str) -> Result<T, Error> {
Deserializer::from_str_with_config(s, self).deserialize()
}
pub fn from_slice<'de, T: Deserialize<'de>>(&self, bytes: &'de [u8]) -> Result<T, Error> {
Deserializer::from_slice_with_config(bytes, self).deserialize()
}
}
pub struct Deserializer<'a> {
input: &'a [u8],
pos: usize,
parser: Parser,
validate_utf8: bool,
failed: bool,
source: Option<Arc<str>>,
config: DeserializerConfig,
}
impl<'a> Deserializer<'a> {
#[allow(clippy::should_implement_trait)]
pub fn from_str(input: &'a str) -> Deserializer<'a> {
Deserializer::from_str_with_config(input, &DeserializerConfig::new())
}
pub fn from_str_with_config(input: &'a str, config: &DeserializerConfig) -> Deserializer<'a> {
Deserializer {
input: input.as_bytes(),
validate_utf8: false,
pos: 0,
parser: Parser::default(),
failed: false,
source: None,
config: config.clone(),
}
}
pub fn from_slice(input: &'a [u8]) -> Deserializer<'a> {
Deserializer::from_slice_with_config(input, &DeserializerConfig::new())
}
pub fn from_slice_with_config(
input: &'a [u8],
config: &DeserializerConfig,
) -> Deserializer<'a> {
Deserializer {
input,
validate_utf8: true,
pos: 0,
parser: Parser::default(),
failed: false,
source: None,
config: config.clone(),
}
}
pub(crate) fn from_frame(input: &'a [u8], config: &DeserializerConfig) -> Deserializer<'a> {
let mut de = Deserializer::from_slice_with_config(input, config);
de.config.trailing = Trailing::Strict;
de
}
pub fn config(&self) -> &DeserializerConfig {
&self.config
}
pub fn offset(&self) -> usize {
self.pos
}
pub fn is_end(&self) -> bool {
self.failed || self.next_token() == self.input.len()
}
pub fn end(&self) -> Result<(), Error> {
if self.is_end() {
return Ok(());
}
Err(Error::new(ErrorKind::Unexpected, "garbage after input")
.with_offset(self.next_token())
.resolve_position(self.input))
}
fn next_token(&self) -> usize {
let mut cursor = Cursor::new(self.input, self.pos);
cursor.parse_whitespace();
cursor.pos
}
fn source(&self) -> alloc::borrow::Cow<'a, str> {
if self.validate_utf8 {
String::from_utf8_lossy(self.input)
} else {
alloc::borrow::Cow::Borrowed(unsafe { str::from_utf8_unchecked(self.input) })
}
}
pub fn deserialize<T: Deserialize<'a>>(&mut self) -> Result<T, Error> {
de::Deserializer::deserialize(self)
}
pub fn deserialize_with<T, F>(&mut self, setup: F) -> Result<T, Error>
where
T: Deserialize<'a>,
F: FnOnce(&mut DeserializeDriver<'_, 'a>),
{
de::Deserializer::deserialize_with(self, setup)
}
pub fn iter<T: Deserialize<'a>>(&mut self) -> Iter<'_, 'a, T> {
Iter {
de: self,
failed: false,
_marker: PhantomData,
}
}
pub fn drive(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
if self.failed {
return Err(Error::new(
ErrorKind::Unexpected,
"cannot continue after an error",
));
}
if self.config.track_locations {
let source = match self.source {
Some(ref source) => source.clone(),
None => {
let source: Arc<str> = self.source().into();
self.source = Some(source.clone());
source
}
};
Source::set(driver.state_mut(), source);
}
if self.config.bytes != BytesFormat::BASE64 {
self.config.bytes.set(driver.state_mut());
}
let input = self.input;
let line_end = if self.config.trailing == Trailing::Newline {
self.skip_whitespace();
let end = LineScan::default()
.find_end(input, self.pos)
.unwrap_or(input.len());
self.input = &input[..end];
Some(end)
} else {
None
};
let rv = self.drive_impl(driver);
self.input = input;
let rv = rv.map_err(|err| self.locate_error(err));
match line_end {
Some(end) => self.pos = end,
None => self.failed = rv.is_err() && !self.is_end(),
}
rv
}
#[cold]
fn locate_error(&self, err: Error) -> Error {
let err = match err.offset() {
Some(_) => err,
None => err.with_offset(self.pos),
};
err.resolve_position(self.input)
}
fn drive_impl(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
let options = Options {
validate_utf8: self.validate_utf8,
exact_numbers: self.config.exact_numbers,
};
let mut out = Borrowing(driver);
match self
.parser
.parse(self.input, self.pos, true, 0, options, &mut out)
{
Ok(Progress::Done(pos)) => {
self.pos = pos;
self.finish_value()
}
Ok(Progress::NeedMore(_)) => unreachable!("the input is complete"),
Err(err) => {
self.parser.reset();
Err(err)
}
}
}
fn skip_whitespace(&mut self) {
self.pos = self.next_token();
}
#[inline]
fn finish_value(&mut self) -> Result<(), Error> {
let msg = match self.config.trailing {
Trailing::Strict => "garbage after input",
Trailing::Newline => "expected end of line after value",
Trailing::Stop => return Ok(()),
};
self.skip_whitespace();
if self.pos < self.input.len() {
return Err(Error::new(ErrorKind::Unexpected, msg));
}
Ok(())
}
}
pub struct Iter<'b, 'a, T> {
de: &'b mut Deserializer<'a>,
failed: bool,
_marker: PhantomData<fn() -> T>,
}
impl<'b, 'a, T: Deserialize<'a>> Iterator for Iter<'b, 'a, T> {
type Item = Result<T, Error>;
fn next(&mut self) -> Option<Self::Item> {
if self.failed || self.de.is_end() {
return None;
}
let rv = self.de.deserialize();
self.failed = rv.is_err();
Some(rv)
}
}
impl<'a> de::Deserializer<'a> for Deserializer<'a> {
fn drive(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
Deserializer::drive(self, driver)
}
}
pub fn from_str<'de, T: Deserialize<'de>>(s: &'de str) -> Result<T, Error> {
DeserializerConfig::new().from_str(s)
}
pub fn from_slice<'de, T: Deserialize<'de>>(bytes: &'de [u8]) -> Result<T, Error> {
DeserializerConfig::new().from_slice(bytes)
}