use std::fmt;
use std::ops::{Deref, DerefMut};
use oneyaml_core::Span;
use serde::de::{self, DeserializeSeed, IntoDeserializer, MapAccess, Visitor};
use crate::error::Error;
const NAME: &str = "$__oneyaml_private_Spanned";
const START: &str = "$__oneyaml_private_start";
const END: &str = "$__oneyaml_private_end";
const VALUE: &str = "$__oneyaml_private_value";
const FIELDS: &[&str] = &[START, END, VALUE];
pub(crate) fn is_spanned(name: &str, fields: &[&str]) -> bool {
name == NAME && fields == FIELDS
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Spanned<T> {
span: Span,
value: T,
}
impl<T> Spanned<T> {
#[must_use]
pub const fn new(span: Span, value: T) -> Self {
Self { span, value }
}
#[must_use]
pub const fn span(&self) -> Span {
self.span
}
#[must_use]
pub const fn get_ref(&self) -> &T {
&self.value
}
pub fn get_mut(&mut self) -> &mut T {
&mut self.value
}
#[must_use]
pub fn into_inner(self) -> T {
self.value
}
}
impl<T> Deref for Spanned<T> {
type Target = T;
fn deref(&self) -> &T {
&self.value
}
}
impl<T> DerefMut for Spanned<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.value
}
}
impl<T: fmt::Debug> fmt::Debug for Spanned<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Spanned({}..{}, ", self.span.start, self.span.end)?;
self.value.fmt(f)?;
f.write_str(")")
}
}
impl<T: serde::Serialize> serde::Serialize for Spanned<T> {
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
self.value.serialize(s)
}
}
impl<'de, T: de::Deserialize<'de>> de::Deserialize<'de> for Spanned<T> {
fn deserialize<D: de::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
d.deserialize_struct(NAME, FIELDS, SpannedVisitor(std::marker::PhantomData))
}
}
struct SpannedVisitor<T>(std::marker::PhantomData<T>);
impl<'de, T: de::Deserialize<'de>> Visitor<'de> for SpannedVisitor<T> {
type Value = Spanned<T>;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("a spanned value (only oneyaml's deserializers provide spans)")
}
fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
let (mut start, mut end, mut value) = (None, None, None);
while let Some(key) = map.next_key::<&str>()? {
match key {
START => start = Some(map.next_value::<usize>()?),
END => end = Some(map.next_value::<usize>()?),
VALUE => value = Some(map.next_value::<T>()?),
other => return Err(de::Error::unknown_field(other, FIELDS)),
}
}
match (start, end, value) {
(Some(start), Some(end), Some(value)) => Ok(Spanned::new(Span::new(start, end), value)),
(None, _, _) => Err(de::Error::missing_field(START)),
(_, None, _) => Err(de::Error::missing_field(END)),
(_, _, None) => Err(de::Error::missing_field(VALUE)),
}
}
}
pub(crate) struct SpannedAccess<D> {
start: usize,
end: usize,
de: Option<D>,
step: u8,
}
impl<D> SpannedAccess<D> {
pub(crate) fn new(start: usize, end: usize, de: D) -> Self {
Self {
start,
end,
de: Some(de),
step: 0,
}
}
}
impl<'de, D: EndAfter<'de>> MapAccess<'de> for SpannedAccess<D> {
type Error = Error;
fn next_key_seed<K: DeserializeSeed<'de>>(
&mut self,
seed: K,
) -> Result<Option<K::Value>, Error> {
let key = match self.step {
0 => START,
1 => VALUE,
2 => END,
_ => return Ok(None),
};
seed.deserialize(de::value::BorrowedStrDeserializer::new(key))
.map(Some)
}
fn next_value_seed<V: DeserializeSeed<'de>>(&mut self, seed: V) -> Result<V::Value, Error> {
let step = self.step;
self.step = step.saturating_add(1);
match step {
0 => seed.deserialize(self.start.into_deserializer()),
1 => match self.de.take() {
Some(d) => {
let (value, end) = d.value_and_end(seed)?;
if let Some(end) = end {
self.end = end;
}
Ok(value)
}
None => Err(Error::internal("spanned value read twice", None)),
},
_ => seed.deserialize(self.end.into_deserializer()),
}
}
}
pub(crate) trait EndAfter<'de>: de::Deserializer<'de, Error = Error> {
fn value_and_end<S: DeserializeSeed<'de>>(
self,
seed: S,
) -> Result<(S::Value, Option<usize>), Error>;
}
impl<'de> EndAfter<'de> for crate::de::scalar::ScalarDe<'de> {
fn value_and_end<S: DeserializeSeed<'de>>(
self,
seed: S,
) -> Result<(S::Value, Option<usize>), Error> {
seed.deserialize(self).map(|v| (v, None))
}
}