1use serde::{Deserialize, Serialize};
5use serde_json::Value;
6
7use super::{Deprecated, RefOr, Required, Schema};
8use crate::PropMap;
9
10#[derive(Serialize, Deserialize, Debug, PartialEq, Default, Clone)]
12pub struct Parameters(pub Vec<Parameter>);
13
14impl IntoIterator for Parameters {
15 type Item = Parameter;
16 type IntoIter = <Vec<Parameter> as IntoIterator>::IntoIter;
17
18 fn into_iter(self) -> Self::IntoIter {
19 self.0.into_iter()
20 }
21}
22
23impl Parameters {
24 #[must_use]
26 pub fn new() -> Self {
27 Default::default()
28 }
29 #[must_use]
31 pub fn is_empty(&self) -> bool {
32 self.0.is_empty()
33 }
34 #[must_use]
36 pub fn parameter<P: Into<Parameter>>(mut self, parameter: P) -> Self {
37 self.insert(parameter);
38 self
39 }
40 #[must_use]
42 pub fn contains(&self, name: &str, parameter_in: ParameterIn) -> bool {
43 self.0
44 .iter()
45 .any(|item| item.name == name && item.parameter_in == parameter_in)
46 }
47 pub fn insert<P: Into<Parameter>>(&mut self, parameter: P) {
49 let parameter = parameter.into();
50 let exist_item = self.0.iter_mut().find(|item| {
51 item.name == parameter.name && item.parameter_in == parameter.parameter_in
52 });
53
54 if let Some(exist_item) = exist_item {
55 exist_item.merge(parameter);
56 } else {
57 self.0.push(parameter);
58 }
59 }
60 pub fn append(&mut self, other: &mut Self) {
65 for item in other.0.drain(..) {
66 self.insert(item);
67 }
68 }
69 pub fn extend<I>(&mut self, iter: I)
71 where
72 I: IntoIterator<Item = Parameter>,
73 {
74 for item in iter {
75 self.insert(item);
76 }
77 }
78}
79
80#[non_exhaustive]
84#[derive(Serialize, Deserialize, Default, Clone, PartialEq, Debug)]
85#[serde(rename_all = "camelCase")]
86pub struct Parameter {
87 pub name: String,
92
93 #[serde(rename = "in")]
95 pub parameter_in: ParameterIn,
96
97 #[serde(skip_serializing_if = "Option::is_none")]
99 pub description: Option<String>,
100
101 pub required: Required,
105
106 #[serde(skip_serializing_if = "Option::is_none")]
108 pub deprecated: Option<Deprecated>,
109 #[serde(skip_serializing_if = "Option::is_none")]
112 pub schema: Option<RefOr<Schema>>,
113
114 #[serde(skip_serializing_if = "Option::is_none")]
117 pub style: Option<ParameterStyle>,
118
119 #[serde(skip_serializing_if = "Option::is_none")]
132 pub explode: Option<bool>,
133
134 #[serde(skip_serializing_if = "Option::is_none")]
138 pub allow_reserved: Option<bool>,
139
140 #[serde(skip_serializing_if = "Option::is_none")]
143 example: Option<Value>,
144
145 #[serde(skip_serializing_if = "PropMap::is_empty", flatten)]
147 pub extensions: PropMap<String, serde_json::Value>,
148}
149
150impl Parameter {
151 #[must_use]
153 pub fn new<S: Into<String>>(name: S) -> Self {
154 Self {
155 name: name.into(),
156 required: Required::Unset,
157 ..Default::default()
158 }
159 }
160 #[must_use]
162 pub fn name<I: Into<String>>(mut self, name: I) -> Self {
163 self.name = name.into();
164 self
165 }
166
167 #[must_use]
169 pub fn parameter_in(mut self, parameter_in: ParameterIn) -> Self {
170 self.parameter_in = parameter_in;
171 if self.parameter_in == ParameterIn::Path {
172 self.required = Required::True;
173 }
174 self
175 }
176
177 pub fn merge(&mut self, other: Self) -> bool {
179 let Self {
180 name,
181 parameter_in,
182 description,
183 required,
184 deprecated,
185 schema,
186 style,
187 explode,
188 allow_reserved,
189 example,
190 extensions,
191 } = other;
192 if name != self.name || parameter_in != self.parameter_in {
193 return false;
194 }
195 if let Some(description) = description {
196 self.description = Some(description);
197 }
198
199 if required != Required::Unset {
200 self.required = required;
201 }
202
203 if let Some(deprecated) = deprecated {
204 self.deprecated = Some(deprecated);
205 }
206 if let Some(schema) = schema {
207 self.schema = Some(schema);
208 }
209 if let Some(style) = style {
210 self.style = Some(style);
211 }
212 if let Some(explode) = explode {
213 self.explode = Some(explode);
214 }
215 if let Some(allow_reserved) = allow_reserved {
216 self.allow_reserved = Some(allow_reserved);
217 }
218 if let Some(example) = example {
219 self.example = Some(example);
220 }
221
222 self.extensions.extend(extensions);
223 true
224 }
225
226 #[must_use]
229 pub fn required(mut self, required: impl Into<Required>) -> Self {
230 self.required = required.into();
231 if self.parameter_in == ParameterIn::Path {
233 self.required = Required::True;
234 }
235
236 self
237 }
238
239 #[must_use]
241 pub fn description<S: Into<String>>(mut self, description: S) -> Self {
242 self.description = Some(description.into());
243 self
244 }
245
246 #[must_use]
248 pub fn deprecated<D: Into<Deprecated>>(mut self, deprecated: D) -> Self {
249 self.deprecated = Some(deprecated.into());
250 self
251 }
252
253 #[must_use]
255 pub fn schema<I: Into<RefOr<Schema>>>(mut self, component: I) -> Self {
256 self.schema = Some(component.into());
257 self
258 }
259
260 #[must_use]
262 pub fn style(mut self, style: ParameterStyle) -> Self {
263 self.style = Some(style);
264 self
265 }
266
267 #[must_use]
269 pub fn explode(mut self, explode: bool) -> Self {
270 self.explode = Some(explode);
271 self
272 }
273
274 #[must_use]
276 pub fn allow_reserved(mut self, allow_reserved: bool) -> Self {
277 self.allow_reserved = Some(allow_reserved);
278 self
279 }
280
281 #[must_use]
283 pub fn example(mut self, example: Value) -> Self {
284 self.example = Some(example);
285 self
286 }
287}
288
289#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Copy, Debug)]
291#[serde(rename_all = "lowercase")]
292pub enum ParameterIn {
293 Query,
295 Path,
297 Header,
299 Cookie,
301}
302
303impl Default for ParameterIn {
304 fn default() -> Self {
305 Self::Path
306 }
307}
308
309#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
311#[serde(rename_all = "camelCase")]
312pub enum ParameterStyle {
313 Matrix,
317 Label,
321 Form,
325 Simple,
328 SpaceDelimited,
331 PipeDelimited,
334 DeepObject,
337}
338
339#[cfg(test)]
340mod tests {
341 use assert_json_diff::assert_json_eq;
342 use serde_json::json;
343
344 use crate::Object;
345
346 use super::*;
347
348 #[test]
349 fn test_build_parameter() {
350 let parameter = Parameter::new("name");
351 assert_eq!(parameter.name, "name");
352
353 let parameter = parameter
354 .name("new name")
355 .parameter_in(ParameterIn::Query)
356 .required(Required::True)
357 .description("description")
358 .deprecated(Deprecated::False)
359 .schema(Schema::object(Object::new()))
360 .style(ParameterStyle::Simple)
361 .explode(true)
362 .allow_reserved(true)
363 .example(Value::String("example".to_owned()));
364 assert_json_eq!(
365 parameter,
366 json!({
367 "name": "new name",
368 "in": "query",
369 "required": true,
370 "description": "description",
371 "deprecated": false,
372 "schema": {
373 "type": "object"
374 },
375 "style": "simple",
376 "explode": true,
377 "allowReserved": true,
378 "example": "example"
379 })
380 );
381 }
382
383 #[test]
384 fn test_parameter_merge_fail() {
385 let mut parameter1 = Parameter::new("param1");
386 let parameter2 = Parameter::new("param2");
387
388 assert!(!parameter1.merge(parameter2));
389 }
390
391 #[test]
392 fn test_parameter_merge_success() {
393 let mut parameter1 = Parameter::new("param1");
394 let mut parameter2 = Parameter::new("param1")
395 .description("description")
396 .required(Required::True)
397 .deprecated(Deprecated::True)
398 .schema(Schema::object(Object::new()))
399 .style(ParameterStyle::Form)
400 .explode(true)
401 .allow_reserved(true)
402 .example(Value::String("example".to_owned()));
403
404 parameter1.extensions =
405 PropMap::from([("key1".to_owned(), Value::String("value1".to_owned()))]);
406 parameter2.extensions =
407 PropMap::from([("key2".to_owned(), Value::String("value2".to_owned()))]);
408
409 assert!(parameter1.merge(parameter2));
410 assert_json_eq!(
411 parameter1,
412 json!({
413 "name": "param1",
414 "in": "path",
415 "description": "description",
416 "required": true,
417 "deprecated": true,
418 "schema": {
419 "type": "object"
420 },
421 "style": "form",
422 "explode": true,
423 "allowReserved": true,
424 "example": "example",
425 "key1": "value1",
426 "key2": "value2"
427 })
428 )
429 }
430
431 #[test]
432 fn test_parameter_merge_no_extensions() {
433 let mut parameter1 = Parameter::new("param1");
434 let mut parameter2 = Parameter::new("param1")
435 .description("description")
436 .required(Required::True)
437 .deprecated(Deprecated::True)
438 .schema(Schema::object(Object::new()))
439 .style(ParameterStyle::Form)
440 .explode(true)
441 .allow_reserved(true)
442 .example(Value::String("example".to_owned()));
443
444 parameter2.extensions =
445 PropMap::from([("key2".to_owned(), Value::String("value2".to_owned()))]);
446
447 assert!(parameter1.merge(parameter2));
448 assert_json_eq!(
449 parameter1,
450 json!({
451 "name": "param1",
452 "in": "path",
453 "description": "description",
454 "required": true,
455 "deprecated": true,
456 "schema": {
457 "type": "object"
458 },
459 "style": "form",
460 "explode": true,
461 "allowReserved": true,
462 "example": "example",
463 "key2": "value2",
464 })
465 )
466 }
467
468 #[test]
469 fn test_build_parameters() {
470 let parameters = Parameters::new();
471 assert!(parameters.is_empty());
472 }
473
474 #[test]
475 fn test_parameters_into_iter() {
476 let parameters = Parameters::new().parameter(Parameter::new("param"));
477 let mut iter = parameters.into_iter();
478 assert_eq!(iter.next(), Some(Parameter::new("param")));
479 assert!(iter.next().is_none());
480 }
481
482 #[test]
483 fn test_parameters_contain() {
484 let parameters = Parameters::new().parameter(Parameter::new("param"));
485 assert!(parameters.contains("param", ParameterIn::Path));
486 }
487
488 #[test]
489 fn test_parameters_insert_existed_item() {
490 let mut parameters = Parameters::new();
491 parameters.insert(Parameter::new("param"));
492 assert!(parameters.contains("param", ParameterIn::Path));
493
494 parameters.insert(Parameter::new("param"));
495 assert_eq!(parameters.0.len(), 1);
496 }
497
498 #[test]
499 fn test_parameters_append() {
500 let mut parameters1 = Parameters::new().parameter(Parameter::new("param1"));
501 let mut parameters2 = Parameters::new().parameter(Parameter::new("param2"));
502
503 parameters1.append(&mut parameters2);
504 assert_json_eq!(
505 parameters1,
506 json!([
507 {
508 "in": "path",
509 "name": "param1",
510 "required": false
511 },
512 {
513 "in": "path",
514 "name": "param2",
515 "required": false
516 }
517 ])
518 );
519 }
520}