use serde::Serialize;
use std::collections::BTreeMap;
pub fn sorted_serialize<S, K, V, M>(map: M, s: S) -> Result<S::Ok, S::Error>
where
M: IntoIterator<Item = (K, V)>,
S: serde::Serializer,
K: Ord + Serialize + Clone,
V: Serialize + Clone,
{
let ordered_map: BTreeMap<K, V> = map.into_iter().collect();
Serialize::serialize(&ordered_map, s)
}
#[cfg(test)]
mod tests {
#![allow(non_snake_case)]
use serde_derive::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
struct SampleData {
#[serde(flatten, serialize_with = "super::sorted_serialize")]
values: HashMap<String, String>,
}
#[test]
fn serde_roundtrip__produces_matching_data() {
let data = SampleData {
values: {
let mut map = HashMap::new();
map.insert("foo".into(), "bar".into());
map.insert("abc".into(), "def".into());
map.insert("123".into(), "456".into());
map
},
};
let string = serde_yaml::to_string(&data).unwrap();
let deserialized_data: SampleData = serde_yaml::from_str(&string).unwrap();
assert_eq!(data, deserialized_data);
}
#[test]
fn yaml_to_string__produces_correctly_sorted_order_consistently() {
for _i in 0..100 {
let data = SampleData {
values: {
let mut map = HashMap::new();
map.insert("d".into(), "jkl".into());
map.insert("a".into(), "abc".into());
map.insert("e".into(), "mno".into());
map.insert("c".into(), "ghi".into());
map.insert("b".into(), "def".into());
map
},
};
let string = serde_yaml::to_string(&data).unwrap();
assert_eq!(
string,
r###"---
a: abc
b: def
c: ghi
d: jkl
e: mno
"###
);
}
}
}