use serde_core::de::{self, Deserializer, IntoDeserializer};
use serde_core::{Deserialize, Serialize};
use crate::Location;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Spanned<T> {
pub value: T,
pub referenced: Location,
pub defined: Location,
}
impl<T> Spanned<T> {
pub const fn new(value: T, referenced: Location, defined: Location) -> Self {
Self {
value,
referenced,
defined,
}
}
}
impl<'de, T> Deserialize<'de> for Spanned<T>
where
T: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct SpannedVisitor<T>(std::marker::PhantomData<T>);
impl<'de, T> de::Visitor<'de> for SpannedVisitor<T>
where
T: Deserialize<'de>,
{
type Value = Spanned<T>;
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.write_str("a span-aware newtype wrapper")
}
fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_any(ReprOrPlainVisitor::<T>(std::marker::PhantomData))
}
}
struct ReprOrPlainVisitor<T>(std::marker::PhantomData<T>);
impl<'de, T> de::Visitor<'de> for ReprOrPlainVisitor<T>
where
T: Deserialize<'de>,
{
type Value = Spanned<T>;
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.write_str("a value or a span-aware map with value/referenced/defined fields")
}
fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
where
A: de::MapAccess<'de>,
{
enum Field {
Value,
Referenced,
Defined,
Ignore,
}
impl<'de> Deserialize<'de> for Field {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct FieldVisitor;
impl<'a> de::Visitor<'a> for FieldVisitor {
type Value = Field;
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.write_str("a Spanned<T> field")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(match value {
"value" => Field::Value,
"referenced" => Field::Referenced,
"defined" => Field::Defined,
_ => Field::Ignore,
})
}
}
deserializer.deserialize_identifier(FieldVisitor)
}
}
let mut map = map;
let mut value = None;
let mut referenced = None;
let mut defined = None;
while let Some(field) = map.next_key::<Field>()? {
match field {
Field::Value => {
if value.is_some() {
return Err(de::Error::duplicate_field("value"));
}
value = Some(map.next_value()?);
}
Field::Referenced => {
if referenced.is_some() {
return Err(de::Error::duplicate_field("referenced"));
}
referenced = Some(map.next_value()?);
}
Field::Defined => {
if defined.is_some() {
return Err(de::Error::duplicate_field("defined"));
}
defined = Some(map.next_value()?);
}
Field::Ignore => {
let _ = map.next_value::<de::IgnoredAny>()?;
}
}
}
let value = value.ok_or_else(|| de::Error::missing_field("value"))?;
let referenced =
referenced.ok_or_else(|| de::Error::missing_field("referenced"))?;
let defined = defined.ok_or_else(|| de::Error::missing_field("defined"))?;
Ok(Spanned::new(value, referenced, defined))
}
fn visit_bool<E: de::Error>(self, v: bool) -> Result<Self::Value, E> {
T::deserialize(v.into_deserializer())
.map(|val| Spanned::new(val, Location::UNKNOWN, Location::UNKNOWN))
}
fn visit_i8<E: de::Error>(self, v: i8) -> Result<Self::Value, E> {
T::deserialize(v.into_deserializer())
.map(|val| Spanned::new(val, Location::UNKNOWN, Location::UNKNOWN))
}
fn visit_i16<E: de::Error>(self, v: i16) -> Result<Self::Value, E> {
T::deserialize(v.into_deserializer())
.map(|val| Spanned::new(val, Location::UNKNOWN, Location::UNKNOWN))
}
fn visit_i32<E: de::Error>(self, v: i32) -> Result<Self::Value, E> {
T::deserialize(v.into_deserializer())
.map(|val| Spanned::new(val, Location::UNKNOWN, Location::UNKNOWN))
}
fn visit_i64<E: de::Error>(self, v: i64) -> Result<Self::Value, E> {
T::deserialize(v.into_deserializer())
.map(|val| Spanned::new(val, Location::UNKNOWN, Location::UNKNOWN))
}
fn visit_u8<E: de::Error>(self, v: u8) -> Result<Self::Value, E> {
T::deserialize(v.into_deserializer())
.map(|val| Spanned::new(val, Location::UNKNOWN, Location::UNKNOWN))
}
fn visit_u16<E: de::Error>(self, v: u16) -> Result<Self::Value, E> {
T::deserialize(v.into_deserializer())
.map(|val| Spanned::new(val, Location::UNKNOWN, Location::UNKNOWN))
}
fn visit_u32<E: de::Error>(self, v: u32) -> Result<Self::Value, E> {
T::deserialize(v.into_deserializer())
.map(|val| Spanned::new(val, Location::UNKNOWN, Location::UNKNOWN))
}
fn visit_u64<E: de::Error>(self, v: u64) -> Result<Self::Value, E> {
T::deserialize(v.into_deserializer())
.map(|val| Spanned::new(val, Location::UNKNOWN, Location::UNKNOWN))
}
fn visit_f32<E: de::Error>(self, v: f32) -> Result<Self::Value, E> {
T::deserialize(v.into_deserializer())
.map(|val| Spanned::new(val, Location::UNKNOWN, Location::UNKNOWN))
}
fn visit_f64<E: de::Error>(self, v: f64) -> Result<Self::Value, E> {
T::deserialize(v.into_deserializer())
.map(|val| Spanned::new(val, Location::UNKNOWN, Location::UNKNOWN))
}
fn visit_char<E: de::Error>(self, v: char) -> Result<Self::Value, E> {
T::deserialize(v.into_deserializer())
.map(|val| Spanned::new(val, Location::UNKNOWN, Location::UNKNOWN))
}
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
T::deserialize(v.into_deserializer())
.map(|val| Spanned::new(val, Location::UNKNOWN, Location::UNKNOWN))
}
fn visit_string<E: de::Error>(self, v: String) -> Result<Self::Value, E> {
T::deserialize(v.into_deserializer())
.map(|val| Spanned::new(val, Location::UNKNOWN, Location::UNKNOWN))
}
fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
T::deserialize(de::value::BytesDeserializer::new(v))
.map(|val| Spanned::new(val, Location::UNKNOWN, Location::UNKNOWN))
}
fn visit_byte_buf<E: de::Error>(self, v: Vec<u8>) -> Result<Self::Value, E> {
T::deserialize(de::value::BytesDeserializer::new(&v))
.map(|val| Spanned::new(val, Location::UNKNOWN, Location::UNKNOWN))
}
fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
T::deserialize(().into_deserializer())
.map(|val| Spanned::new(val, Location::UNKNOWN, Location::UNKNOWN))
}
fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
T::deserialize(().into_deserializer())
.map(|val| Spanned::new(val, Location::UNKNOWN, Location::UNKNOWN))
}
fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
where
A: de::SeqAccess<'de>,
{
T::deserialize(de::value::SeqAccessDeserializer::new(seq))
.map(|val| Spanned::new(val, Location::UNKNOWN, Location::UNKNOWN))
}
}
deserializer
.deserialize_newtype_struct("__yaml_spanned", SpannedVisitor(std::marker::PhantomData))
}
}
impl<T> Serialize for Spanned<T>
where
T: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde_core::Serializer,
{
self.value.serialize(serializer)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn deserialize_spanned_accepts_named_fields_and_ignores_unknown_fields() {
let spanned: Spanned<u32> = serde_json::from_str(
r#"{
"unknown": true,
"value": 42,
"referenced": { "line": 1, "column": 2 },
"defined": { "line": 3, "column": 4 }
}"#,
)
.unwrap();
assert_eq!(spanned.value, 42);
assert_eq!(spanned.referenced.line(), 1);
assert_eq!(spanned.referenced.column(), 2);
assert_eq!(spanned.defined.line(), 3);
assert_eq!(spanned.defined.column(), 4);
}
#[test]
fn deserialize_spanned_rejects_duplicate_fields() {
let err = serde_json::from_str::<Spanned<u32>>(
r#"{
"value": 1,
"value": 2,
"referenced": { "line": 1, "column": 2 },
"defined": { "line": 3, "column": 4 }
}"#,
)
.unwrap_err();
assert!(err.to_string().contains("duplicate field `value`"));
}
#[test]
fn deserialize_spanned_rejects_missing_fields() {
let err = serde_json::from_str::<Spanned<u32>>(
r#"{
"value": 1,
"referenced": { "line": 1, "column": 2 }
}"#,
)
.unwrap_err();
assert!(err.to_string().contains("missing field `defined`"));
}
}