1use serde::{Deserialize, Serialize};
9use std::collections::BTreeMap;
10
11#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
17#[serde(transparent)]
18pub struct ExtensionsMap(BTreeMap<String, serde_json::Value>);
19
20impl ExtensionsMap {
21 pub fn new() -> Self {
23 Self::default()
24 }
25
26 pub fn is_empty(&self) -> bool {
40 self.0.is_empty()
41 }
42
43 pub fn insert(&mut self, key: impl Into<String>, value: serde_json::Value) {
45 self.0.insert(key.into(), value);
46 }
47
48 pub fn get(&self, key: &str) -> Option<&serde_json::Value> {
50 self.0.get(key)
51 }
52
53 pub fn iter(&self) -> impl Iterator<Item = (&String, &serde_json::Value)> {
55 self.0.iter()
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62 use serde::{Deserialize, Serialize};
63 use serde_json::json;
64
65 #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
66 struct Holder {
67 #[serde(default, skip_serializing_if = "ExtensionsMap::is_empty")]
68 extensions: ExtensionsMap,
69 }
70
71 #[test]
72 fn empty_is_empty() {
73 let m = ExtensionsMap::new();
74 assert!(m.is_empty());
75 }
76
77 #[test]
78 fn after_insert_not_empty() {
79 let mut m = ExtensionsMap::new();
80 m.insert("vendor.example/foo", json!({"x": 1}));
81 assert!(!m.is_empty());
82 assert_eq!(m.get("vendor.example/foo"), Some(&json!({"x": 1})));
83 }
84
85 #[test]
86 fn round_trip_with_extension() {
87 let mut m = ExtensionsMap::new();
88 m.insert("vendor.example/foo", json!({"x": 1}));
89 let h = Holder { extensions: m };
90 let s = serde_json::to_string(&h).unwrap();
91 assert!(s.contains("vendor.example/foo"));
92 let back: Holder = serde_json::from_str(&s).unwrap();
93 assert_eq!(h, back);
94 }
95
96 #[test]
97 fn empty_extensions_omitted_from_canonical_json() {
98 let h = Holder {
99 extensions: ExtensionsMap::new(),
100 };
101 let s = serde_json::to_string(&h).unwrap();
102 assert_eq!(s, "{}");
104 }
105
106 #[test]
107 fn keys_iterate_in_sorted_order() {
108 let mut m = ExtensionsMap::new();
109 m.insert("z", json!(1));
110 m.insert("a", json!(2));
111 m.insert("m", json!(3));
112 let order: Vec<_> = m.iter().map(|(k, _)| k.as_str()).collect();
113 assert_eq!(order, vec!["a", "m", "z"]);
114 }
115}