1use indexmap::IndexMap;
4use serde::de::{self, MapAccess, SeqAccess};
5use serde::ser::SerializeMap;
6use serde::{Deserialize, Deserializer, Serialize, Serializer};
7
8pub type NodeMap = IndexMap<String, Node>;
10
11#[derive(Debug, Clone, PartialEq, Default)]
20pub enum Node {
21 #[default]
23 Null,
24 Bool(bool),
26 Int(i64),
28 UInt(u64),
30 Float(f64),
32 String(String),
34 Expr(String),
40 Array(Vec<Node>),
42 Object(NodeMap),
44}
45
46fn small_uint(value: u64) -> Node {
50 if value <= i64::MAX as u64 {
51 Node::Int(value as i64)
52 } else {
53 Node::UInt(value)
54 }
55}
56
57impl Serialize for Node {
58 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
59 match self {
60 Self::Null => serializer.serialize_none(),
61 Self::Bool(value) => serializer.serialize_bool(*value),
62 Self::Int(value) => serializer.serialize_i64(*value),
63 Self::UInt(value) => serializer.serialize_u64(*value),
64 Self::Float(value) => serializer.serialize_f64(*value),
65 Self::String(value) => serializer.serialize_str(value),
66 Self::Expr(value) => serializer.serialize_str(value),
67 Self::Array(items) => items.serialize(serializer),
68 Self::Object(map) => {
69 let mut map_serializer = serializer.serialize_map(Some(map.len()))?;
70 for (key, value) in map {
71 map_serializer.serialize_entry(key, value)?;
72 }
73 map_serializer.end()
74 }
75 }
76 }
77}
78
79impl<'de> Deserialize<'de> for Node {
80 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
81 struct NodeVisitor;
82
83 impl<'de> de::Visitor<'de> for NodeVisitor {
84 type Value = Node;
85
86 fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 f.write_str("any YAML or JSON value")
88 }
89
90 fn visit_bool<E: de::Error>(self, value: bool) -> Result<Node, E> {
91 Ok(Node::Bool(value))
92 }
93
94 fn visit_i64<E: de::Error>(self, value: i64) -> Result<Node, E> {
95 Ok(Node::Int(value))
96 }
97
98 fn visit_i128<E: de::Error>(self, value: i128) -> Result<Node, E> {
99 if value >= i64::MIN as i128 && value <= i64::MAX as i128 {
100 Ok(Node::Int(value as i64))
101 } else if value >= 0 && value <= u64::MAX as i128 {
102 Ok(Node::UInt(value as u64))
103 } else {
104 Err(E::custom("integer out of range"))
105 }
106 }
107
108 fn visit_u64<E: de::Error>(self, value: u64) -> Result<Node, E> {
109 Ok(small_uint(value))
110 }
111
112 fn visit_u128<E: de::Error>(self, value: u128) -> Result<Node, E> {
113 if value <= u64::MAX as u128 {
114 Ok(small_uint(value as u64))
115 } else {
116 Err(E::custom("integer out of range"))
117 }
118 }
119
120 fn visit_f64<E: de::Error>(self, value: f64) -> Result<Node, E> {
121 Ok(Node::Float(value))
122 }
123
124 fn visit_str<E: de::Error>(self, value: &str) -> Result<Node, E> {
125 Ok(Node::String(value.to_owned()))
126 }
127
128 fn visit_string<E: de::Error>(self, value: String) -> Result<Node, E> {
129 Ok(Node::String(value))
130 }
131
132 fn visit_none<E: de::Error>(self) -> Result<Node, E> {
133 Ok(Node::Null)
134 }
135
136 fn visit_unit<E: de::Error>(self) -> Result<Node, E> {
137 Ok(Node::Null)
138 }
139
140 fn visit_some<D: Deserializer<'de>>(self, deserializer: D) -> Result<Node, D::Error> {
141 deserializer.deserialize_any(self)
142 }
143
144 fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Node, A::Error> {
145 let mut items = Vec::new();
146 while let Some(item) = seq.next_element::<Node>()? {
147 items.push(item);
148 }
149 Ok(Node::Array(items))
150 }
151
152 fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Node, A::Error> {
153 let mut entries = NodeMap::new();
154 while let Some((key, value)) = map.next_entry::<String, Node>()? {
155 entries.insert(key, value);
156 }
157 Ok(Node::Object(entries))
158 }
159 }
160
161 deserializer.deserialize_any(NodeVisitor)
162 }
163}
164
165impl Node {
166 pub fn as_str(&self) -> Option<&str> {
168 match self {
169 Self::String(value) => Some(value),
170 _ => None,
171 }
172 }
173
174 pub fn as_i64(&self) -> Option<i64> {
176 match self {
177 Self::Int(value) => Some(*value),
178 Self::UInt(value) => i64::try_from(*value).ok(),
179 _ => None,
180 }
181 }
182
183 pub fn as_bool(&self) -> Option<bool> {
185 match self {
186 Self::Bool(value) => Some(*value),
187 _ => None,
188 }
189 }
190
191 pub fn as_object(&self) -> Option<&NodeMap> {
193 match self {
194 Self::Object(map) => Some(map),
195 _ => None,
196 }
197 }
198
199 pub fn as_array(&self) -> Option<&[Node]> {
201 match self {
202 Self::Array(items) => Some(items),
203 _ => None,
204 }
205 }
206
207 pub fn is_null(&self) -> bool {
209 matches!(self, Self::Null)
210 }
211}
212
213impl From<bool> for Node {
214 fn from(value: bool) -> Self {
215 Self::Bool(value)
216 }
217}
218
219impl From<i8> for Node {
220 fn from(value: i8) -> Self {
221 Self::Int(value as i64)
222 }
223}
224
225impl From<i16> for Node {
226 fn from(value: i16) -> Self {
227 Self::Int(value as i64)
228 }
229}
230
231impl From<i32> for Node {
232 fn from(value: i32) -> Self {
233 Self::Int(value as i64)
234 }
235}
236
237impl From<isize> for Node {
238 fn from(value: isize) -> Self {
239 Self::Int(value as i64)
240 }
241}
242
243impl From<u8> for Node {
244 fn from(value: u8) -> Self {
245 Self::Int(value as i64)
246 }
247}
248
249impl From<u16> for Node {
250 fn from(value: u16) -> Self {
251 Self::Int(value as i64)
252 }
253}
254
255impl From<u32> for Node {
256 fn from(value: u32) -> Self {
257 Self::Int(value as i64)
258 }
259}
260
261impl From<i64> for Node {
262 fn from(value: i64) -> Self {
263 Self::Int(value)
264 }
265}
266
267impl From<u64> for Node {
268 fn from(value: u64) -> Self {
269 small_uint(value)
270 }
271}
272
273impl From<f64> for Node {
274 fn from(value: f64) -> Self {
275 Self::Float(value)
276 }
277}
278
279impl From<usize> for Node {
280 fn from(value: usize) -> Self {
281 small_uint(value as u64)
282 }
283}
284
285impl std::ops::Index<&str> for Node {
290 type Output = Node;
291
292 fn index(&self, key: &str) -> &Node {
293 static NULL: Node = Node::Null;
294 self.as_object()
295 .and_then(|map| map.get(key))
296 .unwrap_or(&NULL)
297 }
298}
299
300impl From<&str> for Node {
301 fn from(value: &str) -> Self {
302 Self::String(value.to_owned())
303 }
304}
305
306impl From<String> for Node {
307 fn from(value: String) -> Self {
308 Self::String(value)
309 }
310}
311
312impl From<Vec<Node>> for Node {
313 fn from(value: Vec<Node>) -> Self {
314 Self::Array(value)
315 }
316}
317
318impl From<NodeMap> for Node {
319 fn from(value: NodeMap) -> Self {
320 Self::Object(value)
321 }
322}
323
324impl FromIterator<(String, Node)> for Node {
325 fn from_iter<I: IntoIterator<Item = (String, Node)>>(iter: I) -> Self {
326 Self::Object(NodeMap::from_iter(iter))
327 }
328}
329
330#[cfg(test)]
331mod tests {
332 use super::*;
333
334 #[test]
335 fn yaml_round_trip_preserves_key_order() {
336 let node: Node = serde_yaml_ng::from_str("b: 1\na: 2\nc: [x, y]").unwrap();
337 let text = serde_yaml_ng::to_string(&node).unwrap();
338 assert!(text.contains("b: 1"), "{text}");
339 assert!(text.contains("a: 2"), "{text}");
340 let back: Node = serde_yaml_ng::from_str(&text).unwrap();
341 assert_eq!(node, back);
342 }
343
344 #[test]
345 fn json_round_trip_preserves_key_order() {
346 let node: Node = serde_json::from_str(r#"{"b":1,"a":2,"c":[1,2.5,true,null]}"#).unwrap();
347 let text = serde_json::to_string(&node).unwrap();
348 assert_eq!(text, r#"{"b":1,"a":2,"c":[1,2.5,true,null]}"#);
349 let back: Node = serde_json::from_str(&text).unwrap();
350 assert_eq!(node, back);
351 }
352
353 #[test]
354 fn wide_integers_survive() {
355 let node: Node = serde_yaml_ng::from_str("big: 18446744073709551615").unwrap();
356 let Node::Object(map) = &node else {
357 panic!("expected object");
358 };
359 assert_eq!(map["big"], Node::UInt(u64::MAX));
360 let text = serde_yaml_ng::to_string(&node).unwrap();
361 assert!(text.contains("18446744073709551615"), "{text}");
362 }
363}