1use std::marker::PhantomData;
2
3use crate::*;
4use indexmap::IndexMap;
5use http::Method;
6use serde::{Deserialize, Deserializer, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
14pub struct PathItem {
15 #[serde(skip_serializing_if = "Option::is_none")]
18 pub summary: Option<String>,
19 #[serde(skip_serializing_if = "Option::is_none")]
22 pub description: Option<String>,
23 #[serde(skip_serializing_if = "Option::is_none")]
24 pub get: Option<Operation>,
25 #[serde(skip_serializing_if = "Option::is_none")]
26 pub put: Option<Operation>,
27 #[serde(skip_serializing_if = "Option::is_none")]
28 pub post: Option<Operation>,
29 #[serde(skip_serializing_if = "Option::is_none")]
30 pub delete: Option<Operation>,
31 #[serde(skip_serializing_if = "Option::is_none")]
32 pub options: Option<Operation>,
33 #[serde(skip_serializing_if = "Option::is_none")]
34 pub head: Option<Operation>,
35 #[serde(skip_serializing_if = "Option::is_none")]
36 pub patch: Option<Operation>,
37 #[serde(skip_serializing_if = "Option::is_none")]
38 pub trace: Option<Operation>,
39 #[serde(default, skip_serializing_if = "Vec::is_empty")]
41 pub servers: Vec<Server>,
42 #[serde(default)]
50 #[serde(skip_serializing_if = "Vec::is_empty")]
51 pub parameters: Vec<RefOr<Parameter>>,
52 #[serde(flatten, deserialize_with = "crate::util::deserialize_extensions")]
54 pub extensions: IndexMap<String, serde_json::Value>,
55}
56
57impl PathItem {
58 pub fn iter(&self) -> impl Iterator<Item=(&str, &'_ Operation)> {
60 vec![
61 ("get", &self.get),
62 ("put", &self.put),
63 ("post", &self.post),
64 ("delete", &self.delete),
65 ("options", &self.options),
66 ("head", &self.head),
67 ("patch", &self.patch),
68 ("trace", &self.trace),
69 ]
70 .into_iter()
71 .filter_map(|(method, maybe_op)| maybe_op.as_ref().map(|op| (method, op)))
72 }
73
74 pub fn iter_mut(&mut self) -> impl Iterator<Item=(&str, &'_ mut Operation)> {
75 vec![
76 ("get", &mut self.get),
77 ("put", &mut self.put),
78 ("post", &mut self.post),
79 ("delete", &mut self.delete),
80 ("options", &mut self.options),
81 ("head", &mut self.head),
82 ("patch", &mut self.patch),
83 ("trace", &mut self.trace),
84 ]
85 .into_iter()
86 .filter_map(|(method, maybe_op)| maybe_op.as_mut().map(|op| (method, op)))
87 }
88
89 pub fn get(operation: Operation) -> Self {
90 Self {
91 get: Some(operation),
92 ..PathItem::default()
93 }
94 }
95
96 pub fn post(operation: Operation) -> Self {
97 Self {
98 post: Some(operation),
99 ..PathItem::default()
100 }
101 }
102}
103
104impl IntoIterator for PathItem {
105 type Item = (&'static str, Operation);
106
107 type IntoIter = std::vec::IntoIter<Self::Item>;
108
109 fn into_iter(self) -> Self::IntoIter {
111 vec![
112 ("get", self.get),
113 ("put", self.put),
114 ("post", self.post),
115 ("delete", self.delete),
116 ("options", self.options),
117 ("head", self.head),
118 ("patch", self.patch),
119 ("trace", self.trace),
120 ]
121 .into_iter()
122 .filter_map(|(method, maybe_op)| maybe_op.map(|op| (method, op)))
123 .collect::<Vec<_>>()
124 .into_iter()
125 }
126}
127
128#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
133pub struct Paths {
134 #[serde(flatten, deserialize_with = "deserialize_paths")]
136 pub paths: IndexMap<String, RefOr<PathItem>>,
137 #[serde(flatten, deserialize_with = "crate::util::deserialize_extensions")]
139 pub extensions: IndexMap<String, serde_json::Value>,
140}
141
142impl std::ops::Deref for Paths {
143 type Target = IndexMap<String, RefOr<PathItem>>;
144
145 fn deref(&self) -> &Self::Target {
146 &self.paths
147 }
148}
149
150impl std::ops::DerefMut for Paths {
151 fn deref_mut(&mut self) -> &mut Self::Target {
152 &mut self.paths
153 }
154}
155
156impl Paths {
157 pub fn insert(&mut self, key: String, path_item: PathItem) -> Option<RefOr<PathItem>> {
158 self.paths.insert(key, RefOr::Item(path_item))
159 }
160
161 pub fn insert_operation(&mut self, path: String, method: Method, operation: Operation) -> Option<Operation> {
162 let item = self.paths.entry(path).or_default();
163 let item = item.as_mut().expect("Currently don't support references for PathItem");
164 match method {
165 Method::GET => item.get.replace(operation),
166 Method::PUT => item.put.replace(operation),
167 Method::POST => item.post.replace(operation),
168 Method::DELETE => item.delete.replace(operation),
169 Method::PATCH => item.patch.replace(operation),
170 Method::HEAD => item.head.replace(operation),
171 Method::OPTIONS => item.options.replace(operation),
172 Method::TRACE => item.trace.replace(operation),
173 _ => panic!("Unsupported method: {:?}", method),
174 }
175 }
176}
177
178impl IntoIterator for Paths {
179 type Item = (String, RefOr<PathItem>);
180
181 type IntoIter = indexmap::map::IntoIter<String, RefOr<PathItem>>;
182
183 fn into_iter(self) -> Self::IntoIter {
184 self.paths.into_iter()
185 }
186}
187
188fn deserialize_paths<'de, D>(
189 deserializer: D,
190) -> Result<IndexMap<String, RefOr<PathItem>>, D::Error>
191 where
192 D: Deserializer<'de>,
193{
194 deserializer.deserialize_map(PredicateVisitor(
195 |key: &String| key.starts_with('/'),
196 PhantomData,
197 ))
198}
199
200#[cfg(test)]
201mod tests {
202 use super::*;
203
204 #[test]
205 fn test_path_item_iterators() {
206 let operation = Operation::default();
207
208 let path_item = PathItem {
209 get: Some(operation.clone()),
210 post: Some(operation.clone()),
211 delete: Some(operation.clone()),
212 ..Default::default()
213 };
214
215 let expected = vec![
216 ("get", &operation),
217 ("post", &operation),
218 ("delete", &operation),
219 ];
220 assert_eq!(path_item.iter().collect::<Vec<_>>(), expected);
221
222 let expected = vec![
223 ("get", operation.clone()),
224 ("post", operation.clone()),
225 ("delete", operation.clone()),
226 ];
227 assert_eq!(path_item.into_iter().collect::<Vec<_>>(), expected);
228 }
229}