1use crate::common::helpers::{Context, ValidateWithContext};
2use crate::v3_0::path_item::PathItem;
3use crate::v3_0::spec::Spec;
4use serde::de::{Error, MapAccess, Visitor};
5use serde::ser::SerializeMap;
6use serde::{Deserialize, Deserializer, Serialize, Serializer};
7use std::collections::BTreeMap;
8use std::fmt;
9
10#[derive(Clone, Debug, PartialEq, Default)]
47pub struct Callback {
48 pub paths: BTreeMap<String, PathItem>,
50
51 pub extensions: Option<BTreeMap<String, serde_json::Value>>,
55}
56
57impl Serialize for Callback {
58 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
59 where
60 S: Serializer,
61 {
62 let mut len = self.paths.len();
63 if let Some(ext) = &self.extensions {
64 len += ext.len();
65 }
66 let mut map = serializer.serialize_map(Some(len))?;
67
68 for (k, v) in &self.paths {
69 map.serialize_entry(&k, &v)?;
70 }
71
72 if let Some(ext) = &self.extensions {
73 for (k, v) in ext {
74 if k.starts_with("x-") {
75 map.serialize_entry(&k, &v)?;
76 }
77 }
78 }
79
80 map.end()
81 }
82}
83
84impl<'de> Deserialize<'de> for Callback {
85 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
86 where
87 D: Deserializer<'de>,
88 {
89 const FIELDS: &[&str] = &["<path name>", "x-<ext name>"];
90
91 struct CallbackVisitor;
92
93 impl<'de> Visitor<'de> for CallbackVisitor {
94 type Value = Callback;
95
96 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
97 formatter.write_str("struct Callback")
98 }
99
100 fn visit_map<V>(self, mut map: V) -> Result<Callback, V::Error>
101 where
102 V: MapAccess<'de>,
103 {
104 let mut res = Callback {
105 paths: BTreeMap::new(),
106 ..Default::default()
107 };
108 let mut extensions: BTreeMap<String, serde_json::Value> = BTreeMap::new();
109 while let Some(key) = map.next_key::<String>()? {
110 if key.starts_with("x-") {
111 if extensions.contains_key(key.as_str()) {
112 return Err(Error::custom(format_args!("duplicate field `{key}`")));
113 }
114 extensions.insert(key, map.next_value()?);
115 } else {
116 if res.paths.contains_key(key.as_str()) {
117 return Err(Error::custom(format_args!("duplicate field `{key}`")));
118 }
119 res.paths.insert(key, map.next_value()?);
120 }
121 }
122 if !extensions.is_empty() {
123 res.extensions = Some(extensions);
124 }
125 Ok(res)
126 }
127 }
128
129 deserializer.deserialize_struct("Callback", FIELDS, CallbackVisitor)
130 }
131}
132
133impl ValidateWithContext<Spec> for Callback {
134 fn validate_with_context(&self, ctx: &mut Context<Spec>, path: String) {
135 for (name, path_item) in &self.paths {
136 path_item.validate_with_context(ctx, format!("{path}[{name}]"));
137 }
138 }
139}