use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::yaml::error::Error;
use crate::yaml::mapping::Mapping;
use crate::yaml::value::Value;
pub(crate) fn serialize<T, S>(
value: &T,
serializer: S,
) -> Result<S::Ok, S::Error>
where
T: Serialize,
S: Serializer,
{
let v = value
.serialize(crate::yaml::value::ValueSerializer)
.map_err(serde::ser::Error::custom)?;
let mapped = to_singleton_map(v);
mapped.serialize(serializer)
}
pub(crate) fn deserialize<'de, T, D>(
deserializer: D,
) -> Result<T, D::Error>
where
T: Deserialize<'de>,
D: Deserializer<'de>,
{
let v = Value::deserialize(deserializer)?;
let converted = from_singleton_map(v);
T::deserialize(converted).map_err(serde::de::Error::custom)
}
pub(crate) fn to_singleton_map(v: Value) -> Value {
match v {
Value::String(s) => {
let mut m = Mapping::new();
m.insert(Value::String(s), Value::Null);
Value::Mapping(m)
}
other => other,
}
}
pub(crate) fn from_singleton_map(v: Value) -> Value {
match v {
Value::Mapping(ref m) if m.len() == 1 => {
let (_, val) = m.iter().next().expect("len == 1");
if val.is_null() {
v
} else {
v
}
}
other => other,
}
}
pub(crate) fn apply_to_value(v: &mut Value) -> Result<(), Error> {
*v = to_singleton_map(std::mem::take(v));
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn from_singleton_map_passthrough_on_multi_key_mapping() {
let mut m = Mapping::new();
m.insert(Value::String("a".into()), Value::String("1".into()));
m.insert(Value::String("b".into()), Value::String("2".into()));
let v = Value::Mapping(m);
let out = from_singleton_map(v.clone());
assert_eq!(out, v);
}
#[test]
fn from_singleton_map_passthrough_on_non_mapping() {
let v = Value::String("x".into());
let out = from_singleton_map(v.clone());
assert_eq!(out, v);
}
#[test]
fn apply_to_value_wraps_string() {
let mut v = Value::String("Variant".into());
apply_to_value(&mut v).unwrap();
let m = v.as_mapping().expect("wrapped as mapping");
assert_eq!(m.len(), 1);
let (k, val) = m.iter().next().unwrap();
assert_eq!(k, &Value::String("Variant".into()));
assert!(val.is_null());
}
#[test]
fn apply_to_value_passes_non_string_through() {
let mut v = Value::Null;
apply_to_value(&mut v).unwrap();
assert!(v.is_null());
}
}