use serde::de::{self, Deserialize, Deserializer, Visitor};
use std::fmt;
use std::marker::PhantomData;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FlowSeq<T>(pub T);
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FlowMap<T>(pub T);
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SpaceAfter<T>(pub T);
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Commented<T>(pub T, pub String);
impl<'de, T: Deserialize<'de>> Deserialize<'de> for FlowSeq<T> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> std::result::Result<Self, D::Error> {
T::deserialize(deserializer).map(FlowSeq)
}
}
impl<'de, T: Deserialize<'de>> Deserialize<'de> for FlowMap<T> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> std::result::Result<Self, D::Error> {
T::deserialize(deserializer).map(FlowMap)
}
}
impl<'de, T: Deserialize<'de>> Deserialize<'de> for Commented<T> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> std::result::Result<Self, D::Error> {
struct CommentedVisitor<T>(PhantomData<T>);
impl<'de, T: Deserialize<'de>> Visitor<'de> for CommentedVisitor<T> {
type Value = Commented<T>;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a commented YAML value")
}
fn visit_newtype_struct<D>(
self,
deserializer: D,
) -> std::result::Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
T::deserialize(deserializer).map(|value| Commented(value, String::new()))
}
fn visit_seq<A>(self, mut seq: A) -> std::result::Result<Self::Value, A::Error>
where
A: de::SeqAccess<'de>,
{
let value = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
let comment = seq.next_element()?.unwrap_or_default();
Ok(Commented(value, comment))
}
}
deserializer.deserialize_newtype_struct("__yaml_commented", CommentedVisitor(PhantomData))
}
}
impl<'de, T: Deserialize<'de>> Deserialize<'de> for SpaceAfter<T> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> std::result::Result<Self, D::Error> {
T::deserialize(deserializer).map(SpaceAfter)
}
}
#[cfg(all(test, feature = "deserialize"))]
mod tests {
use serde::Deserialize;
use crate::{Commented, FlowMap, FlowSeq, SpaceAfter};
#[derive(Debug, Deserialize, PartialEq)]
struct WrappersDoc {
seq: FlowSeq<Vec<u32>>,
map: FlowMap<std::collections::BTreeMap<String, u32>>,
after: SpaceAfter<String>,
commented: Commented<bool>,
}
#[test]
fn wrappers_remain_deserializable_without_serialize() {
let value: WrappersDoc =
crate::from_str("seq: [1, 2]\nmap: {a: 1}\nafter: hello\ncommented: true\n").unwrap();
assert_eq!(value.seq, FlowSeq(vec![1, 2]));
assert_eq!(value.after, SpaceAfter("hello".to_string()));
assert_eq!(value.commented, Commented(true, String::new()));
assert_eq!(value.map.0.get("a"), Some(&1));
}
}