use std::borrow::Cow;
use std::collections::HashMap;
use deser_core::Text;
use deser_core::de::{
self, Deserialize, DeserializeDriver, DuplicateKeys, LexicalRules, deserialize_value,
};
use deser_core::{Atom, Bytes, ContainerShape, Error, ErrorKind, Event, Source, TrackLocations};
use crate::Nesting;
use crate::encoding::{Decoded, decode};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DeserializerConfig {
nesting: Nesting,
max_depth: usize,
max_params: usize,
context: deser_core::Context,
}
impl Default for DeserializerConfig {
fn default() -> DeserializerConfig {
DeserializerConfig::new()
}
}
impl DeserializerConfig {
pub const fn new() -> DeserializerConfig {
DeserializerConfig {
nesting: Nesting::Brackets,
max_depth: 16,
max_params: 4096,
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_nesting(&mut self, nesting: Nesting) {
self.nesting = nesting;
}
pub const fn set_max_depth(&mut self, depth: usize) {
self.max_depth = depth;
}
pub const fn set_max_params(&mut self, max: usize) {
self.max_params = max;
}
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 nesting(mut self, nesting: Nesting) -> DeserializerConfigBuilder {
self.value.set_nesting(nesting);
self
}
pub const fn max_depth(mut self, depth: usize) -> DeserializerConfigBuilder {
self.value.set_max_depth(depth);
self
}
pub const fn max_params(mut self, max: usize) -> DeserializerConfigBuilder {
self.value.set_max_params(max);
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 str,
error: Option<Error>,
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,
error: 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> {
match std::str::from_utf8(input) {
Ok(input) => Deserializer::from_str_with_config(input, config),
Err(err) => Deserializer {
input: "",
error: Some(Error::with_offset(
ErrorKind::Syntax,
"input is not valid UTF-8",
err.valid_up_to(),
)),
config,
},
}
}
pub fn config(&self) -> &DeserializerConfig {
&self.config
}
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.config.context.is_empty() {
driver.set_default_context(self.config.context.clone());
}
if let Some(err) = self.error.take() {
return Err(err);
}
let tree = Tree::parse(self.input, &self.config)?;
let state = driver.state_mut();
if TrackLocations::of(state) {
Source(self.input.into()).set(state);
}
DuplicateKeys::Last.set_default(state);
LexicalRules::LENIENT.set_default(state);
tree.emit(driver).map_err(|mut err| {
err.resolve_position(self.input.as_bytes());
err
})
}
}
impl<'a> de::Deserializer<'a> for Deserializer<'a> {
fn drive(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
Deserializer::drive(self, driver)
}
}
type Range = (usize, usize);
enum NodeKey<'a> {
Root,
Name(Cow<'a, str>),
Index(usize, Cow<'a, str>),
Push,
}
struct Node<'a> {
key: NodeKey<'a>,
key_range: Range,
values: Vec<(Decoded<'a>, Range)>,
children: Vec<usize>,
}
enum Container {
Map(Vec<usize>),
Seq(Vec<usize>),
}
#[derive(PartialEq, Eq, Hash)]
enum ChildId<'a> {
Name(Cow<'a, str>),
Index(usize),
}
#[derive(Clone, Copy)]
pub(crate) enum Segment {
Name(usize, usize),
Index(usize, usize, usize),
Push,
}
struct Tree<'a> {
nodes: Vec<Node<'a>>,
input_len: usize,
}
impl<'a> Tree<'a> {
fn parse(input: &'a str, config: &DeserializerConfig) -> Result<Tree<'a>, Error> {
let mut tree = Tree {
nodes: vec![Node {
key: NodeKey::Root,
key_range: (0, input.len()),
values: Vec::new(),
children: Vec::new(),
}],
input_len: input.len(),
};
let mut lookup = HashMap::new();
let mut segments = Vec::new();
let mut params = 0;
let mut start = usize::from(input.starts_with('?'));
while start <= input.len() {
let end = input[start..]
.find('&')
.map_or(input.len(), |pos| start + pos);
let pair = &input[start..end];
let pair_start = start;
start = end + 1;
if pair.is_empty() {
continue;
}
params += 1;
if params > config.max_params {
return Err(Error::with_offset(
ErrorKind::LimitExceeded,
"too many parameters",
pair_start,
));
}
let (raw_key, raw_value, value_start) = match pair.find('=') {
Some(pos) => (&pair[..pos], &pair[pos + 1..], pair_start + pos + 1),
None => (pair, "", end),
};
let key_range = (pair_start, pair_start + raw_key.len());
let key = match decode(raw_key) {
Decoded::Text(key) => key,
Decoded::Bytes(_) => {
return Err(Error::with_offset(
ErrorKind::Syntax,
"key is not valid UTF-8",
key_range.0,
));
}
};
let value = decode(raw_value);
segments.clear();
let first = split_key(&key, config.nesting, &mut segments);
if segments.len() > config.max_depth {
return Err(Error::with_offset(
ErrorKind::LimitExceeded,
"key is nested too deeply",
key_range.0,
));
}
let mut node = tree.child(&mut lookup, 0, Segment::Name(0, first), &key, key_range);
for segment in segments.iter().copied() {
node = tree.child(&mut lookup, node, segment, &key, key_range);
}
tree.nodes[node].values.push((value, (value_start, end)));
}
Ok(tree)
}
#[allow(clippy::ptr_arg)]
fn child(
&mut self,
lookup: &mut HashMap<(usize, ChildId<'a>), usize>,
parent: usize,
segment: Segment,
key: &Cow<'a, str>,
key_range: Range,
) -> usize {
let (id, node_key) = match segment {
Segment::Name(start, end) => {
let name = sub_cow(key, start, end);
(Some(ChildId::Name(name.clone())), NodeKey::Name(name))
}
Segment::Index(index, start, end) => (
Some(ChildId::Index(index)),
NodeKey::Index(index, sub_cow(key, start, end)),
),
Segment::Push => (None, NodeKey::Push),
};
let id = id.map(|id| (parent, id));
if let Some(ref id) = id
&& let Some(&child) = lookup.get(id)
{
return child;
}
let child = self.nodes.len();
self.nodes.push(Node {
key: node_key,
key_range,
values: Vec::new(),
children: Vec::new(),
});
self.nodes[parent].children.push(child);
if let Some(id) = id {
lookup.insert(id, child);
}
child
}
fn map_shape(&self, children: &[usize]) -> ContainerShape {
let len = children
.iter()
.map(|&child| self.nodes[child].values.len().max(1))
.sum();
{
let mut shape = ContainerShape::with_len(len);
shape.set_multimap(true);
shape
}
}
fn container(&self, node: &Node<'a>) -> Result<Container, Error> {
let (mut names, mut indexes, mut pushes) = (false, false, false);
for &child in &node.children {
match self.nodes[child].key {
NodeKey::Name(_) | NodeKey::Root => names = true,
NodeKey::Index(..) => indexes = true,
NodeKey::Push => pushes = true,
}
}
if pushes && (names || indexes) {
return Err(Error::with_offset(
ErrorKind::Syntax,
"`[]` cannot be combined with other nested keys",
node.key_range.0,
));
}
if pushes {
return Ok(Container::Seq(node.children.clone()));
}
if indexes && !names {
let mut sorted = node.children.clone();
sorted.sort_by_key(|&child| match self.nodes[child].key {
NodeKey::Index(index, _) => index,
_ => unreachable!(),
});
let dense = sorted.iter().enumerate().all(|(pos, &child)| {
matches!(self.nodes[child].key, NodeKey::Index(index, _) if index == pos)
});
if dense {
return Ok(Container::Seq(sorted));
}
}
Ok(Container::Map(node.children.clone()))
}
fn emit(&self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
struct Frame {
children: Vec<usize>,
pos: usize,
is_map: bool,
range: Range,
}
let root = &self.nodes[0];
let end = (self.input_len, self.input_len);
emit_at(
driver,
Event::MapStart(self.map_shape(&root.children)),
root.key_range,
)?;
let mut stack = vec![Frame {
children: root.children.clone(),
pos: 0,
is_map: true,
range: end,
}];
while let Some(frame) = stack.last_mut() {
let Some(&child) = frame.children.get(frame.pos) else {
let event = if frame.is_map {
Event::MapEnd
} else {
Event::SeqEnd
};
let range = frame.range;
stack.pop();
emit_at(driver, event, range)?;
continue;
};
frame.pos += 1;
let is_map = frame.is_map;
let node = &self.nodes[child];
if is_map {
driver
.state_mut()
.set_input_range(node.key_range.0, node.key_range.1);
match node.key {
NodeKey::Name(ref name) | NodeKey::Index(_, ref name) => {
emit_lexical(driver, name)?
}
NodeKey::Root | NodeKey::Push => unreachable!(),
}
}
match (&node.values[..], node.children.is_empty()) {
([(value, range)], true) => emit_value(driver, value, *range)?,
([(first, first_range), rest @ ..], true) if is_map => {
emit_value(driver, first, *first_range)?;
for (value, range) in rest {
driver
.state_mut()
.set_input_range(node.key_range.0, node.key_range.1);
match node.key {
NodeKey::Name(ref name) | NodeKey::Index(_, ref name) => {
emit_lexical(driver, name)?
}
NodeKey::Root | NodeKey::Push => unreachable!(),
}
emit_value(driver, value, *range)?;
}
}
([], true) => unreachable!(),
(values @ [_, _, ..], true) => {
let policy = DuplicateKeys::of(driver.state());
let (value, range) = match policy {
DuplicateKeys::First => &values[0],
DuplicateKeys::Error => {
return Err(Error::with_offset(
ErrorKind::Syntax,
"index given more than once",
values[1].1.0,
));
}
_ => &values[values.len() - 1],
};
emit_value(driver, value, *range)?;
}
([], false) => {
let (children, is_map) = match self.container(node)? {
Container::Map(children) => (children, true),
Container::Seq(children) => (children, false),
};
let event = if is_map {
Event::MapStart(self.map_shape(&children))
} else {
Event::SeqStart(ContainerShape::with_len(children.len()))
};
emit_at(driver, event, node.key_range)?;
stack.push(Frame {
children,
pos: 0,
is_map,
range: node.key_range,
});
}
(_, false) => {
return Err(Error::with_offset(
ErrorKind::Syntax,
"key has a value and nested keys",
node.key_range.0,
));
}
}
}
Ok(())
}
}
#[inline]
fn emit_at<'e, E: Into<Event<'e>>>(
driver: &mut DeserializeDriver<'_, '_>,
event: E,
range: Range,
) -> Result<(), Error> {
driver.state_mut().set_input_range(range.0, range.1);
driver.emit(event)
}
#[allow(clippy::ptr_arg)]
#[inline]
fn emit_lexical<'a>(
driver: &mut DeserializeDriver<'_, 'a>,
text: &Cow<'a, str>,
) -> Result<(), Error> {
match *text {
Cow::Borrowed(text) => driver.emit_borrowed(Atom::Lexical(Text::borrowed(text))),
Cow::Owned(ref text) => driver.emit(Atom::Lexical(Text::borrowed(text.as_str()))),
}
}
fn emit_value<'a>(
driver: &mut DeserializeDriver<'_, 'a>,
value: &Decoded<'a>,
range: Range,
) -> Result<(), Error> {
driver.state_mut().set_input_range(range.0, range.1);
match *value {
Decoded::Text(ref text) => emit_lexical(driver, text),
Decoded::Bytes(ref bytes) => driver.emit(Atom::Bytes(Bytes::borrowed(bytes))),
}
}
fn sub_cow<'a>(key: &Cow<'a, str>, start: usize, end: usize) -> Cow<'a, str> {
match *key {
Cow::Borrowed(key) => Cow::Borrowed(&key[start..end]),
Cow::Owned(ref key) => Cow::Owned(key[start..end].to_string()),
}
}
pub(crate) fn split_key(key: &str, nesting: Nesting, segments: &mut Vec<Segment>) -> usize {
let bytes = key.as_bytes();
let (open, first_end) = match nesting {
Nesting::Flat => return key.len(),
Nesting::Brackets => (b'[', bytes.iter().position(|&b| b == b'[')),
Nesting::Dots => (b'.', bytes.iter().position(|&b| b == b'.')),
};
let first_end = match first_end {
Some(0) | None => return key.len(),
Some(end) => end,
};
let mut pos = first_end;
while pos < bytes.len() {
debug_assert_eq!(bytes[pos], open);
let (start, end, next) = if open == b'[' {
let close = match bytes[pos + 1..].iter().position(|&b| b == b']') {
Some(close) => pos + 1 + close,
None => break,
};
(pos + 1, close, close + 1)
} else {
let end = bytes[pos + 1..]
.iter()
.position(|&b| b == b'.')
.map_or(bytes.len(), |end| pos + 1 + end);
(pos + 1, end, end)
};
let text = &key[start..end];
let valid_next = next == bytes.len() || bytes[next] == open;
if !valid_next || (open == b'[' && text.contains('[')) || (open == b'.' && text.is_empty())
{
break;
}
segments.push(if text.is_empty() {
Segment::Push
} else if text.bytes().all(|b| b.is_ascii_digit()) {
match text.parse() {
Ok(index) => Segment::Index(index, start, end),
Err(_) => Segment::Name(start, end),
}
} else {
Segment::Name(start, end)
});
pos = next;
}
if pos < bytes.len() {
segments.clear();
return key.len();
}
first_end
}
#[cfg(test)]
fn split(key: &str, nesting: Nesting) -> Vec<String> {
let mut segments = Vec::new();
let first = split_key(key, nesting, &mut segments);
let mut rv = vec![key[..first].to_string()];
for segment in segments {
rv.push(match segment {
Segment::Name(start, end) => key[start..end].to_string(),
Segment::Index(index, _, _) => format!("#{}", index),
Segment::Push => "[]".to_string(),
});
}
rv
}
#[test]
fn test_split_key() {
let b = Nesting::Brackets;
assert_eq!(split("a", b), ["a"]);
assert_eq!(split("a[b][0][]", b), ["a", "b", "#0", "[]"]);
assert_eq!(split("a[b.c]", b), ["a", "b.c"]);
assert_eq!(split("a[]", b), ["a", "[]"]);
assert_eq!(split("a[007]", b), ["a", "#7"]);
assert_eq!(
split("a[99999999999999999999999]", b),
["a", "99999999999999999999999"]
);
for key in ["a[b", "[a]", "a[b]c", "a[b[c]]", "a]", "a[b]]"] {
assert_eq!(split(key, b), [key], "{}", key);
}
let d = Nesting::Dots;
assert_eq!(split("a.b.0", d), ["a", "b", "#0"]);
assert_eq!(split("a[b]", d), ["a[b]"]);
for key in ["a.", "a..b", ".a"] {
assert_eq!(split(key, d), [key], "{}", key);
}
assert_eq!(split("a[b].c", Nesting::Flat), ["a[b].c"]);
}