use linked_hash_map::LinkedHashMap;
use serde::Serialize;
use yaml_rust as yr;
#[derive(Debug, PartialEq, Eq, Clone, Serialize)]
#[serde(untagged)]
pub enum Yaml {
Real(String),
Integer(i64),
String(String),
Boolean(bool),
Array(Vec<Yaml>),
Hash(LinkedHashMap<String, Yaml>),
Alias(usize),
Null,
BadValue,
}
impl From<yr::Yaml> for Yaml {
fn from(y: yr::Yaml) -> Self {
match y {
yr::Yaml::Real(s) => Self::Real(s),
yr::Yaml::Integer(i) => Self::Integer(i),
yr::Yaml::String(s) => Self::String(s),
yr::Yaml::Boolean(b) => Self::Boolean(b),
yr::Yaml::Array(a) => Self::Array(a.into_iter().map(Yaml::from).collect()),
yr::Yaml::Hash(m) => Yaml::Hash(m.into_iter().map(with_key_as_string).collect()),
yr::Yaml::Alias(a) => Self::Alias(a),
yr::Yaml::Null => Self::Null,
yr::Yaml::BadValue => Self::BadValue,
}
}
}
impl From<&yr::Yaml> for Yaml {
fn from(y: &yr::Yaml) -> Self {
Self::from(y.clone())
}
}
pub fn from_vec(v: Vec<yr::Yaml>) -> Vec<Yaml> {
v.into_iter().map(Yaml::from).collect()
}
pub fn from_slice(v: &[yr::Yaml]) -> Vec<Yaml> {
v.iter().map(Yaml::from).collect()
}
pub fn from_map(m: LinkedHashMap<yr::Yaml, yr::Yaml>) -> LinkedHashMap<String, Yaml> {
m.into_iter().map(with_key_as_string).collect()
}
pub fn from_map_ref(m: &LinkedHashMap<yr::Yaml, yr::Yaml>) -> LinkedHashMap<String, Yaml> {
m.clone().into_iter().map(with_key_as_string).collect()
}
fn with_key_as_string(t: (yr::Yaml, yr::Yaml)) -> (String, Yaml) {
(t.0.as_str().unwrap().to_owned(), Yaml::from(t.1))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn frontmatter() {
let input = "
title: Home
tags: [c++, war-stories]
";
let yaml = yaml_rust::YamlLoader::load_from_str(input).unwrap();
let yaml = from_vec(yaml);
let yaml_as_string = serde_yaml::to_string(&yaml).unwrap();
let expected = "- title: Home
tags:
- c++
- war-stories
";
assert_eq!(yaml_as_string, expected);
}
#[test]
fn from_vec_ref() {
let input = "
title: Home
tags: [c++, war-stories]
";
let yaml = yaml_rust::YamlLoader::load_from_str(input).unwrap();
let yaml = super::from_slice(&yaml);
let yaml_as_string = serde_yaml::to_string(&yaml).unwrap();
let expected = "- title: Home
tags:
- c++
- war-stories
";
assert_eq!(yaml_as_string, expected);
}
#[test]
fn from_map() {
let input = "
key1: value1
key2: [value2, value3]
";
let yaml = yaml_rust::YamlLoader::load_from_str(input)
.unwrap()
.pop()
.unwrap();
let yr::Yaml::Hash(yaml) = yaml else { panic!() };
let yaml = super::from_map(yaml);
let yaml_as_string = serde_yaml::to_string(&yaml).unwrap();
let expected = "key1: value1
key2:
- value2
- value3
";
assert_eq!(yaml_as_string, expected);
}
#[test]
fn from_map_ref() {
let input = "
key1: value1
key2: [42, 0]
";
let yaml = yaml_rust::YamlLoader::load_from_str(input)
.unwrap()
.pop()
.unwrap();
let yr::Yaml::Hash(yaml) = yaml else { panic!() };
let yaml = super::from_map_ref(&yaml);
let yaml_as_yaml_string = serde_yaml::to_string(&yaml).unwrap();
let expected = "key1: value1
key2:
- 42
- 0
";
assert_eq!(yaml_as_yaml_string, expected);
}
}