use alloc::vec::Vec;
use core::any::TypeId;
use core::fmt;
use crate::de::arena::{Arena, Buffer};
use crate::error::{Error, ErrorContext};
use crate::event::ContainerShape;
use crate::extensions::{EventData, Extensions};
pub(crate) const NO_RANGE: (usize, usize) = (usize::MAX, 0);
pub struct State {
extensions: Extensions,
pub(crate) depth: usize,
pub(crate) container_shape: ContainerShape,
pub(crate) is_map_key: bool,
pub(crate) is_multimap: bool,
pub(crate) content_key: &'static str,
pub(crate) input_range: (usize, usize),
error_context: Vec<(TypeId, AddContextFn)>,
pub(crate) discards_errors: bool,
collect_errors: bool,
remaining_errors: usize,
error_limit_reached: bool,
pub(crate) arena: Arena,
}
type AddContextFn = fn(Error, &State) -> Error;
impl State {
#[allow(clippy::new_without_default)]
pub fn new() -> State {
State {
extensions: Extensions::default(),
depth: 0,
container_shape: ContainerShape::new(),
is_map_key: false,
is_multimap: false,
content_key: "",
input_range: NO_RANGE,
error_context: Vec::new(),
discards_errors: false,
collect_errors: false,
remaining_errors: usize::MAX,
error_limit_reached: false,
arena: Arena::new(),
}
}
pub fn set_collect_errors(&mut self, yes: bool) -> bool {
core::mem::replace(&mut self.collect_errors, yes)
}
pub fn collects_errors(&self) -> bool {
self.collect_errors && !self.discards_errors
}
pub fn set_max_errors(&mut self, max: usize) {
self.remaining_errors = max;
self.error_limit_reached = false;
}
pub fn error_limit_reached(&self) -> bool {
self.error_limit_reached
}
pub(crate) fn take_error_slots(&mut self, count: usize) -> bool {
if !self.collects_errors() {
false
} else if self.remaining_errors >= count {
self.remaining_errors -= count;
true
} else {
self.error_limit_reached = true;
false
}
}
pub fn discards_errors(&self) -> bool {
self.discards_errors
}
pub(crate) fn discard_errors<R>(&mut self, f: impl FnOnce(&mut State) -> R) -> R {
let outer = core::mem::replace(&mut self.discards_errors, true);
let rv = f(self);
self.discards_errors = outer;
rv
}
#[doc(hidden)]
#[inline]
pub fn __private_take_scratch(&mut self) -> Vec<u8> {
self.arena.take_vec(Buffer::Scratch).unwrap_or_default()
}
#[doc(hidden)]
#[inline]
pub fn __private_put_scratch(&mut self, buffer: Vec<u8>) {
self.arena.put_vec(Buffer::Scratch, buffer);
}
pub(crate) fn take(&mut self) -> State {
core::mem::replace(self, State::new())
}
#[inline]
pub(crate) fn extensions(&self) -> &Extensions {
&self.extensions
}
#[inline]
pub(crate) fn extensions_mut(&mut self) -> &mut Extensions {
&mut self.extensions
}
#[inline]
pub fn get<T: fmt::Debug + Send + Sync + 'static>(&self) -> Option<&T> {
self.extensions.get()
}
#[inline]
pub fn get_mut<T: Default + fmt::Debug + Send + Sync + 'static>(&mut self) -> &mut T {
self.extensions.get_mut()
}
pub fn set_replayable<T: Clone + Default + fmt::Debug + Send + Sync + 'static>(&mut self) {
self.extensions.set_replayable::<T>();
}
#[inline(always)]
pub fn event<T: fmt::Debug + Send + Sync + 'static>(&self) -> Option<&T> {
self.extensions.event()
}
#[inline]
pub fn event_mut<T: Default + Clone + fmt::Debug + Send + Sync + 'static>(&mut self) -> &mut T {
self.extensions.event_mut()
}
pub fn take_event<T: Default + fmt::Debug + Send + Sync + 'static>(&mut self) -> Option<T> {
self.extensions.take_event()
}
pub fn capture_event_data(&self) -> EventData {
self.extensions.capture_event_data()
}
pub fn attach_event_data(&mut self, data: &EventData) {
self.extensions.attach_event_data(data);
}
#[inline(always)]
pub(crate) fn clear_event_data(&mut self) {
self.extensions.clear_event_data();
}
pub fn depth(&self) -> usize {
self.depth
}
pub fn container_shape(&self) -> ContainerShape {
self.container_shape
}
pub fn is_map_key(&self) -> bool {
self.is_map_key
}
#[inline]
pub fn is_multimap(&self) -> bool {
self.is_multimap
}
#[inline]
pub fn input_range(&self) -> Option<core::ops::Range<usize>> {
let (start, end) = self.input_range;
if start == NO_RANGE.0 {
None
} else {
Some(start..end)
}
}
#[inline(always)]
pub fn set_input_range(&mut self, start: usize, end: usize) {
self.input_range = (start, end);
}
#[inline(always)]
pub(crate) fn clear_event(&mut self) {
self.input_range.0 = NO_RANGE.0;
self.extensions.clear_event_data();
}
pub fn add_error_context<T: ErrorContext>(&mut self) {
let key = TypeId::of::<T>();
if !self.error_context.iter().any(|&(other, _)| other == key) {
self.error_context.push((key, T::add_context));
}
}
#[cold]
#[inline(never)]
pub fn attach_error_context(&self, mut err: Error) -> Error {
if err.has_context() {
return err;
}
err.set_has_context();
if err.offset().is_none()
&& let Some(range) = self.input_range()
{
err = err.with_offset(range.start);
}
for (_, f) in self.error_context.iter() {
err = f(err, self);
}
err
}
}
const _: () = {
const fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<State>();
};
impl fmt::Debug for State {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("State")
.field("extensions", &self.extensions)
.field("depth", &self.depth)
.field("is_map_key", &self.is_map_key)
.field("is_multimap", &self.is_multimap)
.field("input_range", &self.input_range())
.finish()
}
}