serde_ordered_collections/
map.rs

1use serde::Serialize;
2use std::collections::BTreeMap;
3
4pub fn sorted_serialize<S, K, V, M>(map: M, s: S) -> Result<S::Ok, S::Error>
5where
6    M: IntoIterator<Item = (K, V)>,
7    S: serde::Serializer,
8    K: Ord + Serialize + Clone,
9    V: Serialize + Clone,
10{
11    let ordered_map: BTreeMap<K, V> = map.into_iter().collect();
12    Serialize::serialize(&ordered_map, s)
13}
14
15#[cfg(test)]
16mod tests {
17    #![allow(non_snake_case)]
18
19    use serde_derive::{Deserialize, Serialize};
20    use std::collections::HashMap;
21
22    #[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
23    struct SampleData {
24        #[serde(flatten, serialize_with = "super::sorted_serialize")]
25        values: HashMap<String, String>,
26    }
27
28    #[test]
29    fn serde_roundtrip__produces_matching_data() {
30        // Given
31        let data = SampleData {
32            values: {
33                let mut map = HashMap::new();
34                map.insert("foo".into(), "bar".into());
35                map.insert("abc".into(), "def".into());
36                map.insert("123".into(), "456".into());
37
38                map
39            },
40        };
41
42        // When
43        let string = serde_yaml::to_string(&data).unwrap();
44
45        // Then
46        let deserialized_data: SampleData = serde_yaml::from_str(&string).unwrap();
47        assert_eq!(data, deserialized_data);
48    }
49
50    #[test]
51    fn yaml_to_string__produces_correctly_sorted_order_consistently() {
52        for _i in 0..100 {
53            // Given
54            let data = SampleData {
55                values: {
56                    let mut map = HashMap::new();
57                    map.insert("d".into(), "jkl".into());
58                    map.insert("a".into(), "abc".into());
59                    map.insert("e".into(), "mno".into());
60                    map.insert("c".into(), "ghi".into());
61                    map.insert("b".into(), "def".into());
62
63                    map
64                },
65            };
66
67            // When
68            let string = serde_yaml::to_string(&data).unwrap();
69
70            // Then
71            assert_eq!(
72                string,
73                r###"---
74a: abc
75b: def
76c: ghi
77d: jkl
78e: mno
79"###
80            );
81        }
82    }
83}