openapiv3_1/
extensions.rs1use std::ops::{Deref, DerefMut};
5
6use indexmap::IndexMap;
7
8const EXTENSION_PREFIX: &str = "x-";
9
10#[derive(Default, serde_derive::Serialize, Clone, PartialEq, Eq)]
14#[cfg_attr(feature = "debug", derive(Debug))]
15pub struct Extensions {
16 #[serde(flatten)]
17 extensions: IndexMap<String, serde_json::Value>,
18}
19
20impl Extensions {
21 pub fn new<K: Into<String>, V: Into<serde_json::Value>>(items: impl IntoIterator<Item = (K, V)>) -> Self {
23 items.into_iter().fold(Self::default(), |this, (k, v)| this.add(k, v))
24 }
25
26 pub fn merge(&mut self, other: Extensions) {
28 self.extensions.extend(other.extensions);
29 }
30
31 pub fn add(mut self, key: impl Into<String>, value: impl Into<serde_json::Value>) -> Self {
33 let mut key = key.into();
34 if !key.starts_with(EXTENSION_PREFIX) {
35 key = format!("{EXTENSION_PREFIX}{key}");
36 }
37 self.extensions.insert(key, value.into());
38 self
39 }
40}
41
42impl Deref for Extensions {
43 type Target = IndexMap<String, serde_json::Value>;
44
45 fn deref(&self) -> &Self::Target {
46 &self.extensions
47 }
48}
49
50impl DerefMut for Extensions {
51 fn deref_mut(&mut self) -> &mut Self::Target {
52 &mut self.extensions
53 }
54}
55
56impl<K, V> FromIterator<(K, V)> for Extensions
57where
58 K: Into<String>,
59 V: Into<serde_json::Value>,
60{
61 fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
62 Self::new(iter)
63 }
64}
65
66impl From<Extensions> for IndexMap<String, serde_json::Value> {
67 fn from(value: Extensions) -> Self {
68 value.extensions
69 }
70}
71
72impl<'de> serde::de::Deserialize<'de> for Extensions {
73 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
74 where
75 D: serde::Deserializer<'de>,
76 {
77 let extensions: IndexMap<String, _> = IndexMap::deserialize(deserializer)?;
78 let extensions = extensions
79 .into_iter()
80 .filter(|(k, _)| k.starts_with(EXTENSION_PREFIX))
81 .collect();
82 Ok(Self { extensions })
83 }
84}
85
86#[cfg(test)]
87#[cfg_attr(coverage_nightly, coverage(off))]
88mod tests {
89 use serde_json::json;
90
91 use super::*;
92
93 #[test]
94 fn extensions_builder() {
95 let expected = json!("value");
96 let extensions = Extensions::default()
97 .add("x-some-extension", expected.clone())
98 .add("another-extension", expected.clone());
99
100 let value = serde_json::to_value(&extensions).unwrap();
101 assert_eq!(value.get("x-some-extension"), Some(&expected));
102 assert_eq!(value.get("x-another-extension"), Some(&expected));
103 }
104
105 #[test]
106 fn extensions_from_iter() {
107 let expected = json!("value");
108 let extensions: Extensions = [
109 ("x-some-extension", expected.clone()),
110 ("another-extension", expected.clone()),
111 ]
112 .into_iter()
113 .collect();
114
115 assert_eq!(extensions.get("x-some-extension"), Some(&expected));
116 assert_eq!(extensions.get("x-another-extension"), Some(&expected));
117 }
118}