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, Default, Copy, Debug)]
291#[serde(rename_all = "lowercase")]
292pub enum ParameterIn {
293 Query,
295 #[default]
297 Path,
298 Header,
300 Cookie,
302}
303
304#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
306#[serde(rename_all = "camelCase")]
307pub enum ParameterStyle {
308 Matrix,
312 Label,
316 Form,
320 Simple,
323 SpaceDelimited,
326 PipeDelimited,
329 DeepObject,
332}
333
334#[cfg(test)]
335mod tests {
336 use assert_json_diff::assert_json_eq;
337 use serde_json::json;
338
339 use crate::Object;
340
341 use super::*;
342
343 #[test]
344 fn test_build_parameter() {
345 let parameter = Parameter::new("name");
346 assert_eq!(parameter.name, "name");
347
348 let parameter = parameter
349 .name("new name")
350 .parameter_in(ParameterIn::Query)
351 .required(Required::True)
352 .description("description")
353 .deprecated(Deprecated::False)
354 .schema(Schema::object(Object::new()))
355 .style(ParameterStyle::Simple)
356 .explode(true)
357 .allow_reserved(true)
358 .example(Value::String("example".to_owned()));
359 assert_json_eq!(
360 parameter,
361 json!({
362 "name": "new name",
363 "in": "query",
364 "required": true,
365 "description": "description",
366 "deprecated": false,
367 "schema": {
368 "type": "object"
369 },
370 "style": "simple",
371 "explode": true,
372 "allowReserved": true,
373 "example": "example"
374 })
375 );
376 }
377
378 #[test]
379 fn test_parameter_merge_fail() {
380 let mut parameter1 = Parameter::new("param1");
381 let parameter2 = Parameter::new("param2");
382
383 assert!(!parameter1.merge(parameter2));
384 }
385
386 #[test]
387 fn test_parameter_merge_success() {
388 let mut parameter1 = Parameter::new("param1");
389 let mut parameter2 = Parameter::new("param1")
390 .description("description")
391 .required(Required::True)
392 .deprecated(Deprecated::True)
393 .schema(Schema::object(Object::new()))
394 .style(ParameterStyle::Form)
395 .explode(true)
396 .allow_reserved(true)
397 .example(Value::String("example".to_owned()));
398
399 parameter1.extensions =
400 PropMap::from([("key1".to_owned(), Value::String("value1".to_owned()))]);
401 parameter2.extensions =
402 PropMap::from([("key2".to_owned(), Value::String("value2".to_owned()))]);
403
404 assert!(parameter1.merge(parameter2));
405 assert_json_eq!(
406 parameter1,
407 json!({
408 "name": "param1",
409 "in": "path",
410 "description": "description",
411 "required": true,
412 "deprecated": true,
413 "schema": {
414 "type": "object"
415 },
416 "style": "form",
417 "explode": true,
418 "allowReserved": true,
419 "example": "example",
420 "key1": "value1",
421 "key2": "value2"
422 })
423 )
424 }
425
426 #[test]
427 fn test_parameter_merge_no_extensions() {
428 let mut parameter1 = Parameter::new("param1");
429 let mut parameter2 = Parameter::new("param1")
430 .description("description")
431 .required(Required::True)
432 .deprecated(Deprecated::True)
433 .schema(Schema::object(Object::new()))
434 .style(ParameterStyle::Form)
435 .explode(true)
436 .allow_reserved(true)
437 .example(Value::String("example".to_owned()));
438
439 parameter2.extensions =
440 PropMap::from([("key2".to_owned(), Value::String("value2".to_owned()))]);
441
442 assert!(parameter1.merge(parameter2));
443 assert_json_eq!(
444 parameter1,
445 json!({
446 "name": "param1",
447 "in": "path",
448 "description": "description",
449 "required": true,
450 "deprecated": true,
451 "schema": {
452 "type": "object"
453 },
454 "style": "form",
455 "explode": true,
456 "allowReserved": true,
457 "example": "example",
458 "key2": "value2",
459 })
460 )
461 }
462
463 #[test]
464 fn test_build_parameters() {
465 let parameters = Parameters::new();
466 assert!(parameters.is_empty());
467 }
468
469 #[test]
470 fn test_parameters_into_iter() {
471 let parameters = Parameters::new().parameter(Parameter::new("param"));
472 let mut iter = parameters.into_iter();
473 assert_eq!(iter.next(), Some(Parameter::new("param")));
474 assert!(iter.next().is_none());
475 }
476
477 #[test]
478 fn test_parameters_contain() {
479 let parameters = Parameters::new().parameter(Parameter::new("param"));
480 assert!(parameters.contains("param", ParameterIn::Path));
481 }
482
483 #[test]
484 fn test_parameters_insert_existed_item() {
485 let mut parameters = Parameters::new();
486 parameters.insert(Parameter::new("param"));
487 assert!(parameters.contains("param", ParameterIn::Path));
488
489 parameters.insert(Parameter::new("param"));
490 assert_eq!(parameters.0.len(), 1);
491 }
492
493 #[test]
494 fn test_parameters_append() {
495 let mut parameters1 = Parameters::new().parameter(Parameter::new("param1"));
496 let mut parameters2 = Parameters::new().parameter(Parameter::new("param2"));
497
498 parameters1.append(&mut parameters2);
499 assert_json_eq!(
500 parameters1,
501 json!([
502 {
503 "in": "path",
504 "name": "param1",
505 "required": false
506 },
507 {
508 "in": "path",
509 "name": "param2",
510 "required": false
511 }
512 ])
513 );
514 }
515}