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 {
33 self.0.is_empty()
34 }
35
36 pub fn insert(&mut self, key: impl Into<String>, value: serde_json::Value) {
38 self.0.insert(key.into(), value);
39 }
40
41 pub fn get(&self, key: &str) -> Option<&serde_json::Value> {
43 self.0.get(key)
44 }
45
46 pub fn iter(&self) -> impl Iterator<Item = (&String, &serde_json::Value)> {
48 self.0.iter()
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55 use serde::{Deserialize, Serialize};
56 use serde_json::json;
57
58 #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
59 struct Holder {
60 #[serde(default, skip_serializing_if = "ExtensionsMap::is_empty")]
61 extensions: ExtensionsMap,
62 }
63
64 #[test]
65 fn empty_is_empty() {
66 let m = ExtensionsMap::new();
67 assert!(m.is_empty());
68 }
69
70 #[test]
71 fn after_insert_not_empty() {
72 let mut m = ExtensionsMap::new();
73 m.insert("vendor.example/foo", json!({"x": 1}));
74 assert!(!m.is_empty());
75 assert_eq!(m.get("vendor.example/foo"), Some(&json!({"x": 1})));
76 }
77
78 #[test]
79 fn round_trip_with_extension() {
80 let mut m = ExtensionsMap::new();
81 m.insert("vendor.example/foo", json!({"x": 1}));
82 let h = Holder { extensions: m };
83 let s = serde_json::to_string(&h).unwrap();
84 assert!(s.contains("vendor.example/foo"));
85 let back: Holder = serde_json::from_str(&s).unwrap();
86 assert_eq!(h, back);
87 }
88
89 #[test]
90 fn empty_extensions_omitted_from_canonical_json() {
91 let h = Holder {
92 extensions: ExtensionsMap::new(),
93 };
94 let s = serde_json::to_string(&h).unwrap();
95 assert_eq!(s, "{}");
97 }
98
99 #[test]
100 fn keys_iterate_in_sorted_order() {
101 let mut m = ExtensionsMap::new();
102 m.insert("z", json!(1));
103 m.insert("a", json!(2));
104 m.insert("m", json!(3));
105 let order: Vec<_> = m.iter().map(|(k, _)| k.as_str()).collect();
106 assert_eq!(order, vec!["a", "m", "z"]);
107 }
108}