use alloc::string::String;
use alloc::vec::Vec;
use core::marker::PhantomData;
use deser_core::adapters::BytesEncoding;
use deser_core::de::{self, Deserialize, DeserializeDriver, deserialize_value};
use deser_core::{BytesFormat, Error};
use crate::parser::{self, syntax_error};
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct DeserializerConfig {
context: deser_core::Context,
}
impl DeserializerConfig {
pub const fn new() -> DeserializerConfig {
DeserializerConfig {
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 fn context(&self) -> &deser_core::Context {
&self.context
}
pub fn from_slice<'de, T: Deserialize<'de>>(&self, input: &'de [u8]) -> Result<T, Error> {
deserialize_value(|driver| self.drive_slice(input, driver))
}
pub fn from_str<'de, T: Deserialize<'de>>(&self, input: &'de str) -> Result<T, Error> {
self.from_slice(input.as_bytes())
}
fn drive_slice<'de>(
&self,
input: &'de [u8],
driver: &mut DeserializeDriver<'_, 'de>,
) -> Result<(), Error> {
let mut deserializer = Deserializer::from_slice_with_config(input, self.clone());
de::Deserializer::drive(&mut deserializer, driver)?;
deserializer.end()
}
}
#[derive(Debug, Clone)]
#[must_use]
pub struct DeserializerConfigBuilder {
value: DeserializerConfig,
}
impl DeserializerConfigBuilder {
pub const fn new() -> DeserializerConfigBuilder {
DeserializerConfigBuilder {
value: DeserializerConfig::new(),
}
}
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,
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,
pos: 0,
config,
}
}
pub fn config(&self) -> &DeserializerConfig {
&self.config
}
pub fn offset(&self) -> usize {
self.pos
}
pub fn is_end(&self) -> bool {
self.pos >= self.input.len()
}
pub fn end(&self) -> Result<(), Error> {
if self.is_end() {
Ok(())
} else {
Err(syntax_error(self.pos, "trailing data after value"))
}
}
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> {
driver
.state_mut()
.set_default(BytesFormat::encoded::<PhpStrings>());
let scan = parser::scan(self.input, self.pos)?;
parser::emit(self.input, self.pos, &scan.lists, driver)?;
self.pos = scan.end;
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> {
if !self.config.context.is_empty() {
driver.set_default_context(self.config.context.clone());
}
Deserializer::drive(self, driver)
}
}
struct PhpStrings;
impl BytesEncoding for PhpStrings {
const NAME: &'static str = "php string";
fn encode(bytes: &[u8], out: &mut String) {
out.push_str(&String::from_utf8_lossy(bytes));
}
fn decode(s: &str) -> Result<Vec<u8>, Error> {
Ok(s.as_bytes().to_vec())
}
}
pub fn from_slice<'de, T: Deserialize<'de>>(input: &'de [u8]) -> Result<T, Error> {
DeserializerConfig::new().from_slice(input)
}
pub fn from_str<'de, T: Deserialize<'de>>(input: &'de str) -> Result<T, Error> {
DeserializerConfig::new().from_str(input)
}