1use linked_hash_map::LinkedHashMap;
40use serde::Serialize;
41use yaml_rust as yr;
42
43#[derive(Debug, PartialEq, Eq, Clone, Serialize)]
46#[serde(untagged)]
47pub enum Yaml {
48 Real(String),
49 Integer(i64),
50 String(String),
51 Boolean(bool),
52 Array(Vec<Yaml>),
53 Hash(LinkedHashMap<String, Yaml>),
54 Alias(usize),
55 Null,
56 BadValue,
57}
58
59impl From<yr::Yaml> for Yaml {
60 fn from(y: yr::Yaml) -> Self {
61 match y {
62 yr::Yaml::Real(s) => Self::Real(s),
63 yr::Yaml::Integer(i) => Self::Integer(i),
64 yr::Yaml::String(s) => Self::String(s),
65 yr::Yaml::Boolean(b) => Self::Boolean(b),
66 yr::Yaml::Array(a) => Self::Array(a.into_iter().map(Yaml::from).collect()),
67 yr::Yaml::Hash(m) => Yaml::Hash(m.into_iter().map(with_key_as_string).collect()),
68 yr::Yaml::Alias(a) => Self::Alias(a),
69 yr::Yaml::Null => Self::Null,
70 yr::Yaml::BadValue => Self::BadValue,
71 }
72 }
73}
74
75impl From<&yr::Yaml> for Yaml {
76 fn from(y: &yr::Yaml) -> Self {
77 Self::from(y.clone())
78 }
79}
80
81pub fn from_vec(v: Vec<yr::Yaml>) -> Vec<Yaml> {
82 v.into_iter().map(Yaml::from).collect()
83}
84
85pub fn from_slice(v: &[yr::Yaml]) -> Vec<Yaml> {
86 v.iter().map(Yaml::from).collect()
87}
88
89pub fn from_map(m: LinkedHashMap<yr::Yaml, yr::Yaml>) -> LinkedHashMap<String, Yaml> {
90 m.into_iter().map(with_key_as_string).collect()
91}
92
93pub fn from_map_ref(m: &LinkedHashMap<yr::Yaml, yr::Yaml>) -> LinkedHashMap<String, Yaml> {
94 m.clone().into_iter().map(with_key_as_string).collect()
95}
96
97fn with_key_as_string(t: (yr::Yaml, yr::Yaml)) -> (String, Yaml) {
98 (t.0.as_str().unwrap().to_owned(), Yaml::from(t.1))
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104
105 #[test]
107 fn frontmatter() {
108 let input = "
109 title: Home
110 tags: [c++, war-stories]
111 ";
112 let yaml = yaml_rust::YamlLoader::load_from_str(input).unwrap();
113 let yaml = from_vec(yaml);
114 let yaml_as_string = serde_yaml::to_string(&yaml).unwrap();
115 let expected = "- title: Home
116 tags:
117 - c++
118 - war-stories
119";
120 assert_eq!(yaml_as_string, expected);
121 }
122
123 #[test]
124 fn from_vec_ref() {
125 let input = "
126 title: Home
127 tags: [c++, war-stories]
128 ";
129 let yaml = yaml_rust::YamlLoader::load_from_str(input).unwrap();
130 let yaml = super::from_slice(&yaml);
131 let yaml_as_string = serde_yaml::to_string(&yaml).unwrap();
132 let expected = "- title: Home
133 tags:
134 - c++
135 - war-stories
136";
137 assert_eq!(yaml_as_string, expected);
138 }
139
140 #[test]
142 fn from_map() {
143 let input = "
144 key1: value1
145 key2: [value2, value3]
146 ";
147 let yaml = yaml_rust::YamlLoader::load_from_str(input)
148 .unwrap()
149 .pop()
150 .unwrap();
151 let yr::Yaml::Hash(yaml) = yaml else { panic!() };
152 let yaml = super::from_map(yaml);
153 let yaml_as_string = serde_yaml::to_string(&yaml).unwrap();
154 let expected = "key1: value1
155key2:
156- value2
157- value3
158";
159 assert_eq!(yaml_as_string, expected);
160 }
161
162 #[test]
163 fn from_map_ref() {
164 let input = "
165 key1: value1
166 key2: [42, 0]
167 ";
168 let yaml = yaml_rust::YamlLoader::load_from_str(input)
169 .unwrap()
170 .pop()
171 .unwrap();
172 let yr::Yaml::Hash(yaml) = yaml else { panic!() };
173 let yaml = super::from_map_ref(&yaml);
174 let yaml_as_yaml_string = serde_yaml::to_string(&yaml).unwrap();
175 let expected = "key1: value1
176key2:
177- 42
178- 0
179";
180 assert_eq!(yaml_as_yaml_string, expected);
181 }
182}