use alloc::sync::Arc;
use deser_core::de::{self, Deserialize, DeserializeDriver, LexicalRules};
use deser_core::{Error, ErrorKind, Source};
use crate::common::{Borrowing, Copying, Out, decode_utf16_text, syntax_error};
use crate::format::Format;
use crate::{read_ascii, read_binary, read_xml};
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct DeserializerConfig {
track_locations: bool,
}
impl DeserializerConfig {
pub const fn new() -> DeserializerConfig {
DeserializerConfig {
track_locations: false,
}
}
pub const fn track_locations(mut self, yes: bool) -> DeserializerConfig {
self.track_locations = yes;
self
}
pub fn from_slice<'de, T: Deserialize<'de>>(&self, input: &'de [u8]) -> Result<T, Error> {
Deserializer::from_slice_with_config(input, self).deserialize()
}
}
pub struct Deserializer<'a> {
input: &'a [u8],
format: Format,
config: DeserializerConfig,
}
impl<'a> Deserializer<'a> {
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,
format: Format::detect(input),
config: config.clone(),
}
}
pub fn config(&self) -> &DeserializerConfig {
&self.config
}
pub fn format(&self) -> Format {
self.format
}
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 drive(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
if self.format == Format::Binary {
return read_binary::parse(self.input, &mut Borrowing(driver));
}
if let Some(text) = decode_utf16_text(self.input) {
let text = text.map_err(|offset| syntax_error(offset, "invalid UTF-16"))?;
let text = text.strip_prefix('\u{feff}').unwrap_or(&text);
return self.drive_text(text, &mut Copying(driver));
}
let input = self
.input
.strip_prefix(b"\xef\xbb\xbf")
.unwrap_or(self.input);
let text = core::str::from_utf8(input).map_err(|err| {
let offset = self.input.len() - input.len() + err.valid_up_to();
Error::new(ErrorKind::Unexpected, "invalid UTF-8").with_offset(offset)
})?;
self.drive_text(text, &mut Borrowing(driver))
}
fn drive_text<'i, O: Out<'i>>(&self, text: &'i str, out: &mut O) -> Result<(), Error> {
if self.config.track_locations {
Source::set(out.state_mut(), Arc::<str>::from(text));
}
let rv = if self.format == Format::Xml {
read_xml::parse(text, out)
} else {
LexicalRules::STRICT
.with_lenient_bools(true)
.set(out.state_mut());
read_ascii::parse(text, out)
};
rv.map_err(|err| err.resolve_position(text.as_bytes()))
}
}
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_slice<'de, T: Deserialize<'de>>(input: &'de [u8]) -> Result<T, Error> {
DeserializerConfig::new().from_slice(input)
}