use alloc::vec::Vec;
use core::any::TypeId;
use core::fmt;
use crate::Context;
use crate::arena::{Arena, Buffer};
use crate::de::CollectErrors;
use crate::error::{Error, ErrorContext};
use crate::event::ContainerShape;
use crate::ext::{RawFormatId, RawFormatInfo};
use crate::extensions::{EventData, Extensions};
pub(crate) const NO_RANGE: (usize, usize) = (usize::MAX, 0);
pub struct State {
extensions: Extensions,
context: Context,
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,
pub(crate) raw_format: Option<&'static RawFormatId>,
pub(crate) raw_requested: Option<&'static RawFormatInfo>,
}
type AddContextFn = fn(&mut Error, &State);
impl State {
#[allow(clippy::new_without_default)]
pub fn new() -> State {
State {
extensions: Extensions::default(),
context: Context::new(),
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(),
raw_format: None,
raw_requested: None,
}
}
pub fn set_collect_errors(&mut self, yes: bool) {
self.collect_errors = yes;
}
pub fn collect_errors(&self) -> bool {
self.collect_errors
}
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);
}
#[inline(always)]
pub fn declare_raw_format(
&mut self,
format: &'static RawFormatId,
) -> Option<&'static RawFormatInfo> {
self.raw_format = Some(format);
self.raw_requested
.take()
.filter(|requested| core::ptr::eq(requested.id(), format))
}
#[inline]
pub fn take_raw_request(&mut self) -> Option<&'static RawFormatInfo> {
self.raw_requested.take()
}
#[doc(hidden)]
#[inline]
pub fn __private_request_raw(&mut self, format: &'static RawFormatInfo) -> Result<(), Error> {
match self.raw_format {
Some(own) if core::ptr::eq(own, format.id()) => {
self.raw_requested = Some(format);
Err(Error::raw_request())
}
_ => Ok(()),
}
}
#[inline]
pub(crate) fn accepts_raw(&self, format: &'static RawFormatInfo) -> bool {
self.raw_format
.is_some_and(|own| core::ptr::eq(own, format.id()))
}
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> {
match self.extensions.get() {
Some(value) => Some(value),
None => self.context.get(),
}
}
pub fn set_default<T: Default + fmt::Debug + Send + Sync + 'static>(&mut self, value: T) {
if self.get::<T>().is_none() {
*self.get_mut::<T>() = value;
}
}
#[inline]
pub fn context(&self) -> &Context {
&self.context
}
pub fn set_context(&mut self, context: Context) {
if let Some(collect) = context.get::<CollectErrors>() {
self.collect_errors = true;
self.remaining_errors = collect.max.unwrap_or(usize::MAX);
self.error_limit_reached = false;
}
self.context = context;
}
#[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));
}
}
#[inline]
pub fn attach_error_context(&self, err: &mut Error) {
self.attach_error_context_impl(err)
}
#[inline]
pub(crate) fn error_in_context(&self, mut err: Error) -> Error {
self.attach_error_context_impl(&mut err);
err
}
#[cold]
#[inline(never)]
fn attach_error_context_impl(&self, err: &mut Error) {
if err.has_context() {
return;
}
err.set_has_context();
if err.offset().is_none()
&& let Some(range) = self.input_range()
{
err.set_offset(range.start);
}
for (_, f) in self.error_context.iter() {
f(err, self);
}
}
}
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()
}
}