1use std::str::FromStr;
2
3use crate::*;
4use indexmap::IndexMap;
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
8#[serde(rename_all = "camelCase")]
9pub struct SchemaData {
10 #[serde(default, skip_serializing_if = "is_false")]
11 pub nullable: bool,
12 #[serde(default, skip_serializing_if = "is_false")]
13 pub read_only: bool,
14 #[serde(default, skip_serializing_if = "is_false")]
15 pub write_only: bool,
16 #[serde(default, skip_serializing_if = "is_false")]
17 pub deprecated: bool,
18 #[serde(skip_serializing_if = "Option::is_none")]
19 pub external_docs: Option<ExternalDocumentation>,
20 #[serde(skip_serializing_if = "Option::is_none")]
21 pub example: Option<serde_json::Value>,
22 #[serde(skip_serializing_if = "Option::is_none")]
23 pub title: Option<String>,
24 #[serde(skip_serializing_if = "Option::is_none")]
25 pub description: Option<String>,
26 #[serde(skip_serializing_if = "Option::is_none")]
27 pub discriminator: Option<Discriminator>,
28 #[serde(skip_serializing_if = "Option::is_none")]
29 pub default: Option<serde_json::Value>,
30 #[serde(flatten, deserialize_with = "crate::util::deserialize_extensions")]
32 pub extensions: IndexMap<String, serde_json::Value>,
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
36pub struct Schema {
37 #[serde(flatten)]
38 pub schema_data: SchemaData,
39 #[serde(flatten)]
40 pub schema_kind: SchemaKind,
41}
42
43#[derive(Debug, Clone, Serialize, PartialEq)]
44#[serde(untagged)]
45pub enum SchemaKind {
46 Type(Type),
47 OneOf {
48 #[serde(rename = "oneOf")]
49 one_of: Vec<ReferenceOr<Schema>>,
50 },
51 AllOf {
52 #[serde(rename = "allOf")]
53 all_of: Vec<ReferenceOr<Schema>>,
54 },
55 AnyOf {
56 #[serde(rename = "anyOf")]
57 any_of: Vec<ReferenceOr<Schema>>,
58 },
59 Not {
60 not: Box<ReferenceOr<Schema>>,
61 },
62 Any(AnySchema),
63}
64
65impl<'de> Deserialize<'de> for SchemaKind {
72 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
73 where
74 D: serde::Deserializer<'de>,
75 {
76 #[derive(Deserialize)]
77 #[serde(rename_all = "camelCase")]
78 struct RawAnySchema {
79 #[serde(rename = "type", default)]
80 typ: Option<String>,
81 #[serde(default)]
82 pattern: Option<String>,
83 #[serde(default)]
84 multiple_of: Option<serde_json::Number>,
85 #[serde(default)]
86 exclusive_minimum: Option<bool>,
87 #[serde(default)]
88 exclusive_maximum: Option<bool>,
89 #[serde(default)]
90 minimum: Option<serde_json::Number>,
91 #[serde(default)]
92 maximum: Option<serde_json::Number>,
93 #[serde(default)]
94 properties: Option<IndexMap<String, ReferenceOr<Box<Schema>>>>,
95 #[serde(default)]
96 required: Option<Vec<String>>,
97 #[serde(default)]
98 additional_properties: Option<AdditionalProperties>,
99 #[serde(default)]
100 min_properties: Option<usize>,
101 #[serde(default)]
102 max_properties: Option<usize>,
103 #[serde(default)]
104 items: Option<ReferenceOr<Box<Schema>>>,
105 #[serde(default)]
106 min_items: Option<usize>,
107 #[serde(default)]
108 max_items: Option<usize>,
109 #[serde(default)]
110 unique_items: Option<bool>,
111 #[serde(rename = "enum", default)]
112 enumeration: Option<Vec<serde_json::Value>>,
113 #[serde(default)]
114 format: Option<String>,
115 #[serde(default)]
116 min_length: Option<usize>,
117 #[serde(default)]
118 max_length: Option<usize>,
119 #[serde(default)]
120 one_of: Option<Vec<ReferenceOr<Schema>>>,
121 #[serde(default)]
122 all_of: Option<Vec<ReferenceOr<Schema>>>,
123 #[serde(default)]
124 any_of: Option<Vec<ReferenceOr<Schema>>>,
125 #[serde(default)]
126 not: Option<Box<ReferenceOr<Schema>>>,
127 }
128
129 let any = RawAnySchema::deserialize(deserializer)?;
130 match any {
131 RawAnySchema {
133 typ: Some(typ),
134 pattern,
135 multiple_of: None,
136 exclusive_minimum: None,
137 exclusive_maximum: None,
138 minimum: None,
139 maximum: None,
140 properties: None,
141 required: None,
142 additional_properties: None,
143 min_properties: None,
144 max_properties: None,
145 items: None,
146 min_items: None,
147 max_items: None,
148 unique_items: None,
149 enumeration,
150 format,
151 min_length,
152 max_length,
153 one_of: None,
154 all_of: None,
155 any_of: None,
156 not: None,
157 } if typ == "string"
158 && enumerated_values_valid(&enumeration, serde_json::Value::is_string) =>
159 {
160 Ok(Self::Type(Type::String(StringType {
161 format: format.into(),
162 pattern,
163 enumeration: enumerated_values_transform(enumeration, |v| {
164 v.as_str().map(String::from)
165 }),
166 min_length,
167 max_length,
168 })))
169 }
170
171 RawAnySchema {
173 typ: Some(typ),
174 pattern: None,
175 multiple_of,
176 exclusive_minimum,
177 exclusive_maximum,
178 minimum,
179 maximum,
180 properties: None,
181 required: None,
182 additional_properties: None,
183 min_properties: None,
184 max_properties: None,
185 items: None,
186 min_items: None,
187 max_items: None,
188 unique_items: None,
189 enumeration,
190 format,
191 min_length: None,
192 max_length: None,
193 one_of: None,
194 all_of: None,
195 any_of: None,
196 not: None,
197 } if typ == "number"
198 && enumerated_values_valid(&enumeration, serde_json::Value::is_number) =>
199 {
200 Ok(Self::Type(Type::Number(NumberType {
201 format: format.into(),
202 multiple_of: multiple_of.map(|v| v.as_f64().unwrap()),
203 exclusive_minimum: exclusive_minimum.unwrap_or_default(),
204 exclusive_maximum: exclusive_maximum.unwrap_or_default(),
205 minimum: minimum.map(|v| v.as_f64().unwrap()),
206 maximum: maximum.map(|v| v.as_f64().unwrap()),
207 enumeration: enumerated_values_transform(
208 enumeration,
209 serde_json::Value::as_f64,
210 ),
211 })))
212 }
213
214 RawAnySchema {
216 typ: Some(typ),
217 pattern: None,
218 multiple_of,
219 exclusive_minimum,
220 exclusive_maximum,
221 minimum,
222 maximum,
223 properties: None,
224 required: None,
225 additional_properties: None,
226 min_properties: None,
227 max_properties: None,
228 items: None,
229 min_items: None,
230 max_items: None,
231 unique_items: None,
232 enumeration,
233 format,
234 min_length: None,
235 max_length: None,
236 one_of: None,
237 all_of: None,
238 any_of: None,
239 not: None,
240 } if typ == "integer"
241 && enumerated_values_valid(&enumeration, serde_json::Value::is_i64)
242 && none_or_int(&multiple_of)
243 && none_or_int(&minimum)
244 && none_or_int(&maximum) =>
245 {
246 Ok(Self::Type(Type::Integer(IntegerType {
247 format: format.into(),
248 multiple_of: multiple_of.map(|v| v.as_i64().unwrap()),
249 exclusive_minimum: exclusive_minimum.unwrap_or_default(),
250 exclusive_maximum: exclusive_maximum.unwrap_or_default(),
251 minimum: minimum.map(|v| v.as_i64().unwrap()),
252 maximum: maximum.map(|v| v.as_i64().unwrap()),
253 enumeration: enumerated_values_transform(
254 enumeration,
255 serde_json::Value::as_i64,
256 ),
257 })))
258 }
259
260 RawAnySchema {
262 typ: Some(typ),
263 pattern: None,
264 multiple_of: None,
265 exclusive_minimum: None,
266 exclusive_maximum: None,
267 minimum: None,
268 maximum: None,
269 properties: None,
270 required: None,
271 additional_properties: None,
272 min_properties: None,
273 max_properties: None,
274 items: None,
275 min_items: None,
276 max_items: None,
277 unique_items: None,
278 enumeration,
279 format: None,
280 min_length: None,
281 max_length: None,
282 one_of: None,
283 all_of: None,
284 any_of: None,
285 not: None,
286 } if typ == "boolean"
287 && enumerated_values_valid(&enumeration, serde_json::Value::is_boolean) =>
288 {
289 Ok(Self::Type(Type::Boolean(BooleanType {
290 enumeration: enumerated_values_transform(
291 enumeration,
292 serde_json::Value::as_bool,
293 ),
294 })))
295 }
296
297 RawAnySchema {
299 typ: Some(typ),
300 pattern: None,
301 multiple_of: None,
302 exclusive_minimum: None,
303 exclusive_maximum: None,
304 minimum: None,
305 maximum: None,
306 properties,
307 required,
308 additional_properties,
309 min_properties,
310 max_properties,
311 items: None,
312 min_items: None,
313 max_items: None,
314 unique_items: None,
315 enumeration: None,
316 format: None,
317 min_length: None,
318 max_length: None,
319 one_of: None,
320 all_of: None,
321 any_of: None,
322 not: None,
323 } if typ == "object" => Ok(Self::Type(Type::Object(ObjectType {
324 properties: properties.unwrap_or_default(),
325 required: required.unwrap_or_default(),
326 additional_properties,
327 min_properties,
328 max_properties,
329 }))),
330
331 RawAnySchema {
333 typ: Some(typ),
334 pattern: None,
335 multiple_of: None,
336 exclusive_minimum: None,
337 exclusive_maximum: None,
338 minimum: None,
339 maximum: None,
340 properties: None,
341 required: None,
342 additional_properties: None,
343 min_properties: None,
344 max_properties: None,
345 items,
346 min_items,
347 max_items,
348 unique_items,
349 enumeration: None,
350 format: None,
351 min_length: None,
352 max_length: None,
353 one_of: None,
354 all_of: None,
355 any_of: None,
356 not: None,
357 } if typ == "array" => Ok(Self::Type(Type::Array(ArrayType {
358 items,
359 min_items,
360 max_items,
361 unique_items: unique_items.unwrap_or_default(),
362 }))),
363
364 RawAnySchema {
366 typ: None,
367 pattern: None,
368 multiple_of: None,
369 exclusive_minimum: None,
370 exclusive_maximum: None,
371 minimum: None,
372 maximum: None,
373 properties: None,
374 required: None,
375 additional_properties: None,
376 min_properties: None,
377 max_properties: None,
378 items: None,
379 min_items: None,
380 max_items: None,
381 unique_items: None,
382 enumeration: None,
383 format: None,
384 min_length: None,
385 max_length: None,
386 one_of: Some(one_of),
387 all_of: None,
388 any_of: None,
389 not: None,
390 } => Ok(Self::OneOf { one_of }),
391
392 RawAnySchema {
394 typ: None,
395 pattern: None,
396 multiple_of: None,
397 exclusive_minimum: None,
398 exclusive_maximum: None,
399 minimum: None,
400 maximum: None,
401 properties: None,
402 required: None,
403 additional_properties: None,
404 min_properties: None,
405 max_properties: None,
406 items: None,
407 min_items: None,
408 max_items: None,
409 unique_items: None,
410 enumeration: None,
411 format: None,
412 min_length: None,
413 max_length: None,
414 one_of: None,
415 all_of: Some(all_of),
416 any_of: None,
417 not: None,
418 } => Ok(Self::AllOf { all_of }),
419
420 RawAnySchema {
422 typ: None,
423 pattern: None,
424 multiple_of: None,
425 exclusive_minimum: None,
426 exclusive_maximum: None,
427 minimum: None,
428 maximum: None,
429 properties: None,
430 required: None,
431 additional_properties: None,
432 min_properties: None,
433 max_properties: None,
434 items: None,
435 min_items: None,
436 max_items: None,
437 unique_items: None,
438 enumeration: None,
439 format: None,
440 min_length: None,
441 max_length: None,
442 one_of: None,
443 all_of: None,
444 any_of: Some(any_of),
445 not: None,
446 } => Ok(Self::AnyOf { any_of }),
447
448 RawAnySchema {
450 typ: None,
451 pattern: None,
452 multiple_of: None,
453 exclusive_minimum: None,
454 exclusive_maximum: None,
455 minimum: None,
456 maximum: None,
457 properties: None,
458 required: None,
459 additional_properties: None,
460 min_properties: None,
461 max_properties: None,
462 items: None,
463 min_items: None,
464 max_items: None,
465 unique_items: None,
466 enumeration: None,
467 format: None,
468 min_length: None,
469 max_length: None,
470 one_of: None,
471 all_of: None,
472 any_of: None,
473 not: Some(not),
474 } => Ok(Self::Not { not }),
475
476 RawAnySchema {
478 typ,
479 pattern,
480 multiple_of,
481 exclusive_minimum,
482 exclusive_maximum,
483 minimum,
484 maximum,
485 properties,
486 required,
487 additional_properties,
488 min_properties,
489 max_properties,
490 items,
491 min_items,
492 max_items,
493 unique_items,
494 enumeration,
495 format,
496 min_length,
497 max_length,
498 one_of,
499 all_of,
500 any_of,
501 not,
502 } => Ok(Self::Any(AnySchema {
503 typ,
504 pattern,
505 multiple_of: multiple_of.map(|n| n.as_f64().unwrap()),
506 exclusive_minimum,
507 exclusive_maximum,
508 minimum: minimum.map(|n| n.as_f64().unwrap()),
509 maximum: maximum.map(|n| n.as_f64().unwrap()),
510 properties: properties.unwrap_or_default(),
511 required: required.unwrap_or_default(),
512 additional_properties,
513 min_properties,
514 max_properties,
515 items,
516 min_items,
517 max_items,
518 unique_items,
519 enumeration: enumeration.unwrap_or_default(),
520 format,
521 min_length,
522 max_length,
523 one_of: one_of.unwrap_or_default(),
524 all_of: all_of.unwrap_or_default(),
525 any_of: any_of.unwrap_or_default(),
526 not,
527 })),
528 }
529 }
530}
531
532fn none_or_int(value: &Option<serde_json::Number>) -> bool {
533 match value {
534 None => true,
535 Some(x) => x.is_i64(),
536 }
537}
538
539fn enumerated_values_transform<T, F>(
540 enumeration: Option<Vec<serde_json::Value>>,
541 transform: F,
542) -> Vec<Option<T>>
543where
544 F: Fn(&serde_json::Value) -> Option<T>,
545{
546 match enumeration {
547 Some(values) => values
548 .iter()
549 .map(|v| {
550 if v.is_null() {
551 None
552 } else {
553 Some(transform(v).unwrap())
554 }
555 })
556 .collect::<Vec<_>>(),
557 None => Default::default(),
558 }
559}
560
561fn enumerated_values_valid<F>(enumeration: &Option<Vec<serde_json::Value>>, check: F) -> bool
562where
563 F: Fn(&serde_json::Value) -> bool,
564{
565 match enumeration {
566 Some(values) => values.iter().all(|value| value.is_null() || check(value)),
567 None => true,
568 }
569}
570
571#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
572#[serde(tag = "type", rename_all = "lowercase")]
573pub enum Type {
574 String(StringType),
575 Number(NumberType),
576 Integer(IntegerType),
577 Object(ObjectType),
578 Array(ArrayType),
579 Boolean(BooleanType),
580}
581
582#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
583#[serde(untagged)]
584pub enum AdditionalProperties {
585 Any(bool),
586 Schema(Box<ReferenceOr<Schema>>),
587}
588
589#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
592#[serde(rename_all = "camelCase")]
593pub struct AnySchema {
594 #[serde(rename = "type", default, skip_serializing_if = "Option::is_none")]
595 pub typ: Option<String>,
596 #[serde(default, skip_serializing_if = "Option::is_none")]
597 pub pattern: Option<String>,
598 #[serde(default, skip_serializing_if = "Option::is_none")]
599 pub multiple_of: Option<f64>,
600 #[serde(default, skip_serializing_if = "Option::is_none")]
601 pub exclusive_minimum: Option<bool>,
602 #[serde(default, skip_serializing_if = "Option::is_none")]
603 pub exclusive_maximum: Option<bool>,
604 #[serde(default, skip_serializing_if = "Option::is_none")]
605 pub minimum: Option<f64>,
606 #[serde(default, skip_serializing_if = "Option::is_none")]
607 pub maximum: Option<f64>,
608 #[serde(default, skip_serializing_if = "IndexMap::is_empty")]
609 pub properties: IndexMap<String, ReferenceOr<Box<Schema>>>,
610 #[serde(default, skip_serializing_if = "Vec::is_empty")]
611 pub required: Vec<String>,
612 #[serde(default, skip_serializing_if = "Option::is_none")]
613 pub additional_properties: Option<AdditionalProperties>,
614 #[serde(default, skip_serializing_if = "Option::is_none")]
615 pub min_properties: Option<usize>,
616 #[serde(default, skip_serializing_if = "Option::is_none")]
617 pub max_properties: Option<usize>,
618 #[serde(default, skip_serializing_if = "Option::is_none")]
619 pub items: Option<ReferenceOr<Box<Schema>>>,
620 #[serde(default, skip_serializing_if = "Option::is_none")]
621 pub min_items: Option<usize>,
622 #[serde(default, skip_serializing_if = "Option::is_none")]
623 pub max_items: Option<usize>,
624 #[serde(default, skip_serializing_if = "Option::is_none")]
625 pub unique_items: Option<bool>,
626 #[serde(rename = "enum", default, skip_serializing_if = "Vec::is_empty")]
627 pub enumeration: Vec<serde_json::Value>,
628 #[serde(default, skip_serializing_if = "Option::is_none")]
629 pub format: Option<String>,
630 #[serde(default, skip_serializing_if = "Option::is_none")]
631 pub min_length: Option<usize>,
632 #[serde(default, skip_serializing_if = "Option::is_none")]
633 pub max_length: Option<usize>,
634 #[serde(default, skip_serializing_if = "Vec::is_empty")]
635 pub one_of: Vec<ReferenceOr<Schema>>,
636 #[serde(default, skip_serializing_if = "Vec::is_empty")]
637 pub all_of: Vec<ReferenceOr<Schema>>,
638 #[serde(default, skip_serializing_if = "Vec::is_empty")]
639 pub any_of: Vec<ReferenceOr<Schema>>,
640 #[serde(default, skip_serializing_if = "Option::is_none")]
641 pub not: Option<Box<ReferenceOr<Schema>>>,
642}
643
644#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
645#[serde(rename_all = "camelCase")]
646pub struct StringType {
647 #[serde(default, skip_serializing_if = "VariantOrUnknownOrEmpty::is_empty")]
648 pub format: VariantOrUnknownOrEmpty<StringFormat>,
649 #[serde(skip_serializing_if = "Option::is_none")]
650 pub pattern: Option<String>,
651 #[serde(rename = "enum", default, skip_serializing_if = "Vec::is_empty")]
652 pub enumeration: Vec<Option<String>>,
653 #[serde(skip_serializing_if = "Option::is_none")]
654 pub min_length: Option<usize>,
655 #[serde(skip_serializing_if = "Option::is_none")]
656 pub max_length: Option<usize>,
657}
658
659#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
660#[serde(rename_all = "camelCase")]
661pub struct NumberType {
662 #[serde(default, skip_serializing_if = "VariantOrUnknownOrEmpty::is_empty")]
663 pub format: VariantOrUnknownOrEmpty<NumberFormat>,
664 #[serde(skip_serializing_if = "Option::is_none")]
665 pub multiple_of: Option<f64>,
666 #[serde(default, skip_serializing_if = "is_false")]
667 pub exclusive_minimum: bool,
668 #[serde(default, skip_serializing_if = "is_false")]
669 pub exclusive_maximum: bool,
670 #[serde(skip_serializing_if = "Option::is_none")]
671 pub minimum: Option<f64>,
672 #[serde(skip_serializing_if = "Option::is_none")]
673 pub maximum: Option<f64>,
674 #[serde(rename = "enum", default, skip_serializing_if = "Vec::is_empty")]
675 pub enumeration: Vec<Option<f64>>,
676}
677
678#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
679#[serde(rename_all = "camelCase")]
680pub struct IntegerType {
681 #[serde(default, skip_serializing_if = "VariantOrUnknownOrEmpty::is_empty")]
682 pub format: VariantOrUnknownOrEmpty<IntegerFormat>,
683 #[serde(skip_serializing_if = "Option::is_none")]
684 pub multiple_of: Option<i64>,
685 #[serde(default, skip_serializing_if = "is_false")]
686 pub exclusive_minimum: bool,
687 #[serde(default, skip_serializing_if = "is_false")]
688 pub exclusive_maximum: bool,
689 #[serde(skip_serializing_if = "Option::is_none")]
690 pub minimum: Option<i64>,
691 #[serde(skip_serializing_if = "Option::is_none")]
692 pub maximum: Option<i64>,
693 #[serde(rename = "enum", default, skip_serializing_if = "Vec::is_empty")]
694 pub enumeration: Vec<Option<i64>>,
695}
696
697#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
698#[serde(rename_all = "camelCase")]
699pub struct ObjectType {
700 #[serde(default, skip_serializing_if = "IndexMap::is_empty")]
701 pub properties: IndexMap<String, ReferenceOr<Box<Schema>>>,
702 #[serde(default, skip_serializing_if = "Vec::is_empty")]
703 pub required: Vec<String>,
704 #[serde(skip_serializing_if = "Option::is_none")]
705 pub additional_properties: Option<AdditionalProperties>,
706 #[serde(skip_serializing_if = "Option::is_none")]
707 pub min_properties: Option<usize>,
708 #[serde(skip_serializing_if = "Option::is_none")]
709 pub max_properties: Option<usize>,
710}
711
712#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
713#[serde(rename_all = "camelCase")]
714pub struct ArrayType {
715 #[serde(skip_serializing_if = "Option::is_none")]
716 pub items: Option<ReferenceOr<Box<Schema>>>,
717 #[serde(skip_serializing_if = "Option::is_none")]
718 pub min_items: Option<usize>,
719 #[serde(skip_serializing_if = "Option::is_none")]
720 pub max_items: Option<usize>,
721 #[serde(default, skip_serializing_if = "is_false")]
722 pub unique_items: bool,
723}
724
725#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
726#[serde(rename_all = "camelCase")]
727pub struct BooleanType {
728 #[serde(rename = "enum", default, skip_serializing_if = "Vec::is_empty")]
729 pub enumeration: Vec<Option<bool>>,
730}
731
732#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
733#[serde(rename_all = "lowercase")]
734pub enum NumberFormat {
735 Float,
736 Double,
737}
738
739impl FromStr for NumberFormat {
740 type Err = ();
741
742 fn from_str(s: &str) -> Result<Self, Self::Err> {
743 match s {
744 "float" => Ok(Self::Float),
745 "double" => Ok(Self::Double),
746 _ => Err(()),
747 }
748 }
749}
750
751#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
752#[serde(rename_all = "lowercase")]
753pub enum IntegerFormat {
754 Int32,
755 Int64,
756}
757
758impl FromStr for IntegerFormat {
759 type Err = ();
760
761 fn from_str(s: &str) -> Result<Self, Self::Err> {
762 match s {
763 "int32" => Ok(Self::Int32),
764 "int64" => Ok(Self::Int64),
765 _ => Err(()),
766 }
767 }
768}
769
770#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
771#[serde(rename_all = "kebab-case")]
772pub enum StringFormat {
773 Date,
774 DateTime,
775 Password,
776 Byte,
777 Binary,
778}
779
780impl FromStr for StringFormat {
781 type Err = ();
782
783 fn from_str(s: &str) -> Result<Self, Self::Err> {
784 match s {
785 "date" => Ok(Self::Date),
786 "date-time" => Ok(Self::DateTime),
787 "password" => Ok(Self::Password),
788 "byte" => Ok(Self::Byte),
789 "binary" => Ok(Self::Binary),
790 _ => Err(()),
791 }
792 }
793}
794
795#[cfg(test)]
796mod tests {
797 use serde_json::json;
798
799 use crate::{
800 AnySchema, Schema, SchemaData, SchemaKind, StringType, Type, VariantOrUnknownOrEmpty,
801 };
802
803 #[test]
804 fn test_schema_with_extensions() {
805 let schema = serde_json::from_str::<Schema>(
806 r#"{
807 "type": "boolean",
808 "x-foo": "bar"
809 }"#,
810 )
811 .unwrap();
812
813 assert_eq!(
814 schema.schema_data.extensions.get("x-foo"),
815 Some(&json!("bar"))
816 );
817 }
818
819 #[test]
820 fn test_any() {
821 let value = json! { {} };
822 serde_json::from_value::<AnySchema>(value).unwrap();
823 }
824
825 #[test]
826 fn test_not() {
827 let value = json! {
828 {
829 "not": {}
830 }
831 };
832
833 let schema = serde_json::from_value::<Schema>(value).unwrap();
834 assert!(matches!(schema.schema_kind, SchemaKind::Not { not: _ }));
835 }
836
837 #[test]
838 fn test_null() {
839 let value = json! {
840 {
841 "nullable": true,
842 "enum": [ null ],
843 }
844 };
845
846 let schema = serde_json::from_value::<Schema>(value).unwrap();
847 assert!(matches!(
848 &schema.schema_data,
849 SchemaData { nullable: true, .. }
850 ));
851 assert!(matches!(
852 &schema.schema_kind,
853 SchemaKind::Any(AnySchema { enumeration, .. }) if enumeration[0] == json!(null)));
854 }
855
856 #[test]
857 fn test_object_and_one_of() {
858 let value = json! {
859 {
860 "type": "object",
861 "nullable": true,
862 "description": "xyz",
863 "properties": {
864 "a": {},
865 "b": {},
866 "c": {}
867 },
868 "oneOf": [
869 { "required": ["a"] },
870 { "required": ["b"] },
871 { "required": ["c"] }
872 ],
873 "x-foo": "bar"
874 }
875 };
876
877 let schema = serde_json::from_value::<Schema>(value).unwrap();
878 assert!(schema.schema_data.nullable);
879 assert_eq!(schema.schema_data.extensions.get("x-foo").unwrap(), "bar");
880
881 match schema.schema_kind {
882 SchemaKind::Any(AnySchema {
883 typ,
884 properties,
885 one_of,
886 ..
887 }) => {
888 assert_eq!(typ.unwrap(), "object");
889 assert_eq!(properties.len(), 3);
890 assert_eq!(one_of.len(), 3);
891 }
892 _ => panic!("incorrect kind {:#?}", schema),
893 }
894 }
895
896 #[test]
897 fn test_enum_with_null() {
898 let value = json! {
899 {
900 "type": "string",
901 "nullable": true,
902 "enum": [ null, "howdy" ]
903 }
904 };
905
906 let schema = serde_json::from_value::<Schema>(value).unwrap();
907 assert!(schema.schema_data.nullable);
908
909 match schema.schema_kind {
910 SchemaKind::Type(Type::String(StringType {
911 format: VariantOrUnknownOrEmpty::Empty,
912 pattern: None,
913 enumeration,
914 min_length: None,
915 max_length: None,
916 })) => {
917 assert_eq!(enumeration, vec![None, Some("howdy".to_string())]);
918 }
919 _ => panic!("incorrect kind {:#?}", schema),
920 }
921 }
922}