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