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