use std::borrow::Cow;
use serde::de::value::StrDeserializer;
use serde::de::{self, DeserializeSeed, IntoDeserializer, Visitor};
use super::scalar::{Sc, ScalarDe};
use super::{Core, Hint};
use crate::construct::build::{Cx, build_from};
use crate::construct::keys::{KeyRepr, KeySet, duplicate_at, key_text, on_duplicate};
use crate::construct::{Node, Pull, Recording};
use crate::error::Error;
pub(crate) struct SeqAccess<'c, 'de, P> {
core: &'c mut Core<'de, P>,
index: usize,
done: bool,
}
impl<'c, 'de, P: Pull<'de>> SeqAccess<'c, 'de, P> {
pub(crate) fn new(core: &'c mut Core<'de, P>) -> Self {
Self {
core,
index: 0,
done: false,
}
}
pub(crate) fn finish(&self) -> (bool, usize) {
(self.done, self.index)
}
}
impl<'de, P: Pull<'de>> de::SeqAccess<'de> for SeqAccess<'_, 'de, P> {
type Error = Error;
fn next_element_seed<T: DeserializeSeed<'de>>(
&mut self,
seed: T,
) -> Result<Option<T::Value>, Error> {
if self.done {
return Ok(None);
}
self.core.check_unpoisoned()?;
if matches!(self.core.src.peek()?.node, Node::SeqEnd) {
self.core.src.next()?;
self.done = true;
return Ok(None);
}
let i = self.index;
self.index = i.saturating_add(1);
seed.deserialize(&mut *self.core)
.map(Some)
.map_err(|e| e.in_index(i))
}
}
enum KeyName<'de> {
Text(Cow<'de, str>),
Complex(String),
}
pub(crate) struct MapAccess<'c, 'de, P> {
core: &'c mut Core<'de, P>,
keys: KeySet<'de>,
key: Option<KeyName<'de>>,
pending: Option<(KeyRepr<'de>, oneyaml_core::Span, bool)>,
value_due: bool,
done: bool,
}
impl<'c, 'de, P: Pull<'de>> MapAccess<'c, 'de, P> {
pub(crate) fn new(core: &'c mut Core<'de, P>) -> Self {
Self {
core,
keys: KeySet::default(),
key: None,
pending: None,
value_due: false,
done: false,
}
}
pub(crate) fn core_unpoisoned(&self) -> bool {
!self.core.is_poisoned()
}
pub(crate) fn finish_rest(&mut self) -> Result<(), Error> {
if self.done {
return Ok(());
}
if self.value_due {
self.value_due = false;
let text = self.key_text().to_owned();
self.core.skip_node().map_err(|e| e.in_key(&text))?;
}
self.duplicate()?;
self.done = true;
self.core.finish_mapping(&mut self.keys).map(|_| ())
}
fn key_text(&self) -> &str {
match &self.key {
Some(KeyName::Text(t)) => t.as_ref(),
Some(KeyName::Complex(t)) => t.as_str(),
None => "",
}
}
fn refuse_duplicate(&mut self) -> Result<(), Error> {
let Some((repr, span, _)) = &self.pending else {
return Ok(());
};
let Some(first) = self.keys.first(repr) else {
return Ok(());
};
let text = match &self.key {
Some(KeyName::Text(t)) => t.as_ref(),
Some(KeyName::Complex(t)) => t.as_str(),
None => "",
};
let Err(dup) = on_duplicate(self.core.policy, text, first, *span) else {
return Ok(());
};
let text = text.to_owned();
self.value_due = false;
self.pending = None;
self.core.skip_node().map_err(|e| e.in_key(&text))?;
Err(dup)
}
fn duplicate(&mut self) -> Result<(), Error> {
let Some((repr, span, replayed)) = self.pending.take() else {
return Ok(());
};
let text = match &self.key {
Some(KeyName::Text(t)) => t.as_ref(),
Some(KeyName::Complex(t)) => t.as_str(),
None => "",
};
if let Some(first) = self.keys.insert(repr, span) {
let policy = self.core.policy;
duplicate_at(
&mut self.core.warnings,
policy,
replayed,
|| text.to_owned(),
first,
span,
)?;
}
Ok(())
}
}
impl<'de, P: Pull<'de>> de::MapAccess<'de> for MapAccess<'_, 'de, P> {
type Error = Error;
fn next_key_seed<K: DeserializeSeed<'de>>(
&mut self,
seed: K,
) -> Result<Option<K::Value>, Error> {
if self.done {
return Ok(None);
}
self.core.check_unpoisoned()?;
let span = self.core.src.peek()?.span;
let depth = self.core.src.open;
let result = self.settle().and_then(|()| self.next_key_unchecked(seed));
if let Err(e) = &result {
self.core.after_error(e, span, depth);
}
result
}
fn next_value_seed<V: DeserializeSeed<'de>>(&mut self, seed: V) -> Result<V::Value, Error> {
self.core.check_unpoisoned()?;
let span = self.core.src.peek()?.span;
let depth = self.core.src.open;
let result = self.next_value_unchecked(seed);
if let Err(e) = &result {
self.core.after_error(e, span, depth);
}
result
}
}
impl<'de, P: Pull<'de>> MapAccess<'_, 'de, P> {
fn settle(&mut self) -> Result<(), Error> {
if self.value_due {
self.value_due = false;
let text = self.key_text().to_owned();
self.core.skip_node().map_err(|e| e.in_key(&text))?;
}
self.duplicate()
}
fn next_key_unchecked<K: DeserializeSeed<'de>>(
&mut self,
seed: K,
) -> Result<Option<K::Value>, Error> {
let ev = self.core.src.next()?;
let (span, replayed) = (ev.span, ev.replayed);
if !matches!(ev.node, Node::MapEnd) {
self.value_due = true;
}
match ev.node {
Node::MapEnd => {
self.done = true;
Ok(None)
}
Node::Scalar { value, plain, tag } => {
let sc = self.core.with_memo(
Sc::classify(&self.core.resolver, tag, plain, value, span)?
.typed(self.core.typed_depth, self.core.max_typed_depth),
);
let repr = scalar_key(&sc);
self.pending = Some((repr, span, replayed));
self.key = Some(KeyName::Text(sc.value.clone()));
self.refuse_duplicate()?;
seed.deserialize(ScalarDe(sc))
.map(Some)
.map_err(|e| e.at(span))
}
Node::SeqStart { .. } | Node::MapStart { .. } => {
let planned = self.core.src.last_planned;
let (key, events) = {
let mut rec = Recording::new(&mut self.core.src, &ev);
let mut cx = Cx {
resolver: self.core.resolver,
policy: self.core.policy,
warnings: &mut self.core.warnings,
};
let key = build_from(&mut rec, &mut cx, ev)?;
(key, rec.into_events())
};
let text = key_text(&key);
self.pending = Some((KeyRepr::of_value(key), span, replayed));
self.key = Some(KeyName::Complex(text));
self.refuse_duplicate()?;
self.core.src.push_front_all(events, planned);
seed.deserialize(&mut *self.core)
.map(Some)
.map_err(|e| e.at(span))
}
_ => Err(Error::internal("mapping key expected", Some(span))),
}
}
fn next_value_unchecked<V: DeserializeSeed<'de>>(
&mut self,
seed: V,
) -> Result<V::Value, Error> {
self.value_due = false;
let value = seed
.deserialize(&mut *self.core)
.map_err(|e| match &self.key {
Some(KeyName::Text(t)) => e.in_key(t),
Some(KeyName::Complex(t)) => e.in_key(t),
None => e,
})?;
self.duplicate()?;
Ok(value)
}
}
pub(crate) fn scalar_key<'de>(sc: &Sc<'de>) -> KeyRepr<'de> {
match sc.kind {
super::scalar::Kind::Str => KeyRepr::Str(sc.value.clone()),
_ => KeyRepr::of_value(sc.to_value()),
}
}
#[derive(Default)]
pub(crate) struct EnumState<'de> {
pub(crate) key: Option<(KeyRepr<'de>, oneyaml_core::Span)>,
pub(crate) refused: bool,
pub(crate) content_due: Option<String>,
}
pub(crate) struct MapEnum<'c, 'de, P> {
core: &'c mut Core<'de, P>,
state: &'c mut EnumState<'de>,
}
impl<'c, 'de, P: Pull<'de>> MapEnum<'c, 'de, P> {
pub(crate) fn new(core: &'c mut Core<'de, P>, state: &'c mut EnumState<'de>) -> Self {
Self { core, state }
}
}
impl<'c, 'de, P: Pull<'de>> de::EnumAccess<'de> for MapEnum<'c, 'de, P> {
type Error = Error;
type Variant = Variant<'c, 'de, P>;
fn variant_seed<S: DeserializeSeed<'de>>(
self,
seed: S,
) -> Result<(S::Value, Self::Variant), Error> {
let ev = self.core.src.next()?;
let span = ev.span;
match ev.node {
Node::Scalar { value, plain, tag } => {
let sc = match Sc::classify(&self.core.resolver, tag, plain, value, span) {
Ok(sc) => sc,
Err(e) => {
let depth = self.core.src.open;
self.core.after_error(&e, span, depth);
return Err(e);
}
};
let sc = self
.core
.with_memo(sc.typed(self.core.typed_depth, self.core.max_typed_depth));
let name: Cow<'de, str> = sc.value.clone();
self.state.key = Some((scalar_key(&sc), span));
self.state.content_due = Some(name.clone().into_owned());
let variant = match seed.deserialize(ScalarDe(sc)) {
Ok(v) => v,
Err(e) => {
self.state.refused = true;
return Err(e.at(span));
}
};
Ok((
variant,
Variant {
core: self.core,
name: Cow::Owned(name.into_owned()),
due: Some(&mut self.state.content_due),
},
))
}
Node::MapEnd => Err(de::Error::invalid_length(
0,
&"a mapping with a single key (the variant)",
)),
_ => {
self.core.src.push_front(ev);
self.state.refused = true;
Err(de::Error::invalid_type(
de::Unexpected::Other("a collection as variant name"),
&"a variant name",
))
}
}
}
}
pub(crate) struct TaggedCollection<'c, 'de, P> {
core: &'c mut Core<'de, P>,
name: Cow<'static, str>,
}
impl<'c, 'de, P: Pull<'de>> TaggedCollection<'c, 'de, P> {
pub(crate) fn new(core: &'c mut Core<'de, P>, name: Cow<'static, str>) -> Self {
Self { core, name }
}
}
impl<'c, 'de, P: Pull<'de>> de::EnumAccess<'de> for TaggedCollection<'c, 'de, P> {
type Error = Error;
type Variant = Variant<'c, 'de, P>;
fn variant_seed<S: DeserializeSeed<'de>>(
self,
seed: S,
) -> Result<(S::Value, Self::Variant), Error> {
let de: StrDeserializer<'_, Error> = (&*self.name).into_deserializer();
let variant = seed.deserialize(de)?;
Ok((
variant,
Variant {
core: self.core,
name: self.name,
due: None,
},
))
}
}
pub(crate) struct Variant<'c, 'de, P> {
core: &'c mut Core<'de, P>,
name: Cow<'static, str>,
due: Option<&'c mut Option<String>>,
}
impl<P> Variant<'_, '_, P> {
fn reading(&mut self) {
if let Some(due) = self.due.as_deref_mut() {
*due = None;
}
}
}
impl<'de, P: Pull<'de>> de::VariantAccess<'de> for Variant<'_, 'de, P> {
type Error = Error;
fn unit_variant(mut self) -> Result<(), Error> {
self.reading();
let name = self.name;
de::Deserialize::deserialize(&mut *self.core).map_err(|e: Error| e.in_key(&name))
}
fn newtype_variant_seed<T: DeserializeSeed<'de>>(mut self, seed: T) -> Result<T::Value, Error> {
self.reading();
let name = self.name;
seed.deserialize(&mut *self.core)
.map_err(|e| e.in_key(&name))
}
fn tuple_variant<V: Visitor<'de>>(mut self, _len: usize, v: V) -> Result<V::Value, Error> {
self.reading();
let name = self.name;
self.core.node(Hint::Seq, v).map_err(|e| e.in_key(&name))
}
fn struct_variant<V: Visitor<'de>>(
mut self,
_fields: &'static [&'static str],
v: V,
) -> Result<V::Value, Error> {
self.reading();
let name = self.name;
self.core.node(Hint::Map, v).map_err(|e| e.in_key(&name))
}
}