use alloc::string::String;
use alloc::sync::Arc;
use core::marker::PhantomData;
use core::str;
use deser_core::de::{self, Deserialize, DeserializeDriver, deserialize_value};
use deser_core::{Error, ErrorKind, Source, TrackLocations};
use crate::Trailing;
use crate::parser::{Borrowing, Cursor, Options, Parser, Progress};
use crate::scan::LineScan;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DeserializerConfig {
exact_numbers: bool,
trailing: Trailing,
context: deser_core::Context,
}
impl Default for DeserializerConfig {
fn default() -> DeserializerConfig {
DeserializerConfig::new()
}
}
impl DeserializerConfig {
pub const fn new() -> DeserializerConfig {
DeserializerConfig {
exact_numbers: true,
trailing: Trailing::Strict,
context: deser_core::Context::new(),
}
}
pub const fn builder() -> DeserializerConfigBuilder {
DeserializerConfigBuilder::new()
}
pub const fn into_builder(self) -> DeserializerConfigBuilder {
DeserializerConfigBuilder { value: self }
}
pub fn set_context(&mut self, context: deser_core::Context) {
self.context = context;
}
pub(crate) fn without_context(&self) -> DeserializerConfig {
let mut config = self.clone();
config.context = deser_core::Context::default();
config
}
pub fn context(&self) -> &deser_core::Context {
&self.context
}
pub const fn set_trailing(&mut self, trailing: Trailing) {
self.trailing = trailing;
}
pub(crate) fn trailing_mode(&self) -> Trailing {
self.trailing
}
pub(crate) fn exact_numbers_enabled(&self) -> bool {
self.exact_numbers
}
pub const fn set_exact_numbers(&mut self, yes: bool) {
self.exact_numbers = yes;
}
pub fn from_str<'de, T: Deserialize<'de>>(&self, s: &'de str) -> Result<T, Error> {
deserialize_value(|driver| self.drive_str(s, driver))
}
fn drive_str<'de>(
&self,
s: &'de str,
driver: &mut DeserializeDriver<'_, 'de>,
) -> Result<(), Error> {
de::Deserializer::drive(
&mut Deserializer::from_str_with_config(s, self.clone()),
driver,
)
}
pub fn from_slice<'de, T: Deserialize<'de>>(&self, bytes: &'de [u8]) -> Result<T, Error> {
deserialize_value(|driver| self.drive_slice(bytes, driver))
}
fn drive_slice<'de>(
&self,
bytes: &'de [u8],
driver: &mut DeserializeDriver<'_, 'de>,
) -> Result<(), Error> {
de::Deserializer::drive(
&mut Deserializer::from_slice_with_config(bytes, self.clone()),
driver,
)
}
}
#[derive(Debug, Clone)]
#[must_use]
pub struct DeserializerConfigBuilder {
value: DeserializerConfig,
}
impl DeserializerConfigBuilder {
pub const fn new() -> DeserializerConfigBuilder {
DeserializerConfigBuilder {
value: DeserializerConfig::new(),
}
}
pub const fn trailing(mut self, trailing: Trailing) -> DeserializerConfigBuilder {
self.value.set_trailing(trailing);
self
}
pub const fn exact_numbers(mut self, yes: bool) -> DeserializerConfigBuilder {
self.value.set_exact_numbers(yes);
self
}
pub fn context(mut self, context: deser_core::Context) -> DeserializerConfigBuilder {
self.value.set_context(context);
self
}
pub const fn build(self) -> DeserializerConfig {
let value = unsafe { core::ptr::read(&self.value) };
core::mem::forget(self);
value
}
}
impl Default for DeserializerConfigBuilder {
fn default() -> DeserializerConfigBuilder {
DeserializerConfigBuilder::new()
}
}
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,
}
}
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,
}
}
pub(crate) fn from_frame(input: &'a [u8], config: &DeserializerConfig) -> Deserializer<'a> {
let mut de = Deserializer::from_slice_with_config(input, config.without_context());
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(());
}
let mut err =
Error::with_offset(ErrorKind::Syntax, "garbage after input", self.next_token());
err.resolve_position(self.input);
Err(err)
}
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.config.context.is_empty() {
driver.set_default_context(self.config.context.clone());
}
if self.failed {
return Err(Error::new(
ErrorKind::InvalidState,
"cannot continue after an error",
));
}
if TrackLocations::of(driver.state()) {
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(source).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, mut err: Error) -> Error {
if err.offset().is_none() {
err.set_offset(self.pos);
}
err.resolve_position(self.input);
err
}
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::Syntax, 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)
}