use std::collections::VecDeque;
use std::num::NonZeroU32;
use oneyaml_core::{DuplicateKeys, Settings};
use crate::construct::{Ev, Node, Pull};
use crate::error::Error;
use crate::resolve::Resolver;
mod access;
mod api;
mod core;
mod plan;
pub(crate) mod scalar;
mod value;
pub(crate) use api::read_discarding;
pub use api::{
Deserializer, from_reader, from_reader_with, from_slice, from_slice_with, from_str,
from_str_with, from_str_with_diagnostics,
};
pub(crate) use plan::check_unexpanded;
pub use value::{from_value, from_value_with};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum Hint {
Any,
Ignored,
Bool,
Int(scalar::IntTy),
Float,
Str,
Option,
Unit,
Newtype,
Seq,
Map,
Enum(&'static [&'static str]),
}
pub(crate) struct Src<'de, P> {
p: P,
queue: VecDeque<(Ev<'de>, bool, Option<NonZeroU32>)>,
last_end: usize,
last_planned: bool,
last_prepaid: Option<NonZeroU32>,
open: usize,
reads: usize,
poisoned: Option<oneyaml_core::Span>,
}
fn nesting(ev: &Ev<'_>) -> isize {
match ev.node {
Node::SeqStart { .. } | Node::MapStart { .. } => 1,
Node::SeqEnd | Node::MapEnd => -1,
_ => 0,
}
}
impl<P> Src<'_, P> {
fn count(&mut self, ev: &Ev<'_>, by: isize) {
self.open = self
.open
.saturating_add_signed(nesting(ev).saturating_mul(by));
self.reads = if by > 0 {
self.reads.wrapping_add(1)
} else {
self.reads.wrapping_sub(1)
};
}
}
impl<P> Src<'_, P> {
fn check_unpoisoned(&self) -> Result<(), Error> {
match self.poisoned {
None => Ok(()),
Some(span) => Err(read_after_ignored_error(Some(span))),
}
}
fn poison(&mut self, span: oneyaml_core::Span) {
self.poisoned.get_or_insert(span);
}
fn failed(&mut self, e: Error) -> Error {
self.poison(e.diagnostic().primary.span);
e
}
}
impl<'de, P: Pull<'de>> Pull<'de> for Src<'de, P> {
fn next(&mut self) -> Result<Ev<'de>, Error> {
self.check_unpoisoned()?;
let (ev, planned, prepaid) = match self.queue.pop_front() {
Some(queued) => queued,
None => match self.p.next() {
Ok(ev) => (ev, false, None),
Err(e) => return Err(self.failed(e)),
},
};
self.count(&ev, 1);
self.last_end = ev.span.end;
self.last_planned = planned;
self.last_prepaid = prepaid;
Ok(ev)
}
fn peek(&mut self) -> Result<&Ev<'de>, Error> {
self.check_unpoisoned()?;
if self.queue.is_empty() {
if let Err(e) = self.p.peek() {
return Err(self.failed(e));
}
}
match self.queue.front() {
Some((ev, _, _)) => Ok(ev),
None => self.p.peek(),
}
}
fn last_end(&self) -> usize {
self.last_end
}
fn peeked_delivered_replay(&self) -> bool {
self.queue.is_empty() && self.p.peeked_delivered_replay()
}
}
impl<'de, P> Src<'de, P> {
fn push_front(&mut self, ev: Ev<'de>) {
self.count(&ev, -1);
self.queue.push_front((ev, self.last_planned, None));
}
fn push_front_prepaid(&mut self, ev: Ev<'de>, level: usize) {
let level = level_of(level);
self.count(&ev, -1);
self.queue.push_front((ev, self.last_planned, level));
}
fn end_prepaid(&mut self, level: usize) -> bool {
match self.queue.front_mut() {
Some(front) if front.2.is_some() && front.2 == level_of(level) => {
front.2 = None;
true
}
_ => false,
}
}
fn push_front_all(&mut self, evs: Vec<Ev<'de>>, planned: bool) {
self.queue.reserve(evs.len());
for ev in evs.into_iter().rev() {
self.count(&ev, -1);
self.queue.push_front((ev, planned, None));
}
}
}
pub(crate) fn read_after_ignored_error(span: Option<oneyaml_core::Span>) -> Error {
Error::new(
oneyaml_core::code::READ_AFTER_IGNORED_ERROR,
"the deserializer was used after an error it returned for this \
sequence or mapping was ignored",
span,
)
.with_help(
"a `Deserialize` impl discarded an error for this sequence or mapping \
and read on; propagate the error (`?`) instead",
)
}
pub(crate) fn is_target_error(e: &Error) -> bool {
e.code().range() == oneyaml_core::CodeRange::Serde
}
pub(crate) fn level_of(level: usize) -> Option<NonZeroU32> {
u32::try_from(level).ok().and_then(NonZeroU32::new)
}
pub(crate) struct Core<'de, P> {
src: Src<'de, P>,
resolver: Resolver,
policy: DuplicateKeys,
warnings: crate::diag_cap::Capped,
typed_depth: usize,
max_typed_depth: usize,
max_diagnostics: usize,
scratch: plan::Scratch<'de>,
variants: scalar::SharedMemo,
}
impl<'de, P: Pull<'de>> Core<'de, P> {
pub(crate) const fn max_diagnostics(&self) -> usize {
self.max_diagnostics
}
pub(crate) fn new(p: P, settings: &Settings, shared: scalar::SharedMemo) -> Self {
Self {
src: Src {
p,
queue: VecDeque::new(),
last_end: 0,
last_planned: false,
last_prepaid: None,
open: 0,
reads: 0,
poisoned: None,
},
resolver: Resolver::new(settings),
policy: settings.get_duplicate_keys(),
warnings: crate::diag_cap::Capped::new(settings.get_limits()),
typed_depth: 0,
max_typed_depth: settings.get_limits().get_max_typed_depth(),
max_diagnostics: settings.get_limits().get_max_diagnostics(),
scratch: plan::Scratch::default(),
variants: shared,
}
}
pub(crate) fn check_unpoisoned(&self) -> Result<(), Error> {
self.src.check_unpoisoned()
}
pub(crate) fn is_poisoned(&self) -> bool {
self.src.poisoned.is_some()
}
pub(crate) fn poison(&mut self, span: oneyaml_core::Span) {
self.src.poison(span);
}
fn needs_plan(&self) -> bool {
self.resolver.merge_keys() || self.policy == DuplicateKeys::LastWins
}
}