utoipa/openapi/
schema.rs

1//! Implements [OpenAPI Schema Object][schema] types which can be
2//! used to define field properties, enum values, array or object types.
3//!
4//! [schema]: https://spec.openapis.org/oas/latest.html#schema-object
5use std::collections::BTreeMap;
6
7use serde::{Deserialize, Serialize};
8use serde_json::Value;
9
10use super::extensions::Extensions;
11use super::RefOr;
12use super::{builder, security::SecurityScheme, set_value, xml::Xml, Deprecated, Response};
13use crate::{ToResponse, ToSchema};
14
15macro_rules! component_from_builder {
16    ( $name:ident ) => {
17        impl From<$name> for Schema {
18            fn from(builder: $name) -> Self {
19                builder.build().into()
20            }
21        }
22    };
23}
24
25macro_rules! to_array_builder {
26    () => {
27        /// Construct a new [`ArrayBuilder`] with this component set to [`ArrayBuilder::items`].
28        pub fn to_array_builder(self) -> ArrayBuilder {
29            ArrayBuilder::from(Array::new(self))
30        }
31    };
32}
33
34/// Create an _`empty`_ [`Schema`] that serializes to _`null`_.
35///
36/// Can be used in places where an item can be serialized as `null`. This is used with unit type
37/// enum variants and tuple unit types.
38pub fn empty() -> Schema {
39    Schema::Object(
40        ObjectBuilder::new()
41            .schema_type(SchemaType::AnyValue)
42            .default(Some(serde_json::Value::Null))
43            .into(),
44    )
45}
46
47builder! {
48    ComponentsBuilder;
49
50    /// Implements [OpenAPI Components Object][components] which holds supported
51    /// reusable objects.
52    ///
53    /// Components can hold either reusable types themselves or references to other reusable
54    /// types.
55    ///
56    /// [components]: https://spec.openapis.org/oas/latest.html#components-object
57    #[non_exhaustive]
58    #[derive(Serialize, Deserialize, Default, Clone, PartialEq)]
59    #[cfg_attr(feature = "debug", derive(Debug))]
60    #[serde(rename_all = "camelCase")]
61    pub struct Components {
62        /// Map of reusable [OpenAPI Schema Object][schema]s.
63        ///
64        /// [schema]: https://spec.openapis.org/oas/latest.html#schema-object
65        #[serde(skip_serializing_if = "BTreeMap::is_empty", default)]
66        pub schemas: BTreeMap<String, RefOr<Schema>>,
67
68        /// Map of reusable response name, to [OpenAPI Response Object][response]s or [OpenAPI
69        /// Reference][reference]s to [OpenAPI Response Object][response]s.
70        ///
71        /// [response]: https://spec.openapis.org/oas/latest.html#response-object
72        /// [reference]: https://spec.openapis.org/oas/latest.html#reference-object
73        #[serde(skip_serializing_if = "BTreeMap::is_empty", default)]
74        pub responses: BTreeMap<String, RefOr<Response>>,
75
76        /// Map of reusable [OpenAPI Security Scheme Object][security_scheme]s.
77        ///
78        /// [security_scheme]: https://spec.openapis.org/oas/latest.html#security-scheme-object
79        #[serde(skip_serializing_if = "BTreeMap::is_empty", default)]
80        pub security_schemes: BTreeMap<String, SecurityScheme>,
81
82        /// Optional extensions "x-something".
83        #[serde(skip_serializing_if = "Option::is_none", flatten)]
84        pub extensions: Option<Extensions>,
85    }
86}
87
88impl Components {
89    /// Construct a new [`Components`].
90    pub fn new() -> Self {
91        Self {
92            ..Default::default()
93        }
94    }
95    /// Add [`SecurityScheme`] to [`Components`].
96    ///
97    /// Accepts two arguments where first is the name of the [`SecurityScheme`]. This is later when
98    /// referenced by [`SecurityRequirement`][requirement]s. Second parameter is the [`SecurityScheme`].
99    ///
100    /// [requirement]: ../security/struct.SecurityRequirement.html
101    pub fn add_security_scheme<N: Into<String>, S: Into<SecurityScheme>>(
102        &mut self,
103        name: N,
104        security_scheme: S,
105    ) {
106        self.security_schemes
107            .insert(name.into(), security_scheme.into());
108    }
109
110    /// Add iterator of [`SecurityScheme`]s to [`Components`].
111    ///
112    /// Accepts two arguments where first is the name of the [`SecurityScheme`]. This is later when
113    /// referenced by [`SecurityRequirement`][requirement]s. Second parameter is the [`SecurityScheme`].
114    ///
115    /// [requirement]: ../security/struct.SecurityRequirement.html
116    pub fn add_security_schemes_from_iter<
117        I: IntoIterator<Item = (N, S)>,
118        N: Into<String>,
119        S: Into<SecurityScheme>,
120    >(
121        &mut self,
122        schemas: I,
123    ) {
124        self.security_schemes.extend(
125            schemas
126                .into_iter()
127                .map(|(name, item)| (name.into(), item.into())),
128        );
129    }
130}
131
132impl ComponentsBuilder {
133    /// Add [`Schema`] to [`Components`].
134    ///
135    /// Accepts two arguments where first is name of the schema and second is the schema itself.
136    pub fn schema<S: Into<String>, I: Into<RefOr<Schema>>>(mut self, name: S, schema: I) -> Self {
137        self.schemas.insert(name.into(), schema.into());
138
139        self
140    }
141
142    /// Add [`Schema`] to [`Components`].
143    ///
144    /// This is effectively same as calling [`ComponentsBuilder::schema`] but expects to be called
145    /// with one generic argument that implements [`ToSchema`][trait@ToSchema] trait.
146    ///
147    /// # Examples
148    ///
149    /// _**Add schema from `Value` type that derives `ToSchema`.**_
150    ///
151    /// ```rust
152    /// # use utoipa::{ToSchema, openapi::schema::ComponentsBuilder};
153    ///  #[derive(ToSchema)]
154    ///  struct Value(String);
155    ///
156    ///  let _ = ComponentsBuilder::new().schema_from::<Value>().build();
157    /// ```
158    pub fn schema_from<I: ToSchema>(mut self) -> Self {
159        let name = I::name();
160        let schema = I::schema();
161        self.schemas.insert(name.to_string(), schema);
162
163        self
164    }
165
166    /// Add [`Schema`]s from iterator.
167    ///
168    /// # Examples
169    /// ```rust
170    /// # use utoipa::openapi::schema::{ComponentsBuilder, ObjectBuilder,
171    /// #    Type, Schema};
172    /// ComponentsBuilder::new().schemas_from_iter([(
173    ///     "Pet",
174    ///     Schema::from(
175    ///         ObjectBuilder::new()
176    ///             .property(
177    ///                 "name",
178    ///                 ObjectBuilder::new().schema_type(Type::String),
179    ///             )
180    ///             .required("name")
181    ///     ),
182    /// )]);
183    /// ```
184    pub fn schemas_from_iter<
185        I: IntoIterator<Item = (S, C)>,
186        C: Into<RefOr<Schema>>,
187        S: Into<String>,
188    >(
189        mut self,
190        schemas: I,
191    ) -> Self {
192        self.schemas.extend(
193            schemas
194                .into_iter()
195                .map(|(name, schema)| (name.into(), schema.into())),
196        );
197
198        self
199    }
200
201    /// Add [`struct@Response`] to [`Components`].
202    ///
203    /// Method accepts tow arguments; `name` of the reusable response and `response` which is the
204    /// reusable response itself.
205    pub fn response<S: Into<String>, R: Into<RefOr<Response>>>(
206        mut self,
207        name: S,
208        response: R,
209    ) -> Self {
210        self.responses.insert(name.into(), response.into());
211        self
212    }
213
214    /// Add [`struct@Response`] to [`Components`].
215    ///
216    /// This behaves the same way as [`ComponentsBuilder::schema_from`] but for responses. It
217    /// allows adding response from type implementing [`trait@ToResponse`] trait. Method is
218    /// expected to be called with one generic argument that implements the trait.
219    pub fn response_from<'r, I: ToResponse<'r>>(self) -> Self {
220        let (name, response) = I::response();
221        self.response(name, response)
222    }
223
224    /// Add multiple [`struct@Response`]s to [`Components`] from iterator.
225    ///
226    /// Like the [`ComponentsBuilder::schemas_from_iter`] this allows adding multiple responses by
227    /// any iterator what returns tuples of (name, response) values.
228    pub fn responses_from_iter<
229        I: IntoIterator<Item = (S, R)>,
230        S: Into<String>,
231        R: Into<RefOr<Response>>,
232    >(
233        mut self,
234        responses: I,
235    ) -> Self {
236        self.responses.extend(
237            responses
238                .into_iter()
239                .map(|(name, response)| (name.into(), response.into())),
240        );
241
242        self
243    }
244
245    /// Add [`SecurityScheme`] to [`Components`].
246    ///
247    /// Accepts two arguments where first is the name of the [`SecurityScheme`]. This is later when
248    /// referenced by [`SecurityRequirement`][requirement]s. Second parameter is the [`SecurityScheme`].
249    ///
250    /// [requirement]: ../security/struct.SecurityRequirement.html
251    pub fn security_scheme<N: Into<String>, S: Into<SecurityScheme>>(
252        mut self,
253        name: N,
254        security_scheme: S,
255    ) -> Self {
256        self.security_schemes
257            .insert(name.into(), security_scheme.into());
258
259        self
260    }
261
262    /// Add openapi extensions (x-something) of the API.
263    pub fn extensions(mut self, extensions: Option<Extensions>) -> Self {
264        set_value!(self extensions extensions)
265    }
266}
267
268/// Is super type for [OpenAPI Schema Object][schemas]. Schema is reusable resource what can be
269/// referenced from path operations and other components using [`Ref`].
270///
271/// [schemas]: https://spec.openapis.org/oas/latest.html#schema-object
272#[non_exhaustive]
273#[derive(Serialize, Deserialize, Clone, PartialEq)]
274#[cfg_attr(feature = "debug", derive(Debug))]
275#[serde(untagged, rename_all = "camelCase")]
276pub enum Schema {
277    /// Defines array schema from another schema. Typically used with
278    /// [`Schema::Object`]. Slice and Vec types are translated to [`Schema::Array`] types.
279    Array(Array),
280    /// Defines object schema. Object is either `object` holding **properties** which are other [`Schema`]s
281    /// or can be a field within the [`Object`].
282    Object(Object),
283    /// Creates a _OneOf_ type [composite Object][composite] schema. This schema
284    /// is used to map multiple schemas together where API endpoint could return any of them.
285    /// [`Schema::OneOf`] is created form mixed enum where enum contains various variants.
286    ///
287    /// [composite]: https://spec.openapis.org/oas/latest.html#components-object
288    OneOf(OneOf),
289
290    /// Creates a _AllOf_ type [composite Object][composite] schema.
291    ///
292    /// [composite]: https://spec.openapis.org/oas/latest.html#components-object
293    AllOf(AllOf),
294
295    /// Creates a _AnyOf_ type [composite Object][composite] schema.
296    ///
297    /// [composite]: https://spec.openapis.org/oas/latest.html#components-object
298    AnyOf(AnyOf),
299}
300
301impl Default for Schema {
302    fn default() -> Self {
303        Schema::Object(Object::default())
304    }
305}
306
307/// OpenAPI [Discriminator][discriminator] object which can be optionally used together with
308/// [`OneOf`] composite object.
309///
310/// [discriminator]: https://spec.openapis.org/oas/latest.html#discriminator-object
311#[derive(Serialize, Deserialize, Clone, Default, PartialEq, Eq)]
312#[serde(rename_all = "camelCase")]
313#[cfg_attr(feature = "debug", derive(Debug))]
314pub struct Discriminator {
315    /// Defines a discriminator property name which must be found within all composite
316    /// objects.
317    pub property_name: String,
318
319    /// An object to hold mappings between payload values and schema names or references.
320    /// This field can only be populated manually. There is no macro support and no
321    /// validation.
322    #[serde(skip_serializing_if = "BTreeMap::is_empty", default)]
323    pub mapping: BTreeMap<String, String>,
324
325    /// Optional extensions "x-something".
326    #[serde(skip_serializing_if = "Option::is_none", flatten)]
327    pub extensions: Option<Extensions>,
328}
329
330impl Discriminator {
331    /// Construct a new [`Discriminator`] object with property name.
332    ///
333    /// # Examples
334    ///
335    /// Create a new [`Discriminator`] object for `pet_type` property.
336    /// ```rust
337    /// # use utoipa::openapi::schema::Discriminator;
338    /// let discriminator = Discriminator::new("pet_type");
339    /// ```
340    pub fn new<I: Into<String>>(property_name: I) -> Self {
341        Self {
342            property_name: property_name.into(),
343            mapping: BTreeMap::new(),
344            ..Default::default()
345        }
346    }
347
348    /// Construct a new [`Discriminator`] object with property name and mappings.
349    ///
350    ///
351    /// Method accepts two arguments. First _`property_name`_ to use as `discriminator` and
352    /// _`mapping`_ for custom property name mappings.
353    ///
354    /// # Examples
355    ///
356    ///_**Construct an ew [`Discriminator`] with custom mapping.**_
357    ///
358    /// ```rust
359    /// # use utoipa::openapi::schema::Discriminator;
360    /// let discriminator = Discriminator::with_mapping("pet_type", [
361    ///     ("cat","#/components/schemas/Cat")
362    /// ]);
363    /// ```
364    pub fn with_mapping<
365        P: Into<String>,
366        M: IntoIterator<Item = (K, V)>,
367        K: Into<String>,
368        V: Into<String>,
369    >(
370        property_name: P,
371        mapping: M,
372    ) -> Self {
373        Self {
374            property_name: property_name.into(),
375            mapping: BTreeMap::from_iter(
376                mapping
377                    .into_iter()
378                    .map(|(key, val)| (key.into(), val.into())),
379            ),
380            ..Default::default()
381        }
382    }
383}
384
385builder! {
386    OneOfBuilder;
387
388    /// OneOf [Composite Object][oneof] component holds
389    /// multiple components together where API endpoint could return any of them.
390    ///
391    /// See [`Schema::OneOf`] for more details.
392    ///
393    /// [oneof]: https://spec.openapis.org/oas/latest.html#components-object
394    #[derive(Serialize, Deserialize, Clone, PartialEq)]
395    #[cfg_attr(feature = "debug", derive(Debug))]
396    pub struct OneOf {
397        /// Components of _OneOf_ component.
398        #[serde(rename = "oneOf")]
399        pub items: Vec<RefOr<Schema>>,
400
401        /// Type of [`OneOf`] e.g. `SchemaType::new(Type::Object)` for `object`.
402        ///
403        /// By default this is [`SchemaType::AnyValue`] as the type is defined by items
404        /// themselves.
405        #[serde(rename = "type", default = "SchemaType::any", skip_serializing_if = "SchemaType::is_any_value")]
406        pub schema_type: SchemaType,
407
408        /// Changes the [`OneOf`] title.
409        #[serde(skip_serializing_if = "Option::is_none")]
410        pub title: Option<String>,
411
412        /// Description of the [`OneOf`]. Markdown syntax is supported.
413        #[serde(skip_serializing_if = "Option::is_none")]
414        pub description: Option<String>,
415
416        /// Default value which is provided when user has not provided the input in Swagger UI.
417        #[serde(skip_serializing_if = "Option::is_none")]
418        pub default: Option<Value>,
419
420        /// Example shown in UI of the value for richer documentation.
421        ///
422        /// **Deprecated since 3.0.x. Prefer [`OneOf::examples`] instead**
423        #[serde(skip_serializing_if = "Option::is_none")]
424        pub example: Option<Value>,
425
426        /// Examples shown in UI of the value for richer documentation.
427        #[serde(skip_serializing_if = "Vec::is_empty", default)]
428        pub examples: Vec<Value>,
429
430        /// Optional discriminator field can be used to aid deserialization, serialization and validation of a
431        /// specific schema.
432        #[serde(skip_serializing_if = "Option::is_none")]
433        pub discriminator: Option<Discriminator>,
434
435        /// Optional extensions `x-something`.
436        #[serde(skip_serializing_if = "Option::is_none", flatten)]
437        pub extensions: Option<Extensions>,
438    }
439}
440
441impl OneOf {
442    /// Construct a new [`OneOf`] component.
443    pub fn new() -> Self {
444        Self {
445            ..Default::default()
446        }
447    }
448
449    /// Construct a new [`OneOf`] component with given capacity.
450    ///
451    /// OneOf component is then able to contain number of components without
452    /// reallocating.
453    ///
454    /// # Examples
455    ///
456    /// Create [`OneOf`] component with initial capacity of 5.
457    /// ```rust
458    /// # use utoipa::openapi::schema::OneOf;
459    /// let one_of = OneOf::with_capacity(5);
460    /// ```
461    pub fn with_capacity(capacity: usize) -> Self {
462        Self {
463            items: Vec::with_capacity(capacity),
464            ..Default::default()
465        }
466    }
467}
468
469impl Default for OneOf {
470    fn default() -> Self {
471        Self {
472            items: Default::default(),
473            schema_type: SchemaType::AnyValue,
474            title: Default::default(),
475            description: Default::default(),
476            default: Default::default(),
477            example: Default::default(),
478            examples: Default::default(),
479            discriminator: Default::default(),
480            extensions: Default::default(),
481        }
482    }
483}
484
485impl OneOfBuilder {
486    /// Adds a given [`Schema`] to [`OneOf`] [Composite Object][composite].
487    ///
488    /// [composite]: https://spec.openapis.org/oas/latest.html#components-object
489    pub fn item<I: Into<RefOr<Schema>>>(mut self, component: I) -> Self {
490        self.items.push(component.into());
491
492        self
493    }
494
495    /// Add or change type of the object e.g. to change type to _`string`_
496    /// use value `SchemaType::Type(Type::String)`.
497    pub fn schema_type<T: Into<SchemaType>>(mut self, schema_type: T) -> Self {
498        set_value!(self schema_type schema_type.into())
499    }
500
501    /// Add or change the title of the [`OneOf`].
502    pub fn title<I: Into<String>>(mut self, title: Option<I>) -> Self {
503        set_value!(self title title.map(|title| title.into()))
504    }
505
506    /// Add or change optional description for `OneOf` component.
507    pub fn description<I: Into<String>>(mut self, description: Option<I>) -> Self {
508        set_value!(self description description.map(|description| description.into()))
509    }
510
511    /// Add or change default value for the object which is provided when user has not provided the input in Swagger UI.
512    pub fn default(mut self, default: Option<Value>) -> Self {
513        set_value!(self default default)
514    }
515
516    /// Add or change example shown in UI of the value for richer documentation.
517    ///
518    /// **Deprecated since 3.0.x. Prefer [`OneOfBuilder::examples`] instead**
519    #[deprecated = "Since OpenAPI 3.1 prefer using `examples`"]
520    pub fn example(mut self, example: Option<Value>) -> Self {
521        set_value!(self example example)
522    }
523
524    /// Add or change examples shown in UI of the value for richer documentation.
525    pub fn examples<I: IntoIterator<Item = V>, V: Into<Value>>(mut self, examples: I) -> Self {
526        set_value!(self examples examples.into_iter().map(Into::into).collect())
527    }
528
529    /// Add or change discriminator field of the composite [`OneOf`] type.
530    pub fn discriminator(mut self, discriminator: Option<Discriminator>) -> Self {
531        set_value!(self discriminator discriminator)
532    }
533
534    /// Add openapi extensions (`x-something`) for [`OneOf`].
535    pub fn extensions(mut self, extensions: Option<Extensions>) -> Self {
536        set_value!(self extensions extensions)
537    }
538
539    to_array_builder!();
540}
541
542impl From<OneOf> for Schema {
543    fn from(one_of: OneOf) -> Self {
544        Self::OneOf(one_of)
545    }
546}
547
548impl From<OneOfBuilder> for RefOr<Schema> {
549    fn from(one_of: OneOfBuilder) -> Self {
550        Self::T(Schema::OneOf(one_of.build()))
551    }
552}
553
554impl From<OneOfBuilder> for ArrayItems {
555    fn from(value: OneOfBuilder) -> Self {
556        Self::RefOrSchema(Box::new(value.into()))
557    }
558}
559
560component_from_builder!(OneOfBuilder);
561
562builder! {
563    AllOfBuilder;
564
565    /// AllOf [Composite Object][allof] component holds
566    /// multiple components together where API endpoint will return a combination of all of them.
567    ///
568    /// See [`Schema::AllOf`] for more details.
569    ///
570    /// [allof]: https://spec.openapis.org/oas/latest.html#components-object
571    #[derive(Serialize, Deserialize, Clone, PartialEq)]
572    #[cfg_attr(feature = "debug", derive(Debug))]
573    pub struct AllOf {
574        /// Components of _AllOf_ component.
575        #[serde(rename = "allOf")]
576        pub items: Vec<RefOr<Schema>>,
577
578        /// Type of [`AllOf`] e.g. `SchemaType::new(Type::Object)` for `object`.
579        ///
580        /// By default this is [`SchemaType::AnyValue`] as the type is defined by items
581        /// themselves.
582        #[serde(rename = "type", default = "SchemaType::any", skip_serializing_if = "SchemaType::is_any_value")]
583        pub schema_type: SchemaType,
584
585        /// Changes the [`AllOf`] title.
586        #[serde(skip_serializing_if = "Option::is_none")]
587        pub title: Option<String>,
588
589        /// Description of the [`AllOf`]. Markdown syntax is supported.
590        #[serde(skip_serializing_if = "Option::is_none")]
591        pub description: Option<String>,
592
593        /// Default value which is provided when user has not provided the input in Swagger UI.
594        #[serde(skip_serializing_if = "Option::is_none")]
595        pub default: Option<Value>,
596
597        /// Example shown in UI of the value for richer documentation.
598        ///
599        /// **Deprecated since 3.0.x. Prefer [`AllOf::examples`] instead**
600        #[serde(skip_serializing_if = "Option::is_none")]
601        pub example: Option<Value>,
602
603        /// Examples shown in UI of the value for richer documentation.
604        #[serde(skip_serializing_if = "Vec::is_empty", default)]
605        pub examples: Vec<Value>,
606
607        /// Optional discriminator field can be used to aid deserialization, serialization and validation of a
608        /// specific schema.
609        #[serde(skip_serializing_if = "Option::is_none")]
610        pub discriminator: Option<Discriminator>,
611
612        /// Optional extensions `x-something`.
613        #[serde(skip_serializing_if = "Option::is_none", flatten)]
614        pub extensions: Option<Extensions>,
615    }
616}
617
618impl AllOf {
619    /// Construct a new [`AllOf`] component.
620    pub fn new() -> Self {
621        Self {
622            ..Default::default()
623        }
624    }
625
626    /// Construct a new [`AllOf`] component with given capacity.
627    ///
628    /// AllOf component is then able to contain number of components without
629    /// reallocating.
630    ///
631    /// # Examples
632    ///
633    /// Create [`AllOf`] component with initial capacity of 5.
634    /// ```rust
635    /// # use utoipa::openapi::schema::AllOf;
636    /// let one_of = AllOf::with_capacity(5);
637    /// ```
638    pub fn with_capacity(capacity: usize) -> Self {
639        Self {
640            items: Vec::with_capacity(capacity),
641            ..Default::default()
642        }
643    }
644}
645
646impl Default for AllOf {
647    fn default() -> Self {
648        Self {
649            items: Default::default(),
650            schema_type: SchemaType::AnyValue,
651            title: Default::default(),
652            description: Default::default(),
653            default: Default::default(),
654            example: Default::default(),
655            examples: Default::default(),
656            discriminator: Default::default(),
657            extensions: Default::default(),
658        }
659    }
660}
661
662impl AllOfBuilder {
663    /// Adds a given [`Schema`] to [`AllOf`] [Composite Object][composite].
664    ///
665    /// [composite]: https://spec.openapis.org/oas/latest.html#components-object
666    pub fn item<I: Into<RefOr<Schema>>>(mut self, component: I) -> Self {
667        self.items.push(component.into());
668
669        self
670    }
671
672    /// Add or change type of the object e.g. to change type to _`string`_
673    /// use value `SchemaType::Type(Type::String)`.
674    pub fn schema_type<T: Into<SchemaType>>(mut self, schema_type: T) -> Self {
675        set_value!(self schema_type schema_type.into())
676    }
677
678    /// Add or change the title of the [`AllOf`].
679    pub fn title<I: Into<String>>(mut self, title: Option<I>) -> Self {
680        set_value!(self title title.map(|title| title.into()))
681    }
682
683    /// Add or change optional description for `AllOf` component.
684    pub fn description<I: Into<String>>(mut self, description: Option<I>) -> Self {
685        set_value!(self description description.map(|description| description.into()))
686    }
687
688    /// Add or change default value for the object which is provided when user has not provided the input in Swagger UI.
689    pub fn default(mut self, default: Option<Value>) -> Self {
690        set_value!(self default default)
691    }
692
693    /// Add or change example shown in UI of the value for richer documentation.
694    ///
695    /// **Deprecated since 3.0.x. Prefer [`AllOfBuilder::examples`] instead**
696    #[deprecated = "Since OpenAPI 3.1 prefer using `examples`"]
697    pub fn example(mut self, example: Option<Value>) -> Self {
698        set_value!(self example example)
699    }
700
701    /// Add or change examples shown in UI of the value for richer documentation.
702    pub fn examples<I: IntoIterator<Item = V>, V: Into<Value>>(mut self, examples: I) -> Self {
703        set_value!(self examples examples.into_iter().map(Into::into).collect())
704    }
705
706    /// Add or change discriminator field of the composite [`AllOf`] type.
707    pub fn discriminator(mut self, discriminator: Option<Discriminator>) -> Self {
708        set_value!(self discriminator discriminator)
709    }
710
711    /// Add openapi extensions (`x-something`) for [`AllOf`].
712    pub fn extensions(mut self, extensions: Option<Extensions>) -> Self {
713        set_value!(self extensions extensions)
714    }
715
716    to_array_builder!();
717}
718
719impl From<AllOf> for Schema {
720    fn from(one_of: AllOf) -> Self {
721        Self::AllOf(one_of)
722    }
723}
724
725impl From<AllOfBuilder> for RefOr<Schema> {
726    fn from(one_of: AllOfBuilder) -> Self {
727        Self::T(Schema::AllOf(one_of.build()))
728    }
729}
730
731impl From<AllOfBuilder> for ArrayItems {
732    fn from(value: AllOfBuilder) -> Self {
733        Self::RefOrSchema(Box::new(value.into()))
734    }
735}
736
737component_from_builder!(AllOfBuilder);
738
739builder! {
740    AnyOfBuilder;
741
742    /// AnyOf [Composite Object][anyof] component holds
743    /// multiple components together where API endpoint will return a combination of one or more of them.
744    ///
745    /// See [`Schema::AnyOf`] for more details.
746    ///
747    /// [anyof]: https://spec.openapis.org/oas/latest.html#components-object
748    #[derive(Serialize, Deserialize, Clone, PartialEq)]
749    #[cfg_attr(feature = "debug", derive(Debug))]
750    pub struct AnyOf {
751        /// Components of _AnyOf component.
752        #[serde(rename = "anyOf")]
753        pub items: Vec<RefOr<Schema>>,
754
755        /// Type of [`AnyOf`] e.g. `SchemaType::new(Type::Object)` for `object`.
756        ///
757        /// By default this is [`SchemaType::AnyValue`] as the type is defined by items
758        /// themselves.
759        #[serde(rename = "type", default = "SchemaType::any", skip_serializing_if = "SchemaType::is_any_value")]
760        pub schema_type: SchemaType,
761
762        /// Description of the [`AnyOf`]. Markdown syntax is supported.
763        #[serde(skip_serializing_if = "Option::is_none")]
764        pub description: Option<String>,
765
766        /// Default value which is provided when user has not provided the input in Swagger UI.
767        #[serde(skip_serializing_if = "Option::is_none")]
768        pub default: Option<Value>,
769
770        /// Example shown in UI of the value for richer documentation.
771        ///
772        /// **Deprecated since 3.0.x. Prefer [`AnyOf::examples`] instead**
773        #[serde(skip_serializing_if = "Option::is_none")]
774        pub example: Option<Value>,
775
776        /// Examples shown in UI of the value for richer documentation.
777        #[serde(skip_serializing_if = "Vec::is_empty", default)]
778        pub examples: Vec<Value>,
779
780        /// Optional discriminator field can be used to aid deserialization, serialization and validation of a
781        /// specific schema.
782        #[serde(skip_serializing_if = "Option::is_none")]
783        pub discriminator: Option<Discriminator>,
784
785        /// Optional extensions `x-something`.
786        #[serde(skip_serializing_if = "Option::is_none", flatten)]
787        pub extensions: Option<Extensions>,
788    }
789}
790
791impl AnyOf {
792    /// Construct a new [`AnyOf`] component.
793    pub fn new() -> Self {
794        Self {
795            ..Default::default()
796        }
797    }
798
799    /// Construct a new [`AnyOf`] component with given capacity.
800    ///
801    /// AnyOf component is then able to contain number of components without
802    /// reallocating.
803    ///
804    /// # Examples
805    ///
806    /// Create [`AnyOf`] component with initial capacity of 5.
807    /// ```rust
808    /// # use utoipa::openapi::schema::AnyOf;
809    /// let one_of = AnyOf::with_capacity(5);
810    /// ```
811    pub fn with_capacity(capacity: usize) -> Self {
812        Self {
813            items: Vec::with_capacity(capacity),
814            ..Default::default()
815        }
816    }
817}
818
819impl Default for AnyOf {
820    fn default() -> Self {
821        Self {
822            items: Default::default(),
823            schema_type: SchemaType::AnyValue,
824            description: Default::default(),
825            default: Default::default(),
826            example: Default::default(),
827            examples: Default::default(),
828            discriminator: Default::default(),
829            extensions: Default::default(),
830        }
831    }
832}
833
834impl AnyOfBuilder {
835    /// Adds a given [`Schema`] to [`AnyOf`] [Composite Object][composite].
836    ///
837    /// [composite]: https://spec.openapis.org/oas/latest.html#components-object
838    pub fn item<I: Into<RefOr<Schema>>>(mut self, component: I) -> Self {
839        self.items.push(component.into());
840
841        self
842    }
843
844    /// Add or change type of the object e.g. to change type to _`string`_
845    /// use value `SchemaType::Type(Type::String)`.
846    pub fn schema_type<T: Into<SchemaType>>(mut self, schema_type: T) -> Self {
847        set_value!(self schema_type schema_type.into())
848    }
849
850    /// Add or change optional description for `AnyOf` component.
851    pub fn description<I: Into<String>>(mut self, description: Option<I>) -> Self {
852        set_value!(self description description.map(|description| description.into()))
853    }
854
855    /// Add or change default value for the object which is provided when user has not provided the input in Swagger UI.
856    pub fn default(mut self, default: Option<Value>) -> Self {
857        set_value!(self default default)
858    }
859
860    /// Add or change example shown in UI of the value for richer documentation.
861    ///
862    /// **Deprecated since 3.0.x. Prefer [`AllOfBuilder::examples`] instead**
863    #[deprecated = "Since OpenAPI 3.1 prefer using `examples`"]
864    pub fn example(mut self, example: Option<Value>) -> Self {
865        set_value!(self example example)
866    }
867
868    /// Add or change examples shown in UI of the value for richer documentation.
869    pub fn examples<I: IntoIterator<Item = V>, V: Into<Value>>(mut self, examples: I) -> Self {
870        set_value!(self examples examples.into_iter().map(Into::into).collect())
871    }
872
873    /// Add or change discriminator field of the composite [`AnyOf`] type.
874    pub fn discriminator(mut self, discriminator: Option<Discriminator>) -> Self {
875        set_value!(self discriminator discriminator)
876    }
877
878    /// Add openapi extensions (`x-something`) for [`AnyOf`].
879    pub fn extensions(mut self, extensions: Option<Extensions>) -> Self {
880        set_value!(self extensions extensions)
881    }
882
883    to_array_builder!();
884}
885
886impl From<AnyOf> for Schema {
887    fn from(any_of: AnyOf) -> Self {
888        Self::AnyOf(any_of)
889    }
890}
891
892impl From<AnyOfBuilder> for RefOr<Schema> {
893    fn from(any_of: AnyOfBuilder) -> Self {
894        Self::T(Schema::AnyOf(any_of.build()))
895    }
896}
897
898impl From<AnyOfBuilder> for ArrayItems {
899    fn from(value: AnyOfBuilder) -> Self {
900        Self::RefOrSchema(Box::new(value.into()))
901    }
902}
903
904component_from_builder!(AnyOfBuilder);
905
906#[cfg(not(feature = "preserve_order"))]
907type ObjectPropertiesMap<K, V> = BTreeMap<K, V>;
908#[cfg(feature = "preserve_order")]
909type ObjectPropertiesMap<K, V> = indexmap::IndexMap<K, V>;
910
911builder! {
912    ObjectBuilder;
913
914    /// Implements subset of [OpenAPI Schema Object][schema] which allows
915    /// adding other [`Schema`]s as **properties** to this [`Schema`].
916    ///
917    /// This is a generic OpenAPI schema object which can used to present `object`, `field` or an `enum`.
918    ///
919    /// [schema]: https://spec.openapis.org/oas/latest.html#schema-object
920    #[non_exhaustive]
921    #[derive(Serialize, Deserialize, Default, Clone, PartialEq)]
922    #[cfg_attr(feature = "debug", derive(Debug))]
923    #[serde(rename_all = "camelCase")]
924    pub struct Object {
925        /// Type of [`Object`] e.g. [`Type::Object`] for `object` and [`Type::String`] for
926        /// `string` types.
927        #[serde(rename = "type", skip_serializing_if="SchemaType::is_any_value")]
928        pub schema_type: SchemaType,
929
930        /// Changes the [`Object`] title.
931        #[serde(skip_serializing_if = "Option::is_none")]
932        pub title: Option<String>,
933
934        /// Additional format for detailing the schema type.
935        #[serde(skip_serializing_if = "Option::is_none")]
936        pub format: Option<SchemaFormat>,
937
938        /// Description of the [`Object`]. Markdown syntax is supported.
939        #[serde(skip_serializing_if = "Option::is_none")]
940        pub description: Option<String>,
941
942        /// Default value which is provided when user has not provided the input in Swagger UI.
943        #[serde(skip_serializing_if = "Option::is_none")]
944        pub default: Option<Value>,
945
946        /// Enum variants of fields that can be represented as `unit` type `enums`.
947        #[serde(rename = "enum", skip_serializing_if = "Option::is_none")]
948        pub enum_values: Option<Vec<Value>>,
949
950        /// Vector of required field names.
951        #[serde(skip_serializing_if = "Vec::is_empty", default = "Vec::new")]
952        pub required: Vec<String>,
953
954        /// Map of fields with their [`Schema`] types.
955        ///
956        /// With **preserve_order** feature flag [`indexmap::IndexMap`] will be used as
957        /// properties map backing implementation to retain property order of [`ToSchema`][to_schema].
958        /// By default [`BTreeMap`] will be used.
959        ///
960        /// [to_schema]: crate::ToSchema
961        #[serde(skip_serializing_if = "ObjectPropertiesMap::is_empty", default = "ObjectPropertiesMap::new")]
962        pub properties: ObjectPropertiesMap<String, RefOr<Schema>>,
963
964        /// Additional [`Schema`] for non specified fields (Useful for typed maps).
965        #[serde(skip_serializing_if = "Option::is_none")]
966        pub additional_properties: Option<Box<AdditionalProperties<Schema>>>,
967
968        /// Additional [`Schema`] to describe property names of an object such as a map. See more
969        /// details <https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-01#name-propertynames>
970        #[serde(skip_serializing_if = "Option::is_none")]
971        pub property_names: Option<Box<Schema>>,
972
973        /// Changes the [`Object`] deprecated status.
974        #[serde(skip_serializing_if = "Option::is_none")]
975        pub deprecated: Option<Deprecated>,
976
977        /// Example shown in UI of the value for richer documentation.
978        ///
979        /// **Deprecated since 3.0.x. Prefer [`Object::examples`] instead**
980        #[serde(skip_serializing_if = "Option::is_none")]
981        pub example: Option<Value>,
982
983        /// Examples shown in UI of the value for richer documentation.
984        #[serde(skip_serializing_if = "Vec::is_empty", default)]
985        pub examples: Vec<Value>,
986
987        /// Write only property will be only sent in _write_ requests like _POST, PUT_.
988        #[serde(skip_serializing_if = "Option::is_none")]
989        pub write_only: Option<bool>,
990
991        /// Read only property will be only sent in _read_ requests like _GET_.
992        #[serde(skip_serializing_if = "Option::is_none")]
993        pub read_only: Option<bool>,
994
995        /// Additional [`Xml`] formatting of the [`Object`].
996        #[serde(skip_serializing_if = "Option::is_none")]
997        pub xml: Option<Xml>,
998
999        /// Must be a number strictly greater than `0`. Numeric value is considered valid if value
1000        /// divided by the _`multiple_of`_ value results an integer.
1001        #[serde(skip_serializing_if = "Option::is_none", serialize_with = "omit_decimal_zero")]
1002        pub multiple_of: Option<crate::utoipa::Number>,
1003
1004        /// Specify inclusive upper limit for the [`Object`]'s value. Number is considered valid if
1005        /// it is equal or less than the _`maximum`_.
1006        #[serde(skip_serializing_if = "Option::is_none", serialize_with = "omit_decimal_zero")]
1007        pub maximum: Option<crate::utoipa::Number>,
1008
1009        /// Specify inclusive lower limit for the [`Object`]'s value. Number value is considered
1010        /// valid if it is equal or greater than the _`minimum`_.
1011        #[serde(skip_serializing_if = "Option::is_none", serialize_with = "omit_decimal_zero")]
1012        pub minimum: Option<crate::utoipa::Number>,
1013
1014        /// Specify exclusive upper limit for the [`Object`]'s value. Number value is considered
1015        /// valid if it is strictly less than _`exclusive_maximum`_.
1016        #[serde(skip_serializing_if = "Option::is_none", serialize_with = "omit_decimal_zero")]
1017        pub exclusive_maximum: Option<crate::utoipa::Number>,
1018
1019        /// Specify exclusive lower limit for the [`Object`]'s value. Number value is considered
1020        /// valid if it is strictly above the _`exclusive_minimum`_.
1021        #[serde(skip_serializing_if = "Option::is_none", serialize_with = "omit_decimal_zero")]
1022        pub exclusive_minimum: Option<crate::utoipa::Number>,
1023
1024        /// Specify maximum length for `string` values. _`max_length`_ cannot be a negative integer
1025        /// value. Value is considered valid if content length is equal or less than the _`max_length`_.
1026        #[serde(skip_serializing_if = "Option::is_none")]
1027        pub max_length: Option<usize>,
1028
1029        /// Specify minimum length for `string` values. _`min_length`_ cannot be a negative integer
1030        /// value. Setting this to _`0`_ has the same effect as omitting this field. Value is
1031        /// considered valid if content length is equal or more than the _`min_length`_.
1032        #[serde(skip_serializing_if = "Option::is_none")]
1033        pub min_length: Option<usize>,
1034
1035        /// Define a valid `ECMA-262` dialect regular expression. The `string` content is
1036        /// considered valid if the _`pattern`_ matches the value successfully.
1037        #[serde(skip_serializing_if = "Option::is_none")]
1038        pub pattern: Option<String>,
1039
1040        /// Specify inclusive maximum amount of properties an [`Object`] can hold.
1041        #[serde(skip_serializing_if = "Option::is_none")]
1042        pub max_properties: Option<usize>,
1043
1044        /// Specify inclusive minimum amount of properties an [`Object`] can hold. Setting this to
1045        /// `0` will have same effect as omitting the attribute.
1046        #[serde(skip_serializing_if = "Option::is_none")]
1047        pub min_properties: Option<usize>,
1048
1049        /// Optional extensions `x-something`.
1050        #[serde(skip_serializing_if = "Option::is_none", flatten)]
1051        pub extensions: Option<Extensions>,
1052
1053        /// The `content_encoding` keyword specifies the encoding used to store the contents, as specified in
1054        /// [RFC 2054, part 6.1](https://tools.ietf.org/html/rfc2045) and [RFC 4648](RFC 2054, part 6.1).
1055        ///
1056        /// Typically this is either unset for _`string`_ content types which then uses the content
1057        /// encoding of the underlying JSON document. If the content is in _`binary`_ format such as an image or an audio
1058        /// set it to `base64` to encode it as _`Base64`_.
1059        ///
1060        /// See more details at <https://json-schema.org/understanding-json-schema/reference/non_json_data#contentencoding>
1061        #[serde(skip_serializing_if = "String::is_empty", default)]
1062        pub content_encoding: String,
1063
1064        /// The _`content_media_type`_ keyword specifies the MIME type of the contents of a string,
1065        /// as described in [RFC 2046](https://tools.ietf.org/html/rfc2046).
1066        ///
1067        /// See more details at <https://json-schema.org/understanding-json-schema/reference/non_json_data#contentmediatype>
1068        #[serde(skip_serializing_if = "String::is_empty", default)]
1069        pub content_media_type: String,
1070    }
1071}
1072
1073fn is_false(value: &bool) -> bool {
1074    !*value
1075}
1076
1077impl Object {
1078    /// Initialize a new [`Object`] with default [`SchemaType`]. This effectively same as calling
1079    /// `Object::with_type(SchemaType::Object)`.
1080    pub fn new() -> Self {
1081        Self {
1082            ..Default::default()
1083        }
1084    }
1085
1086    /// Initialize new [`Object`] with given [`SchemaType`].
1087    ///
1088    /// Create [`std::string`] object type which can be used to define `string` field of an object.
1089    /// ```rust
1090    /// # use utoipa::openapi::schema::{Object, Type};
1091    /// let object = Object::with_type(Type::String);
1092    /// ```
1093    pub fn with_type<T: Into<SchemaType>>(schema_type: T) -> Self {
1094        Self {
1095            schema_type: schema_type.into(),
1096            ..Default::default()
1097        }
1098    }
1099}
1100
1101impl From<Object> for Schema {
1102    fn from(s: Object) -> Self {
1103        Self::Object(s)
1104    }
1105}
1106
1107impl From<Object> for ArrayItems {
1108    fn from(value: Object) -> Self {
1109        Self::RefOrSchema(Box::new(value.into()))
1110    }
1111}
1112
1113impl ToArray for Object {}
1114
1115impl ObjectBuilder {
1116    /// Add or change type of the object e.g. to change type to _`string`_
1117    /// use value `SchemaType::Type(Type::String)`.
1118    pub fn schema_type<T: Into<SchemaType>>(mut self, schema_type: T) -> Self {
1119        set_value!(self schema_type schema_type.into())
1120    }
1121
1122    /// Add or change additional format for detailing the schema type.
1123    pub fn format(mut self, format: Option<SchemaFormat>) -> Self {
1124        set_value!(self format format)
1125    }
1126
1127    /// Add new property to the [`Object`].
1128    ///
1129    /// Method accepts property name and property component as an arguments.
1130    pub fn property<S: Into<String>, I: Into<RefOr<Schema>>>(
1131        mut self,
1132        property_name: S,
1133        component: I,
1134    ) -> Self {
1135        self.properties
1136            .insert(property_name.into(), component.into());
1137
1138        self
1139    }
1140
1141    /// Add additional [`Schema`] for non specified fields (Useful for typed maps).
1142    pub fn additional_properties<I: Into<AdditionalProperties<Schema>>>(
1143        mut self,
1144        additional_properties: Option<I>,
1145    ) -> Self {
1146        set_value!(self additional_properties additional_properties.map(|additional_properties| Box::new(additional_properties.into())))
1147    }
1148
1149    /// Add additional [`Schema`] to describe property names of an object such as a map. See more
1150    /// details <https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-01#name-propertynames>
1151    pub fn property_names<S: Into<Schema>>(mut self, property_name: Option<S>) -> Self {
1152        set_value!(self property_names property_name.map(|property_name| Box::new(property_name.into())))
1153    }
1154
1155    /// Add field to the required fields of [`Object`].
1156    pub fn required<I: Into<String>>(mut self, required_field: I) -> Self {
1157        self.required.push(required_field.into());
1158
1159        self
1160    }
1161
1162    /// Add or change the title of the [`Object`].
1163    pub fn title<I: Into<String>>(mut self, title: Option<I>) -> Self {
1164        set_value!(self title title.map(|title| title.into()))
1165    }
1166
1167    /// Add or change description of the property. Markdown syntax is supported.
1168    pub fn description<I: Into<String>>(mut self, description: Option<I>) -> Self {
1169        set_value!(self description description.map(|description| description.into()))
1170    }
1171
1172    /// Add or change default value for the object which is provided when user has not provided the input in Swagger UI.
1173    pub fn default(mut self, default: Option<Value>) -> Self {
1174        set_value!(self default default)
1175    }
1176
1177    /// Add or change deprecated status for [`Object`].
1178    pub fn deprecated(mut self, deprecated: Option<Deprecated>) -> Self {
1179        set_value!(self deprecated deprecated)
1180    }
1181
1182    /// Add or change enum property variants.
1183    pub fn enum_values<I: IntoIterator<Item = E>, E: Into<Value>>(
1184        mut self,
1185        enum_values: Option<I>,
1186    ) -> Self {
1187        set_value!(self enum_values
1188            enum_values.map(|values| values.into_iter().map(|enum_value| enum_value.into()).collect()))
1189    }
1190
1191    /// Add or change example shown in UI of the value for richer documentation.
1192    ///
1193    /// **Deprecated since 3.0.x. Prefer [`Object::examples`] instead**
1194    #[deprecated = "Since OpenAPI 3.1 prefer using `examples`"]
1195    pub fn example(mut self, example: Option<Value>) -> Self {
1196        set_value!(self example example)
1197    }
1198
1199    /// Add or change examples shown in UI of the value for richer documentation.
1200    pub fn examples<I: IntoIterator<Item = V>, V: Into<Value>>(mut self, examples: I) -> Self {
1201        set_value!(self examples examples.into_iter().map(Into::into).collect())
1202    }
1203
1204    /// Add or change write only flag for [`Object`].
1205    pub fn write_only(mut self, write_only: Option<bool>) -> Self {
1206        set_value!(self write_only write_only)
1207    }
1208
1209    /// Add or change read only flag for [`Object`].
1210    pub fn read_only(mut self, read_only: Option<bool>) -> Self {
1211        set_value!(self read_only read_only)
1212    }
1213
1214    /// Add or change additional [`Xml`] formatting of the [`Object`].
1215    pub fn xml(mut self, xml: Option<Xml>) -> Self {
1216        set_value!(self xml xml)
1217    }
1218
1219    /// Set or change _`multiple_of`_ validation flag for `number` and `integer` type values.
1220    pub fn multiple_of<N: Into<crate::utoipa::Number>>(mut self, multiple_of: Option<N>) -> Self {
1221        set_value!(self multiple_of multiple_of.map(|multiple_of| multiple_of.into()))
1222    }
1223
1224    /// Set or change inclusive maximum value for `number` and `integer` values.
1225    pub fn maximum<N: Into<crate::utoipa::Number>>(mut self, maximum: Option<N>) -> Self {
1226        set_value!(self maximum maximum.map(|max| max.into()))
1227    }
1228
1229    /// Set or change inclusive minimum value for `number` and `integer` values.
1230    pub fn minimum<N: Into<crate::utoipa::Number>>(mut self, minimum: Option<N>) -> Self {
1231        set_value!(self minimum minimum.map(|min| min.into()))
1232    }
1233
1234    /// Set or change exclusive maximum value for `number` and `integer` values.
1235    pub fn exclusive_maximum<N: Into<crate::utoipa::Number>>(
1236        mut self,
1237        exclusive_maximum: Option<N>,
1238    ) -> Self {
1239        set_value!(self exclusive_maximum exclusive_maximum.map(|exclusive_maximum| exclusive_maximum.into()))
1240    }
1241
1242    /// Set or change exclusive minimum value for `number` and `integer` values.
1243    pub fn exclusive_minimum<N: Into<crate::utoipa::Number>>(
1244        mut self,
1245        exclusive_minimum: Option<N>,
1246    ) -> Self {
1247        set_value!(self exclusive_minimum exclusive_minimum.map(|exclusive_minimum| exclusive_minimum.into()))
1248    }
1249
1250    /// Set or change maximum length for `string` values.
1251    pub fn max_length(mut self, max_length: Option<usize>) -> Self {
1252        set_value!(self max_length max_length)
1253    }
1254
1255    /// Set or change minimum length for `string` values.
1256    pub fn min_length(mut self, min_length: Option<usize>) -> Self {
1257        set_value!(self min_length min_length)
1258    }
1259
1260    /// Set or change a valid regular expression for `string` value to match.
1261    pub fn pattern<I: Into<String>>(mut self, pattern: Option<I>) -> Self {
1262        set_value!(self pattern pattern.map(|pattern| pattern.into()))
1263    }
1264
1265    /// Set or change maximum number of properties the [`Object`] can hold.
1266    pub fn max_properties(mut self, max_properties: Option<usize>) -> Self {
1267        set_value!(self max_properties max_properties)
1268    }
1269
1270    /// Set or change minimum number of properties the [`Object`] can hold.
1271    pub fn min_properties(mut self, min_properties: Option<usize>) -> Self {
1272        set_value!(self min_properties min_properties)
1273    }
1274
1275    /// Add openapi extensions (`x-something`) for [`Object`].
1276    pub fn extensions(mut self, extensions: Option<Extensions>) -> Self {
1277        set_value!(self extensions extensions)
1278    }
1279
1280    /// Set of change [`Object::content_encoding`]. Typically left empty but could be `base64` for
1281    /// example.
1282    pub fn content_encoding<S: Into<String>>(mut self, content_encoding: S) -> Self {
1283        set_value!(self content_encoding content_encoding.into())
1284    }
1285
1286    /// Set of change [`Object::content_media_type`]. Value must be valid MIME type e.g.
1287    /// `application/json`.
1288    pub fn content_media_type<S: Into<String>>(mut self, content_media_type: S) -> Self {
1289        set_value!(self content_media_type content_media_type.into())
1290    }
1291
1292    to_array_builder!();
1293}
1294
1295component_from_builder!(ObjectBuilder);
1296
1297impl From<ObjectBuilder> for RefOr<Schema> {
1298    fn from(builder: ObjectBuilder) -> Self {
1299        Self::T(Schema::Object(builder.build()))
1300    }
1301}
1302
1303impl From<RefOr<Schema>> for Schema {
1304    fn from(value: RefOr<Schema>) -> Self {
1305        match value {
1306            RefOr::Ref(_) => {
1307                panic!("Invalid type `RefOr::Ref` provided, cannot convert to RefOr::T<Schema>")
1308            }
1309            RefOr::T(value) => value,
1310        }
1311    }
1312}
1313
1314impl From<ObjectBuilder> for ArrayItems {
1315    fn from(value: ObjectBuilder) -> Self {
1316        Self::RefOrSchema(Box::new(value.into()))
1317    }
1318}
1319
1320/// AdditionalProperties is used to define values of map fields of the [`Schema`].
1321///
1322/// The value can either be [`RefOr`] or _`bool`_.
1323#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
1324#[cfg_attr(feature = "debug", derive(Debug))]
1325#[serde(untagged)]
1326pub enum AdditionalProperties<T> {
1327    /// Use when value type of the map is a known [`Schema`] or [`Ref`] to the [`Schema`].
1328    RefOr(RefOr<T>),
1329    /// Use _`AdditionalProperties::FreeForm(true)`_ when any value is allowed in the map.
1330    FreeForm(bool),
1331}
1332
1333impl<T> From<RefOr<T>> for AdditionalProperties<T> {
1334    fn from(value: RefOr<T>) -> Self {
1335        Self::RefOr(value)
1336    }
1337}
1338
1339impl From<ObjectBuilder> for AdditionalProperties<Schema> {
1340    fn from(value: ObjectBuilder) -> Self {
1341        Self::RefOr(RefOr::T(Schema::Object(value.build())))
1342    }
1343}
1344
1345impl From<ArrayBuilder> for AdditionalProperties<Schema> {
1346    fn from(value: ArrayBuilder) -> Self {
1347        Self::RefOr(RefOr::T(Schema::Array(value.build())))
1348    }
1349}
1350
1351impl From<Ref> for AdditionalProperties<Schema> {
1352    fn from(value: Ref) -> Self {
1353        Self::RefOr(RefOr::Ref(value))
1354    }
1355}
1356
1357impl From<RefBuilder> for AdditionalProperties<Schema> {
1358    fn from(value: RefBuilder) -> Self {
1359        Self::RefOr(RefOr::Ref(value.build()))
1360    }
1361}
1362
1363impl From<Schema> for AdditionalProperties<Schema> {
1364    fn from(value: Schema) -> Self {
1365        Self::RefOr(RefOr::T(value))
1366    }
1367}
1368
1369impl From<AllOfBuilder> for AdditionalProperties<Schema> {
1370    fn from(value: AllOfBuilder) -> Self {
1371        Self::RefOr(RefOr::T(Schema::AllOf(value.build())))
1372    }
1373}
1374
1375builder! {
1376    RefBuilder;
1377
1378    /// Implements [OpenAPI Reference Object][reference] that can be used to reference
1379    /// reusable components such as [`Schema`]s or [`Response`]s.
1380    ///
1381    /// [reference]: https://spec.openapis.org/oas/latest.html#reference-object
1382    #[non_exhaustive]
1383    #[derive(Serialize, Deserialize, Default, Clone, PartialEq, Eq)]
1384    #[cfg_attr(feature = "debug", derive(Debug))]
1385    pub struct Ref {
1386        /// Reference location of the actual component.
1387        #[serde(rename = "$ref")]
1388        pub ref_location: String,
1389
1390        /// A description which by default should override that of the referenced component.
1391        /// Description supports markdown syntax. If referenced object type does not support
1392        /// description this field does not have effect.
1393        #[serde(skip_serializing_if = "String::is_empty", default)]
1394        pub description: String,
1395
1396        /// A short summary which by default should override that of the referenced component. If
1397        /// referenced component does not support summary field this does not have effect.
1398        #[serde(skip_serializing_if = "String::is_empty", default)]
1399        pub summary: String,
1400    }
1401}
1402
1403impl Ref {
1404    /// Construct a new [`Ref`] with custom ref location. In most cases this is not necessary
1405    /// and [`Ref::from_schema_name`] could be used instead.
1406    pub fn new<I: Into<String>>(ref_location: I) -> Self {
1407        Self {
1408            ref_location: ref_location.into(),
1409            ..Default::default()
1410        }
1411    }
1412
1413    /// Construct a new [`Ref`] from provided schema name. This will create a [`Ref`] that
1414    /// references the the reusable schemas.
1415    pub fn from_schema_name<I: Into<String>>(schema_name: I) -> Self {
1416        Self::new(format!("#/components/schemas/{}", schema_name.into()))
1417    }
1418
1419    /// Construct a new [`Ref`] from provided response name. This will create a [`Ref`] that
1420    /// references the reusable response.
1421    pub fn from_response_name<I: Into<String>>(response_name: I) -> Self {
1422        Self::new(format!("#/components/responses/{}", response_name.into()))
1423    }
1424
1425    to_array_builder!();
1426}
1427
1428impl RefBuilder {
1429    /// Add or change reference location of the actual component.
1430    pub fn ref_location(mut self, ref_location: String) -> Self {
1431        set_value!(self ref_location ref_location)
1432    }
1433
1434    /// Add or change reference location of the actual component automatically formatting the $ref
1435    /// to `#/components/schemas/...` format.
1436    pub fn ref_location_from_schema_name<S: Into<String>>(mut self, schema_name: S) -> Self {
1437        set_value!(self ref_location format!("#/components/schemas/{}", schema_name.into()))
1438    }
1439
1440    // TODO: REMOVE THE unnecessary description Option wrapping.
1441
1442    /// Add or change description which by default should override that of the referenced component.
1443    /// Description supports markdown syntax. If referenced object type does not support
1444    /// description this field does not have effect.
1445    pub fn description<S: Into<String>>(mut self, description: Option<S>) -> Self {
1446        set_value!(self description description.map(Into::into).unwrap_or_default())
1447    }
1448
1449    /// Add or change short summary which by default should override that of the referenced component. If
1450    /// referenced component does not support summary field this does not have effect.
1451    pub fn summary<S: Into<String>>(mut self, summary: S) -> Self {
1452        set_value!(self summary summary.into())
1453    }
1454}
1455
1456impl From<RefBuilder> for RefOr<Schema> {
1457    fn from(builder: RefBuilder) -> Self {
1458        Self::Ref(builder.build())
1459    }
1460}
1461
1462impl From<RefBuilder> for ArrayItems {
1463    fn from(value: RefBuilder) -> Self {
1464        Self::RefOrSchema(Box::new(value.into()))
1465    }
1466}
1467
1468impl From<Ref> for RefOr<Schema> {
1469    fn from(r: Ref) -> Self {
1470        Self::Ref(r)
1471    }
1472}
1473
1474impl From<Ref> for ArrayItems {
1475    fn from(value: Ref) -> Self {
1476        Self::RefOrSchema(Box::new(value.into()))
1477    }
1478}
1479
1480impl<T> From<T> for RefOr<T> {
1481    fn from(t: T) -> Self {
1482        Self::T(t)
1483    }
1484}
1485
1486impl Default for RefOr<Schema> {
1487    fn default() -> Self {
1488        Self::T(Schema::Object(Object::new()))
1489    }
1490}
1491
1492impl ToArray for RefOr<Schema> {}
1493
1494impl From<Object> for RefOr<Schema> {
1495    fn from(object: Object) -> Self {
1496        Self::T(Schema::Object(object))
1497    }
1498}
1499
1500impl From<Array> for RefOr<Schema> {
1501    fn from(array: Array) -> Self {
1502        Self::T(Schema::Array(array))
1503    }
1504}
1505
1506fn omit_decimal_zero<S>(
1507    maybe_value: &Option<crate::utoipa::Number>,
1508    serializer: S,
1509) -> Result<S::Ok, S::Error>
1510where
1511    S: serde::Serializer,
1512{
1513    match maybe_value {
1514        Some(crate::utoipa::Number::Float(float)) => {
1515            if float.fract() == 0.0 && *float >= i64::MIN as f64 && *float <= i64::MAX as f64 {
1516                serializer.serialize_i64(float.trunc() as i64)
1517            } else {
1518                serializer.serialize_f64(*float)
1519            }
1520        }
1521        Some(crate::utoipa::Number::Int(int)) => serializer.serialize_i64(*int as i64),
1522        Some(crate::utoipa::Number::UInt(uint)) => serializer.serialize_u64(*uint as u64),
1523        None => serializer.serialize_none(),
1524    }
1525}
1526
1527/// Represents [`Array`] items in [JSON Schema Array][json_schema_array].
1528///
1529/// [json_schema_array]: <https://json-schema.org/understanding-json-schema/reference/array#items>
1530#[derive(Serialize, Deserialize, Clone, PartialEq)]
1531#[cfg_attr(feature = "debug", derive(Debug))]
1532#[serde(untagged)]
1533pub enum ArrayItems {
1534    /// Defines [`Array::items`] as [`RefOr::T(Schema)`]. This is the default for [`Array`].
1535    RefOrSchema(Box<RefOr<Schema>>),
1536    /// Defines [`Array::items`] as `false` indicating that no extra items are allowed to the
1537    /// [`Array`]. This can be used together with [`Array::prefix_items`] to disallow [additional
1538    /// items][additional_items] in [`Array`].
1539    ///
1540    /// [additional_items]: <https://json-schema.org/understanding-json-schema/reference/array#additionalitems>
1541    #[serde(with = "array_items_false")]
1542    False,
1543}
1544
1545mod array_items_false {
1546    use serde::de::Visitor;
1547
1548    pub fn serialize<S: serde::Serializer>(serializer: S) -> Result<S::Ok, S::Error> {
1549        serializer.serialize_bool(false)
1550    }
1551
1552    pub fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<(), D::Error> {
1553        struct ItemsFalseVisitor;
1554
1555        impl<'de> Visitor<'de> for ItemsFalseVisitor {
1556            type Value = ();
1557            fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
1558            where
1559                E: serde::de::Error,
1560            {
1561                if !v {
1562                    Ok(())
1563                } else {
1564                    Err(serde::de::Error::custom(format!(
1565                        "invalid boolean value: {v}, expected false"
1566                    )))
1567                }
1568            }
1569
1570            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
1571                formatter.write_str("expected boolean false")
1572            }
1573        }
1574
1575        deserializer.deserialize_bool(ItemsFalseVisitor)
1576    }
1577}
1578
1579impl Default for ArrayItems {
1580    fn default() -> Self {
1581        Self::RefOrSchema(Box::new(Object::with_type(SchemaType::AnyValue).into()))
1582    }
1583}
1584
1585impl From<RefOr<Schema>> for ArrayItems {
1586    fn from(value: RefOr<Schema>) -> Self {
1587        Self::RefOrSchema(Box::new(value))
1588    }
1589}
1590
1591builder! {
1592    ArrayBuilder;
1593
1594    /// Array represents [`Vec`] or [`slice`] type  of items.
1595    ///
1596    /// See [`Schema::Array`] for more details.
1597    #[non_exhaustive]
1598    #[derive(Serialize, Deserialize, Clone, PartialEq)]
1599    #[cfg_attr(feature = "debug", derive(Debug))]
1600    #[serde(rename_all = "camelCase")]
1601    pub struct Array {
1602        /// Type will always be [`SchemaType::Array`].
1603        #[serde(rename = "type")]
1604        pub schema_type: SchemaType,
1605
1606        /// Changes the [`Array`] title.
1607        #[serde(skip_serializing_if = "Option::is_none")]
1608        pub title: Option<String>,
1609
1610        /// Items of the [`Array`].
1611        pub items: ArrayItems,
1612
1613        /// Prefix items of [`Array`] is used to define item validation of tuples according [JSON schema
1614        /// item validation][item_validation].
1615        ///
1616        /// [item_validation]: <https://json-schema.org/understanding-json-schema/reference/array#tupleValidation>
1617        #[serde(skip_serializing_if = "Vec::is_empty", default)]
1618        pub prefix_items: Vec<Schema>,
1619
1620        /// Description of the [`Array`]. Markdown syntax is supported.
1621        #[serde(skip_serializing_if = "Option::is_none")]
1622        pub description: Option<String>,
1623
1624        /// Marks the [`Array`] deprecated.
1625        #[serde(skip_serializing_if = "Option::is_none")]
1626        pub deprecated: Option<Deprecated>,
1627
1628        /// Example shown in UI of the value for richer documentation.
1629        ///
1630        /// **Deprecated since 3.0.x. Prefer [`Array::examples`] instead**
1631        #[serde(skip_serializing_if = "Option::is_none")]
1632        pub example: Option<Value>,
1633
1634        /// Examples shown in UI of the value for richer documentation.
1635        #[serde(skip_serializing_if = "Vec::is_empty", default)]
1636        pub examples: Vec<Value>,
1637
1638        /// Default value which is provided when user has not provided the input in Swagger UI.
1639        #[serde(skip_serializing_if = "Option::is_none")]
1640        pub default: Option<Value>,
1641
1642        /// Max length of the array.
1643        #[serde(skip_serializing_if = "Option::is_none")]
1644        pub max_items: Option<usize>,
1645
1646        /// Min length of the array.
1647        #[serde(skip_serializing_if = "Option::is_none")]
1648        pub min_items: Option<usize>,
1649
1650        /// Setting this to `true` will validate successfully if all elements of this [`Array`] are
1651        /// unique.
1652        #[serde(default, skip_serializing_if = "is_false")]
1653        pub unique_items: bool,
1654
1655        /// Xml format of the array.
1656        #[serde(skip_serializing_if = "Option::is_none")]
1657        pub xml: Option<Xml>,
1658
1659        /// The `content_encoding` keyword specifies the encoding used to store the contents, as specified in
1660        /// [RFC 2054, part 6.1](https://tools.ietf.org/html/rfc2045) and [RFC 4648](RFC 2054, part 6.1).
1661        ///
1662        /// Typically this is either unset for _`string`_ content types which then uses the content
1663        /// encoding of the underlying JSON document. If the content is in _`binary`_ format such as an image or an audio
1664        /// set it to `base64` to encode it as _`Base64`_.
1665        ///
1666        /// See more details at <https://json-schema.org/understanding-json-schema/reference/non_json_data#contentencoding>
1667        #[serde(skip_serializing_if = "String::is_empty", default)]
1668        pub content_encoding: String,
1669
1670        /// The _`content_media_type`_ keyword specifies the MIME type of the contents of a string,
1671        /// as described in [RFC 2046](https://tools.ietf.org/html/rfc2046).
1672        ///
1673        /// See more details at <https://json-schema.org/understanding-json-schema/reference/non_json_data#contentmediatype>
1674        #[serde(skip_serializing_if = "String::is_empty", default)]
1675        pub content_media_type: String,
1676
1677        /// Optional extensions `x-something`.
1678        #[serde(skip_serializing_if = "Option::is_none", flatten)]
1679        pub extensions: Option<Extensions>,
1680    }
1681}
1682
1683impl Default for Array {
1684    fn default() -> Self {
1685        Self {
1686            title: Default::default(),
1687            schema_type: Type::Array.into(),
1688            unique_items: bool::default(),
1689            items: Default::default(),
1690            prefix_items: Vec::default(),
1691            description: Default::default(),
1692            deprecated: Default::default(),
1693            example: Default::default(),
1694            examples: Default::default(),
1695            default: Default::default(),
1696            max_items: Default::default(),
1697            min_items: Default::default(),
1698            xml: Default::default(),
1699            extensions: Default::default(),
1700            content_encoding: Default::default(),
1701            content_media_type: Default::default(),
1702        }
1703    }
1704}
1705
1706impl Array {
1707    /// Construct a new [`Array`] component from given [`Schema`].
1708    ///
1709    /// # Examples
1710    ///
1711    /// _**Create a `String` array component**_.
1712    /// ```rust
1713    /// # use utoipa::openapi::schema::{Schema, Array, Type, Object};
1714    /// let string_array = Array::new(Object::with_type(Type::String));
1715    /// ```
1716    pub fn new<I: Into<RefOr<Schema>>>(component: I) -> Self {
1717        Self {
1718            items: ArrayItems::RefOrSchema(Box::new(component.into())),
1719            ..Default::default()
1720        }
1721    }
1722
1723    /// Construct a new nullable [`Array`] component from given [`Schema`].
1724    ///
1725    /// # Examples
1726    ///
1727    /// _**Create a nullable `String` array component**_.
1728    /// ```rust
1729    /// # use utoipa::openapi::schema::{Schema, Array, Type, Object};
1730    /// let string_array = Array::new_nullable(Object::with_type(Type::String));
1731    /// ```
1732    pub fn new_nullable<I: Into<RefOr<Schema>>>(component: I) -> Self {
1733        Self {
1734            items: ArrayItems::RefOrSchema(Box::new(component.into())),
1735            schema_type: SchemaType::from_iter([Type::Array, Type::Null]),
1736            ..Default::default()
1737        }
1738    }
1739}
1740
1741impl ArrayBuilder {
1742    /// Set [`Schema`] type for the [`Array`].
1743    pub fn items<I: Into<ArrayItems>>(mut self, items: I) -> Self {
1744        set_value!(self items items.into())
1745    }
1746
1747    /// Add prefix items of [`Array`] to define item validation of tuples according [JSON schema
1748    /// item validation][item_validation].
1749    ///
1750    /// [item_validation]: <https://json-schema.org/understanding-json-schema/reference/array#tupleValidation>
1751    pub fn prefix_items<I: IntoIterator<Item = S>, S: Into<Schema>>(mut self, items: I) -> Self {
1752        self.prefix_items = items
1753            .into_iter()
1754            .map(|item| item.into())
1755            .collect::<Vec<_>>();
1756
1757        self
1758    }
1759
1760    /// Change type of the array e.g. to change type to _`string`_
1761    /// use value `SchemaType::Type(Type::String)`.
1762    ///
1763    /// # Examples
1764    ///
1765    /// _**Make nullable string array.**_
1766    /// ```rust
1767    /// # use utoipa::openapi::schema::{ArrayBuilder, SchemaType, Type, Object};
1768    /// let _ = ArrayBuilder::new()
1769    ///     .schema_type(SchemaType::from_iter([Type::Array, Type::Null]))
1770    ///     .items(Object::with_type(Type::String))
1771    ///     .build();
1772    /// ```
1773    pub fn schema_type<T: Into<SchemaType>>(mut self, schema_type: T) -> Self {
1774        set_value!(self schema_type schema_type.into())
1775    }
1776
1777    /// Add or change the title of the [`Array`].
1778    pub fn title<I: Into<String>>(mut self, title: Option<I>) -> Self {
1779        set_value!(self title title.map(|title| title.into()))
1780    }
1781
1782    /// Add or change description of the property. Markdown syntax is supported.
1783    pub fn description<I: Into<String>>(mut self, description: Option<I>) -> Self {
1784        set_value!(self description description.map(|description| description.into()))
1785    }
1786
1787    /// Add or change deprecated status for [`Array`].
1788    pub fn deprecated(mut self, deprecated: Option<Deprecated>) -> Self {
1789        set_value!(self deprecated deprecated)
1790    }
1791
1792    /// Add or change example shown in UI of the value for richer documentation.
1793    ///
1794    /// **Deprecated since 3.0.x. Prefer [`Array::examples`] instead**
1795    #[deprecated = "Since OpenAPI 3.1 prefer using `examples`"]
1796    pub fn example(mut self, example: Option<Value>) -> Self {
1797        set_value!(self example example)
1798    }
1799
1800    /// Add or change examples shown in UI of the value for richer documentation.
1801    pub fn examples<I: IntoIterator<Item = V>, V: Into<Value>>(mut self, examples: I) -> Self {
1802        set_value!(self examples examples.into_iter().map(Into::into).collect())
1803    }
1804
1805    /// Add or change default value for the object which is provided when user has not provided the input in Swagger UI.
1806    pub fn default(mut self, default: Option<Value>) -> Self {
1807        set_value!(self default default)
1808    }
1809
1810    /// Set maximum allowed length for [`Array`].
1811    pub fn max_items(mut self, max_items: Option<usize>) -> Self {
1812        set_value!(self max_items max_items)
1813    }
1814
1815    /// Set minimum allowed length for [`Array`].
1816    pub fn min_items(mut self, min_items: Option<usize>) -> Self {
1817        set_value!(self min_items min_items)
1818    }
1819
1820    /// Set or change whether [`Array`] should enforce all items to be unique.
1821    pub fn unique_items(mut self, unique_items: bool) -> Self {
1822        set_value!(self unique_items unique_items)
1823    }
1824
1825    /// Set [`Xml`] formatting for [`Array`].
1826    pub fn xml(mut self, xml: Option<Xml>) -> Self {
1827        set_value!(self xml xml)
1828    }
1829
1830    /// Set of change [`Object::content_encoding`]. Typically left empty but could be `base64` for
1831    /// example.
1832    pub fn content_encoding<S: Into<String>>(mut self, content_encoding: S) -> Self {
1833        set_value!(self content_encoding content_encoding.into())
1834    }
1835
1836    /// Set of change [`Object::content_media_type`]. Value must be valid MIME type e.g.
1837    /// `application/json`.
1838    pub fn content_media_type<S: Into<String>>(mut self, content_media_type: S) -> Self {
1839        set_value!(self content_media_type content_media_type.into())
1840    }
1841
1842    /// Add openapi extensions (`x-something`) for [`Array`].
1843    pub fn extensions(mut self, extensions: Option<Extensions>) -> Self {
1844        set_value!(self extensions extensions)
1845    }
1846
1847    to_array_builder!();
1848}
1849
1850component_from_builder!(ArrayBuilder);
1851
1852impl From<Array> for Schema {
1853    fn from(array: Array) -> Self {
1854        Self::Array(array)
1855    }
1856}
1857
1858impl From<ArrayBuilder> for ArrayItems {
1859    fn from(value: ArrayBuilder) -> Self {
1860        Self::RefOrSchema(Box::new(value.into()))
1861    }
1862}
1863
1864impl From<ArrayBuilder> for RefOr<Schema> {
1865    fn from(array: ArrayBuilder) -> Self {
1866        Self::T(Schema::Array(array.build()))
1867    }
1868}
1869
1870impl ToArray for Array {}
1871
1872/// This convenience trait allows quick way to wrap any `RefOr<Schema>` with [`Array`] schema.
1873pub trait ToArray
1874where
1875    RefOr<Schema>: From<Self>,
1876    Self: Sized,
1877{
1878    /// Wrap this `RefOr<Schema>` with [`Array`].
1879    fn to_array(self) -> Array {
1880        Array::new(self)
1881    }
1882}
1883
1884/// Represents type of [`Schema`].
1885///
1886/// This is a collection type for [`Type`] that can be represented as a single value
1887/// or as [`slice`] of [`Type`]s.
1888#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
1889#[cfg_attr(feature = "debug", derive(Debug))]
1890#[serde(untagged)]
1891pub enum SchemaType {
1892    /// Single type known from OpenAPI spec 3.0
1893    Type(Type),
1894    /// Multiple types rendered as [`slice`]
1895    Array(Vec<Type>),
1896    /// Type that is considered typeless. _`AnyValue`_ will omit the type definition from the schema
1897    /// making it to accept any type possible.
1898    AnyValue,
1899}
1900
1901impl Default for SchemaType {
1902    fn default() -> Self {
1903        Self::Type(Type::default())
1904    }
1905}
1906
1907impl From<Type> for SchemaType {
1908    fn from(value: Type) -> Self {
1909        SchemaType::new(value)
1910    }
1911}
1912
1913impl FromIterator<Type> for SchemaType {
1914    fn from_iter<T: IntoIterator<Item = Type>>(iter: T) -> Self {
1915        Self::Array(iter.into_iter().collect())
1916    }
1917}
1918
1919impl SchemaType {
1920    /// Instantiate new [`SchemaType`] of given [`Type`]
1921    ///
1922    /// Method accepts one argument `type` to create [`SchemaType`] for.
1923    ///
1924    /// # Examples
1925    ///
1926    /// _**Create string [`SchemaType`]**_
1927    /// ```rust
1928    /// # use utoipa::openapi::schema::{SchemaType, Type};
1929    /// let ty = SchemaType::new(Type::String);
1930    /// ```
1931    pub fn new(r#type: Type) -> Self {
1932        Self::Type(r#type)
1933    }
1934
1935    //// Instantiate new [`SchemaType::AnyValue`].
1936    ///
1937    /// This is same as calling [`SchemaType::AnyValue`] but in a function form `() -> SchemaType`
1938    /// allowing it to be used as argument for _serde's_ _`default = "..."`_.
1939    pub fn any() -> Self {
1940        SchemaType::AnyValue
1941    }
1942
1943    /// Check whether this [`SchemaType`] is any value _(typeless)_ returning true on any value
1944    /// schema type.
1945    pub fn is_any_value(&self) -> bool {
1946        matches!(self, Self::AnyValue)
1947    }
1948}
1949
1950/// Represents data type fragment of [`Schema`].
1951///
1952/// [`Type`] is used to create a [`SchemaType`] that defines the type of the [`Schema`].
1953/// [`SchemaType`] can be created from a single [`Type`] or multiple [`Type`]s according to the
1954/// OpenAPI 3.1 spec. Since the OpenAPI 3.1 is fully compatible with JSON schema the definition of
1955/// the _**type**_ property comes from [JSON Schema type](https://json-schema.org/understanding-json-schema/reference/type).
1956///
1957/// # Examples
1958/// _**Create nullable string [`SchemaType`]**_
1959/// ```rust
1960/// # use std::iter::FromIterator;
1961/// # use utoipa::openapi::schema::{Type, SchemaType};
1962/// let _: SchemaType = [Type::String, Type::Null].into_iter().collect();
1963/// ```
1964/// _**Create string [`SchemaType`]**_
1965/// ```rust
1966/// # use utoipa::openapi::schema::{Type, SchemaType};
1967/// let _ = SchemaType::new(Type::String);
1968/// ```
1969#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Default)]
1970#[cfg_attr(feature = "debug", derive(Debug))]
1971#[serde(rename_all = "lowercase")]
1972pub enum Type {
1973    /// Used with [`Object`] and [`ObjectBuilder`] to describe schema that has _properties_
1974    /// describing fields.
1975    #[default]
1976    Object,
1977    /// Indicates string type of content. Used with [`Object`] and [`ObjectBuilder`] on a `string`
1978    /// field.
1979    String,
1980    /// Indicates integer type of content. Used with [`Object`] and [`ObjectBuilder`] on a `number`
1981    /// field.
1982    Integer,
1983    /// Indicates floating point number type of content. Used with
1984    /// [`Object`] and [`ObjectBuilder`] on a `number` field.
1985    Number,
1986    /// Indicates boolean type of content. Used with [`Object`] and [`ObjectBuilder`] on
1987    /// a `bool` field.
1988    Boolean,
1989    /// Used with [`Array`] and [`ArrayBuilder`]. Indicates array type of content.
1990    Array,
1991    /// Null type. Used together with other type to indicate nullable values.
1992    Null,
1993}
1994
1995/// Additional format for [`SchemaType`] to fine tune the data type used. If the **format** is not
1996/// supported by the UI it may default back to [`SchemaType`] alone.
1997/// Format is an open value, so you can use any formats, even not those defined by the
1998/// OpenAPI Specification.
1999#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
2000#[cfg_attr(feature = "debug", derive(Debug))]
2001#[serde(rename_all = "lowercase", untagged)]
2002pub enum SchemaFormat {
2003    /// Use to define additional detail about the value.
2004    KnownFormat(KnownFormat),
2005    /// Can be used to provide additional detail about the value when [`SchemaFormat::KnownFormat`]
2006    /// is not suitable.
2007    Custom(String),
2008}
2009
2010/// Known schema format modifier property to provide fine detail of the primitive type.
2011///
2012/// Known format is defined in <https://spec.openapis.org/oas/latest.html#data-types> and
2013/// <https://datatracker.ietf.org/doc/html/draft-bhutton-json-schema-validation-00#section-7.3> as
2014/// well as by few known data types that are enabled by specific feature flag e.g. _`uuid`_.
2015#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
2016#[cfg_attr(feature = "debug", derive(Debug))]
2017#[serde(rename_all = "kebab-case")]
2018pub enum KnownFormat {
2019    /// 8 bit integer.
2020    #[cfg(feature = "non_strict_integers")]
2021    #[cfg_attr(doc_cfg, doc(cfg(feature = "non_strict_integers")))]
2022    Int8,
2023    /// 16 bit integer.
2024    #[cfg(feature = "non_strict_integers")]
2025    #[cfg_attr(doc_cfg, doc(cfg(feature = "non_strict_integers")))]
2026    Int16,
2027    /// 32 bit integer.
2028    Int32,
2029    /// 64 bit integer.
2030    Int64,
2031    /// 8 bit unsigned integer.
2032    #[cfg(feature = "non_strict_integers")]
2033    #[cfg_attr(doc_cfg, doc(cfg(feature = "non_strict_integers")))]
2034    UInt8,
2035    /// 16 bit unsigned integer.
2036    #[cfg(feature = "non_strict_integers")]
2037    #[cfg_attr(doc_cfg, doc(cfg(feature = "non_strict_integers")))]
2038    UInt16,
2039    /// 32 bit unsigned integer.
2040    #[cfg(feature = "non_strict_integers")]
2041    #[cfg_attr(doc_cfg, doc(cfg(feature = "non_strict_integers")))]
2042    UInt32,
2043    /// 64 bit unsigned integer.
2044    #[cfg(feature = "non_strict_integers")]
2045    #[cfg_attr(doc_cfg, doc(cfg(feature = "non_strict_integers")))]
2046    UInt64,
2047    /// floating point number.
2048    Float,
2049    /// double (floating point) number.
2050    Double,
2051    /// base64 encoded chars.
2052    Byte,
2053    /// binary data (octet).
2054    Binary,
2055    /// ISO-8601 full time format [RFC3339](https://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14).
2056    Time,
2057    /// ISO-8601 full date [RFC3339](https://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14).
2058    Date,
2059    /// ISO-8601 full date time [RFC3339](https://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14).
2060    DateTime,
2061    /// duration format from [RFC3339 Appendix-A](https://datatracker.ietf.org/doc/html/rfc3339#appendix-A).
2062    Duration,
2063    /// Hint to UI to obscure input.
2064    Password,
2065    /// Used with [`String`] values to indicate value is in UUID format.
2066    ///
2067    /// **uuid** feature need to be enabled.
2068    #[cfg(feature = "uuid")]
2069    #[cfg_attr(doc_cfg, doc(cfg(feature = "uuid")))]
2070    Uuid,
2071    /// Used with [`String`] values to indicate value is in ULID format.
2072    #[cfg(feature = "ulid")]
2073    #[cfg_attr(doc_cfg, doc(cfg(feature = "ulid")))]
2074    Ulid,
2075    /// Used with [`String`] values to indicate value is in Url format according to
2076    /// [RFC3986](https://datatracker.ietf.org/doc/html/rfc3986).
2077    #[cfg(feature = "url")]
2078    #[cfg_attr(doc_cfg, doc(cfg(feature = "url")))]
2079    Uri,
2080    /// A string instance is valid against this attribute if it is a valid URI Reference
2081    /// (either a URI or a relative-reference) according to
2082    /// [RFC3986](https://datatracker.ietf.org/doc/html/rfc3986).
2083    #[cfg(feature = "url")]
2084    #[cfg_attr(doc_cfg, doc(cfg(feature = "url")))]
2085    UriReference,
2086    /// A string instance is valid against this attribute if it is a
2087    /// valid IRI, according to [RFC3987](https://datatracker.ietf.org/doc/html/rfc3987).
2088    #[cfg(feature = "url")]
2089    #[cfg_attr(doc_cfg, doc(cfg(feature = "url")))]
2090    Iri,
2091    /// A string instance is valid against this attribute if it is a valid IRI Reference
2092    /// (either an IRI or a relative-reference)
2093    /// according to [RFC3987](https://datatracker.ietf.org/doc/html/rfc3987).
2094    #[cfg(feature = "url")]
2095    #[cfg_attr(doc_cfg, doc(cfg(feature = "url")))]
2096    IriReference,
2097    /// As defined in "Mailbox" rule [RFC5321](https://datatracker.ietf.org/doc/html/rfc5321#section-4.1.2).
2098    Email,
2099    /// As defined by extended "Mailbox" rule [RFC6531](https://datatracker.ietf.org/doc/html/rfc6531#section-3.3).
2100    IdnEmail,
2101    /// As defined by [RFC1123](https://datatracker.ietf.org/doc/html/rfc1123#section-2.1), including host names
2102    /// produced using the Punycode algorithm
2103    /// specified in [RFC5891](https://datatracker.ietf.org/doc/html/rfc5891#section-4.4).
2104    Hostname,
2105    /// As defined by either [RFC1123](https://datatracker.ietf.org/doc/html/rfc1123#section-2.1) as for hostname,
2106    /// or an internationalized hostname as defined by [RFC5890](https://datatracker.ietf.org/doc/html/rfc5890#section-2.3.2.3).
2107    IdnHostname,
2108    /// An IPv4 address according to [RFC2673](https://datatracker.ietf.org/doc/html/rfc2673#section-3.2).
2109    Ipv4,
2110    /// An IPv6 address according to [RFC4291](https://datatracker.ietf.org/doc/html/rfc4291#section-2.2).
2111    Ipv6,
2112    /// A string instance is a valid URI Template if it is according to
2113    /// [RFC6570](https://datatracker.ietf.org/doc/html/rfc6570).
2114    ///
2115    /// _**Note!**_ There are no separate IRL template.
2116    UriTemplate,
2117    /// A valid JSON string representation of a JSON Pointer according to [RFC6901](https://datatracker.ietf.org/doc/html/rfc6901#section-5).
2118    JsonPointer,
2119    /// A valid relative JSON Pointer according to [draft-handrews-relative-json-pointer-01](https://datatracker.ietf.org/doc/html/draft-handrews-relative-json-pointer-01).
2120    RelativeJsonPointer,
2121    /// Regular expression, which SHOULD be valid according to the
2122    /// [ECMA-262](https://datatracker.ietf.org/doc/html/draft-bhutton-json-schema-validation-00#ref-ecma262).
2123    Regex,
2124}
2125
2126#[cfg(test)]
2127mod tests {
2128    use insta::assert_json_snapshot;
2129    use serde_json::{json, Value};
2130
2131    use super::*;
2132    use crate::openapi::*;
2133
2134    #[test]
2135    fn create_schema_serializes_json() -> Result<(), serde_json::Error> {
2136        let openapi = OpenApiBuilder::new()
2137            .info(Info::new("My api", "1.0.0"))
2138            .paths(Paths::new())
2139            .components(Some(
2140                ComponentsBuilder::new()
2141                    .schema("Person", Ref::new("#/components/PersonModel"))
2142                    .schema(
2143                        "Credential",
2144                        Schema::from(
2145                            ObjectBuilder::new()
2146                                .property(
2147                                    "id",
2148                                    ObjectBuilder::new()
2149                                        .schema_type(Type::Integer)
2150                                        .format(Some(SchemaFormat::KnownFormat(KnownFormat::Int32)))
2151                                        .description(Some("Id of credential"))
2152                                        .default(Some(json!(1i32))),
2153                                )
2154                                .property(
2155                                    "name",
2156                                    ObjectBuilder::new()
2157                                        .schema_type(Type::String)
2158                                        .description(Some("Name of credential")),
2159                                )
2160                                .property(
2161                                    "status",
2162                                    ObjectBuilder::new()
2163                                        .schema_type(Type::String)
2164                                        .default(Some(json!("Active")))
2165                                        .description(Some("Credential status"))
2166                                        .enum_values(Some([
2167                                            "Active",
2168                                            "NotActive",
2169                                            "Locked",
2170                                            "Expired",
2171                                        ])),
2172                                )
2173                                .property(
2174                                    "history",
2175                                    Array::new(Ref::from_schema_name("UpdateHistory")),
2176                                )
2177                                .property("tags", Object::with_type(Type::String).to_array()),
2178                        ),
2179                    )
2180                    .build(),
2181            ))
2182            .build();
2183
2184        let serialized = serde_json::to_string_pretty(&openapi)?;
2185        println!("serialized json:\n {serialized}");
2186
2187        let value = serde_json::to_value(&openapi)?;
2188        let credential = get_json_path(&value, "components.schemas.Credential.properties");
2189        let person = get_json_path(&value, "components.schemas.Person");
2190
2191        assert!(
2192            credential.get("id").is_some(),
2193            "could not find path: components.schemas.Credential.properties.id"
2194        );
2195        assert!(
2196            credential.get("status").is_some(),
2197            "could not find path: components.schemas.Credential.properties.status"
2198        );
2199        assert!(
2200            credential.get("name").is_some(),
2201            "could not find path: components.schemas.Credential.properties.name"
2202        );
2203        assert!(
2204            credential.get("history").is_some(),
2205            "could not find path: components.schemas.Credential.properties.history"
2206        );
2207        assert_eq!(
2208            credential
2209                .get("id")
2210                .unwrap_or(&serde_json::value::Value::Null)
2211                .to_string(),
2212            r#"{"default":1,"description":"Id of credential","format":"int32","type":"integer"}"#,
2213            "components.schemas.Credential.properties.id did not match"
2214        );
2215        assert_eq!(
2216            credential
2217                .get("name")
2218                .unwrap_or(&serde_json::value::Value::Null)
2219                .to_string(),
2220            r#"{"description":"Name of credential","type":"string"}"#,
2221            "components.schemas.Credential.properties.name did not match"
2222        );
2223        assert_eq!(
2224            credential
2225                .get("status")
2226                .unwrap_or(&serde_json::value::Value::Null)
2227                .to_string(),
2228            r#"{"default":"Active","description":"Credential status","enum":["Active","NotActive","Locked","Expired"],"type":"string"}"#,
2229            "components.schemas.Credential.properties.status did not match"
2230        );
2231        assert_eq!(
2232            credential
2233                .get("history")
2234                .unwrap_or(&serde_json::value::Value::Null)
2235                .to_string(),
2236            r###"{"items":{"$ref":"#/components/schemas/UpdateHistory"},"type":"array"}"###,
2237            "components.schemas.Credential.properties.history did not match"
2238        );
2239        assert_eq!(
2240            person.to_string(),
2241            r###"{"$ref":"#/components/PersonModel"}"###,
2242            "components.schemas.Person.ref did not match"
2243        );
2244
2245        Ok(())
2246    }
2247
2248    // Examples taken from https://spec.openapis.org/oas/latest.html#model-with-map-dictionary-properties
2249    #[test]
2250    fn test_property_order() {
2251        let json_value = ObjectBuilder::new()
2252            .property(
2253                "id",
2254                ObjectBuilder::new()
2255                    .schema_type(Type::Integer)
2256                    .format(Some(SchemaFormat::KnownFormat(KnownFormat::Int32)))
2257                    .description(Some("Id of credential"))
2258                    .default(Some(json!(1i32))),
2259            )
2260            .property(
2261                "name",
2262                ObjectBuilder::new()
2263                    .schema_type(Type::String)
2264                    .description(Some("Name of credential")),
2265            )
2266            .property(
2267                "status",
2268                ObjectBuilder::new()
2269                    .schema_type(Type::String)
2270                    .default(Some(json!("Active")))
2271                    .description(Some("Credential status"))
2272                    .enum_values(Some(["Active", "NotActive", "Locked", "Expired"])),
2273            )
2274            .property(
2275                "history",
2276                Array::new(Ref::from_schema_name("UpdateHistory")),
2277            )
2278            .property("tags", Object::with_type(Type::String).to_array())
2279            .build();
2280
2281        #[cfg(not(feature = "preserve_order"))]
2282        assert_eq!(
2283            json_value.properties.keys().collect::<Vec<_>>(),
2284            vec!["history", "id", "name", "status", "tags"]
2285        );
2286
2287        #[cfg(feature = "preserve_order")]
2288        assert_eq!(
2289            json_value.properties.keys().collect::<Vec<_>>(),
2290            vec!["id", "name", "status", "history", "tags"]
2291        );
2292    }
2293
2294    // Examples taken from https://spec.openapis.org/oas/latest.html#model-with-map-dictionary-properties
2295    #[test]
2296    fn test_additional_properties() {
2297        let json_value = ObjectBuilder::new()
2298            .additional_properties(Some(ObjectBuilder::new().schema_type(Type::String)))
2299            .build();
2300        assert_json_snapshot!(json_value, @r#"
2301        {
2302          "type": "object",
2303          "additionalProperties": {
2304            "type": "string"
2305          }
2306        }
2307        "#);
2308
2309        let json_value = ObjectBuilder::new()
2310            .additional_properties(Some(ArrayBuilder::new().items(ArrayItems::RefOrSchema(
2311                Box::new(ObjectBuilder::new().schema_type(Type::Number).into()),
2312            ))))
2313            .build();
2314        assert_json_snapshot!(json_value, @r#"
2315        {
2316          "type": "object",
2317          "additionalProperties": {
2318            "type": "array",
2319            "items": {
2320              "type": "number"
2321            }
2322          }
2323        }
2324        "#);
2325
2326        let json_value = ObjectBuilder::new()
2327            .additional_properties(Some(Ref::from_schema_name("ComplexModel")))
2328            .build();
2329        assert_json_snapshot!(json_value, @r##"
2330        {
2331          "type": "object",
2332          "additionalProperties": {
2333            "$ref": "#/components/schemas/ComplexModel"
2334          }
2335        }
2336        "##);
2337    }
2338
2339    #[test]
2340    fn test_object_with_title() {
2341        let json_value = ObjectBuilder::new().title(Some("SomeName")).build();
2342        assert_json_snapshot!(json_value, @r#"
2343        {
2344          "type": "object",
2345          "title": "SomeName"
2346        }
2347        "#);
2348    }
2349
2350    #[test]
2351    fn derive_object_with_examples() {
2352        let json_value = ObjectBuilder::new()
2353            .examples([Some(json!({"age": 20, "name": "bob the cat"}))])
2354            .build();
2355        assert_json_snapshot!(json_value, @r#"
2356        {
2357          "type": "object",
2358          "examples": [
2359            {
2360              "age": 20,
2361              "name": "bob the cat"
2362            }
2363          ]
2364        }
2365        "#);
2366    }
2367
2368    fn get_json_path<'a>(value: &'a Value, path: &str) -> &'a Value {
2369        path.split('.').fold(value, |acc, fragment| {
2370            acc.get(fragment).unwrap_or(&serde_json::value::Value::Null)
2371        })
2372    }
2373
2374    #[test]
2375    fn test_array_new() {
2376        let array = Array::new(
2377            ObjectBuilder::new().property(
2378                "id",
2379                ObjectBuilder::new()
2380                    .schema_type(Type::Integer)
2381                    .format(Some(SchemaFormat::KnownFormat(KnownFormat::Int32)))
2382                    .description(Some("Id of credential"))
2383                    .default(Some(json!(1i32))),
2384            ),
2385        );
2386
2387        assert!(matches!(array.schema_type, SchemaType::Type(Type::Array)));
2388    }
2389
2390    #[test]
2391    fn test_array_builder() {
2392        let array: Array = ArrayBuilder::new()
2393            .items(
2394                ObjectBuilder::new().property(
2395                    "id",
2396                    ObjectBuilder::new()
2397                        .schema_type(Type::Integer)
2398                        .format(Some(SchemaFormat::KnownFormat(KnownFormat::Int32)))
2399                        .description(Some("Id of credential"))
2400                        .default(Some(json!(1i32))),
2401                ),
2402            )
2403            .build();
2404
2405        assert!(matches!(array.schema_type, SchemaType::Type(Type::Array)));
2406    }
2407
2408    #[test]
2409    fn reserialize_deserialized_schema_components() {
2410        let components = ComponentsBuilder::new()
2411            .schemas_from_iter(vec![(
2412                "Comp",
2413                Schema::from(
2414                    ObjectBuilder::new()
2415                        .property("name", ObjectBuilder::new().schema_type(Type::String))
2416                        .required("name"),
2417                ),
2418            )])
2419            .responses_from_iter(vec![(
2420                "200",
2421                ResponseBuilder::new().description("Okay").build(),
2422            )])
2423            .security_scheme(
2424                "TLS",
2425                SecurityScheme::MutualTls {
2426                    description: None,
2427                    extensions: None,
2428                },
2429            )
2430            .build();
2431
2432        let serialized_components = serde_json::to_string(&components).unwrap();
2433
2434        let deserialized_components: Components =
2435            serde_json::from_str(serialized_components.as_str()).unwrap();
2436
2437        assert_eq!(
2438            serialized_components,
2439            serde_json::to_string(&deserialized_components).unwrap()
2440        )
2441    }
2442
2443    #[test]
2444    fn reserialize_deserialized_object_component() {
2445        let prop = ObjectBuilder::new()
2446            .property("name", ObjectBuilder::new().schema_type(Type::String))
2447            .required("name")
2448            .build();
2449
2450        let serialized_components = serde_json::to_string(&prop).unwrap();
2451        let deserialized_components: Object =
2452            serde_json::from_str(serialized_components.as_str()).unwrap();
2453
2454        assert_eq!(
2455            serialized_components,
2456            serde_json::to_string(&deserialized_components).unwrap()
2457        )
2458    }
2459
2460    #[test]
2461    fn reserialize_deserialized_property() {
2462        let prop = ObjectBuilder::new().schema_type(Type::String).build();
2463
2464        let serialized_components = serde_json::to_string(&prop).unwrap();
2465        let deserialized_components: Object =
2466            serde_json::from_str(serialized_components.as_str()).unwrap();
2467
2468        assert_eq!(
2469            serialized_components,
2470            serde_json::to_string(&deserialized_components).unwrap()
2471        )
2472    }
2473
2474    #[test]
2475    fn serialize_deserialize_array_within_ref_or_t_object_builder() {
2476        let ref_or_schema = RefOr::T(Schema::Object(
2477            ObjectBuilder::new()
2478                .property(
2479                    "test",
2480                    RefOr::T(Schema::Array(
2481                        ArrayBuilder::new()
2482                            .items(RefOr::T(Schema::Object(
2483                                ObjectBuilder::new()
2484                                    .property("element", RefOr::Ref(Ref::new("#/test")))
2485                                    .build(),
2486                            )))
2487                            .build(),
2488                    )),
2489                )
2490                .build(),
2491        ));
2492
2493        let json_str = serde_json::to_string(&ref_or_schema).expect("");
2494        println!("----------------------------");
2495        println!("{json_str}");
2496
2497        let deserialized: RefOr<Schema> = serde_json::from_str(&json_str).expect("");
2498
2499        let json_de_str = serde_json::to_string(&deserialized).expect("");
2500        println!("----------------------------");
2501        println!("{json_de_str}");
2502
2503        assert_eq!(json_str, json_de_str);
2504    }
2505
2506    #[test]
2507    fn serialize_deserialize_one_of_within_ref_or_t_object_builder() {
2508        let ref_or_schema = RefOr::T(Schema::Object(
2509            ObjectBuilder::new()
2510                .property(
2511                    "test",
2512                    RefOr::T(Schema::OneOf(
2513                        OneOfBuilder::new()
2514                            .item(Schema::Array(
2515                                ArrayBuilder::new()
2516                                    .items(RefOr::T(Schema::Object(
2517                                        ObjectBuilder::new()
2518                                            .property("element", RefOr::Ref(Ref::new("#/test")))
2519                                            .build(),
2520                                    )))
2521                                    .build(),
2522                            ))
2523                            .item(Schema::Array(
2524                                ArrayBuilder::new()
2525                                    .items(RefOr::T(Schema::Object(
2526                                        ObjectBuilder::new()
2527                                            .property("foobar", RefOr::Ref(Ref::new("#/foobar")))
2528                                            .build(),
2529                                    )))
2530                                    .build(),
2531                            ))
2532                            .build(),
2533                    )),
2534                )
2535                .build(),
2536        ));
2537
2538        let json_str = serde_json::to_string(&ref_or_schema).expect("");
2539        println!("----------------------------");
2540        println!("{json_str}");
2541
2542        let deserialized: RefOr<Schema> = serde_json::from_str(&json_str).expect("");
2543
2544        let json_de_str = serde_json::to_string(&deserialized).expect("");
2545        println!("----------------------------");
2546        println!("{json_de_str}");
2547
2548        assert_eq!(json_str, json_de_str);
2549    }
2550
2551    #[test]
2552    fn serialize_deserialize_all_of_of_within_ref_or_t_object_builder() {
2553        let ref_or_schema = RefOr::T(Schema::Object(
2554            ObjectBuilder::new()
2555                .property(
2556                    "test",
2557                    RefOr::T(Schema::AllOf(
2558                        AllOfBuilder::new()
2559                            .item(Schema::Array(
2560                                ArrayBuilder::new()
2561                                    .items(RefOr::T(Schema::Object(
2562                                        ObjectBuilder::new()
2563                                            .property("element", RefOr::Ref(Ref::new("#/test")))
2564                                            .build(),
2565                                    )))
2566                                    .build(),
2567                            ))
2568                            .item(RefOr::T(Schema::Object(
2569                                ObjectBuilder::new()
2570                                    .property("foobar", RefOr::Ref(Ref::new("#/foobar")))
2571                                    .build(),
2572                            )))
2573                            .build(),
2574                    )),
2575                )
2576                .build(),
2577        ));
2578
2579        let json_str = serde_json::to_string(&ref_or_schema).expect("");
2580        println!("----------------------------");
2581        println!("{json_str}");
2582
2583        let deserialized: RefOr<Schema> = serde_json::from_str(&json_str).expect("");
2584
2585        let json_de_str = serde_json::to_string(&deserialized).expect("");
2586        println!("----------------------------");
2587        println!("{json_de_str}");
2588
2589        assert_eq!(json_str, json_de_str);
2590    }
2591
2592    #[test]
2593    fn deserialize_reserialize_one_of_default_type() {
2594        let a = OneOfBuilder::new()
2595            .item(Schema::Array(
2596                ArrayBuilder::new()
2597                    .items(RefOr::T(Schema::Object(
2598                        ObjectBuilder::new()
2599                            .property("element", RefOr::Ref(Ref::new("#/test")))
2600                            .build(),
2601                    )))
2602                    .build(),
2603            ))
2604            .item(Schema::Array(
2605                ArrayBuilder::new()
2606                    .items(RefOr::T(Schema::Object(
2607                        ObjectBuilder::new()
2608                            .property("foobar", RefOr::Ref(Ref::new("#/foobar")))
2609                            .build(),
2610                    )))
2611                    .build(),
2612            ))
2613            .build();
2614
2615        let serialized_json = serde_json::to_string(&a).expect("should serialize to json");
2616        let b: OneOf = serde_json::from_str(&serialized_json).expect("should deserialize OneOf");
2617        let reserialized_json = serde_json::to_string(&b).expect("reserialized json");
2618
2619        println!("{serialized_json}");
2620        println!("{reserialized_json}",);
2621        assert_eq!(serialized_json, reserialized_json);
2622    }
2623
2624    #[test]
2625    fn serialize_deserialize_any_of_of_within_ref_or_t_object_builder() {
2626        let ref_or_schema = RefOr::T(Schema::Object(
2627            ObjectBuilder::new()
2628                .property(
2629                    "test",
2630                    RefOr::T(Schema::AnyOf(
2631                        AnyOfBuilder::new()
2632                            .item(Schema::Array(
2633                                ArrayBuilder::new()
2634                                    .items(RefOr::T(Schema::Object(
2635                                        ObjectBuilder::new()
2636                                            .property("element", RefOr::Ref(Ref::new("#/test")))
2637                                            .build(),
2638                                    )))
2639                                    .build(),
2640                            ))
2641                            .item(RefOr::T(Schema::Object(
2642                                ObjectBuilder::new()
2643                                    .property("foobar", RefOr::Ref(Ref::new("#/foobar")))
2644                                    .build(),
2645                            )))
2646                            .build(),
2647                    )),
2648                )
2649                .build(),
2650        ));
2651
2652        let json_str = serde_json::to_string(&ref_or_schema).expect("");
2653        println!("----------------------------");
2654        println!("{json_str}");
2655
2656        let deserialized: RefOr<Schema> = serde_json::from_str(&json_str).expect("");
2657
2658        let json_de_str = serde_json::to_string(&deserialized).expect("");
2659        println!("----------------------------");
2660        println!("{json_de_str}");
2661        assert!(json_str.contains("\"anyOf\""));
2662        assert_eq!(json_str, json_de_str);
2663    }
2664
2665    #[test]
2666    fn serialize_deserialize_schema_array_ref_or_t() {
2667        let ref_or_schema = RefOr::T(Schema::Array(
2668            ArrayBuilder::new()
2669                .items(RefOr::T(Schema::Object(
2670                    ObjectBuilder::new()
2671                        .property("element", RefOr::Ref(Ref::new("#/test")))
2672                        .build(),
2673                )))
2674                .build(),
2675        ));
2676
2677        let json_str = serde_json::to_string(&ref_or_schema).expect("");
2678        println!("----------------------------");
2679        println!("{json_str}");
2680
2681        let deserialized: RefOr<Schema> = serde_json::from_str(&json_str).expect("");
2682
2683        let json_de_str = serde_json::to_string(&deserialized).expect("");
2684        println!("----------------------------");
2685        println!("{json_de_str}");
2686
2687        assert_eq!(json_str, json_de_str);
2688    }
2689
2690    #[test]
2691    fn serialize_deserialize_schema_array_builder() {
2692        let ref_or_schema = ArrayBuilder::new()
2693            .items(RefOr::T(Schema::Object(
2694                ObjectBuilder::new()
2695                    .property("element", RefOr::Ref(Ref::new("#/test")))
2696                    .build(),
2697            )))
2698            .build();
2699
2700        let json_str = serde_json::to_string(&ref_or_schema).expect("");
2701        println!("----------------------------");
2702        println!("{json_str}");
2703
2704        let deserialized: RefOr<Schema> = serde_json::from_str(&json_str).expect("");
2705
2706        let json_de_str = serde_json::to_string(&deserialized).expect("");
2707        println!("----------------------------");
2708        println!("{json_de_str}");
2709
2710        assert_eq!(json_str, json_de_str);
2711    }
2712
2713    #[test]
2714    fn serialize_deserialize_schema_with_additional_properties() {
2715        let schema = Schema::Object(
2716            ObjectBuilder::new()
2717                .property(
2718                    "map",
2719                    ObjectBuilder::new()
2720                        .additional_properties(Some(AdditionalProperties::FreeForm(true))),
2721                )
2722                .build(),
2723        );
2724
2725        let json_str = serde_json::to_string(&schema).unwrap();
2726        println!("----------------------------");
2727        println!("{json_str}");
2728
2729        let deserialized: RefOr<Schema> = serde_json::from_str(&json_str).unwrap();
2730
2731        let json_de_str = serde_json::to_string(&deserialized).unwrap();
2732        println!("----------------------------");
2733        println!("{json_de_str}");
2734
2735        assert_eq!(json_str, json_de_str);
2736    }
2737
2738    #[test]
2739    fn serialize_deserialize_schema_with_additional_properties_object() {
2740        let schema = Schema::Object(
2741            ObjectBuilder::new()
2742                .property(
2743                    "map",
2744                    ObjectBuilder::new().additional_properties(Some(
2745                        ObjectBuilder::new().property("name", Object::with_type(Type::String)),
2746                    )),
2747                )
2748                .build(),
2749        );
2750
2751        let json_str = serde_json::to_string(&schema).unwrap();
2752        println!("----------------------------");
2753        println!("{json_str}");
2754
2755        let deserialized: RefOr<Schema> = serde_json::from_str(&json_str).unwrap();
2756
2757        let json_de_str = serde_json::to_string(&deserialized).unwrap();
2758        println!("----------------------------");
2759        println!("{json_de_str}");
2760
2761        assert_eq!(json_str, json_de_str);
2762    }
2763
2764    #[test]
2765    fn serialize_discriminator_with_mapping() {
2766        let mut discriminator = Discriminator::new("type");
2767        discriminator.mapping = [("int".to_string(), "#/components/schemas/MyInt".to_string())]
2768            .into_iter()
2769            .collect::<BTreeMap<_, _>>();
2770        let one_of = OneOfBuilder::new()
2771            .item(Ref::from_schema_name("MyInt"))
2772            .discriminator(Some(discriminator))
2773            .build();
2774        assert_json_snapshot!(one_of, @r##"
2775        {
2776          "oneOf": [
2777            {
2778              "$ref": "#/components/schemas/MyInt"
2779            }
2780          ],
2781          "discriminator": {
2782            "propertyName": "type",
2783            "mapping": {
2784              "int": "#/components/schemas/MyInt"
2785            }
2786          }
2787        }
2788        "##);
2789    }
2790
2791    #[test]
2792    fn serialize_deserialize_object_with_multiple_schema_types() {
2793        let object = ObjectBuilder::new()
2794            .schema_type(SchemaType::from_iter([Type::Object, Type::Null]))
2795            .build();
2796
2797        let json_str = serde_json::to_string(&object).unwrap();
2798        println!("----------------------------");
2799        println!("{json_str}");
2800
2801        let deserialized: Object = serde_json::from_str(&json_str).unwrap();
2802
2803        let json_de_str = serde_json::to_string(&deserialized).unwrap();
2804        println!("----------------------------");
2805        println!("{json_de_str}");
2806
2807        assert_eq!(json_str, json_de_str);
2808    }
2809
2810    #[test]
2811    fn object_with_extensions() {
2812        let expected = json!("value");
2813        let extensions = extensions::ExtensionsBuilder::new()
2814            .add("x-some-extension", expected.clone())
2815            .build();
2816        let json_value = ObjectBuilder::new().extensions(Some(extensions)).build();
2817
2818        let value = serde_json::to_value(&json_value).unwrap();
2819        assert_eq!(value.get("x-some-extension"), Some(&expected));
2820    }
2821
2822    #[test]
2823    fn array_with_extensions() {
2824        let expected = json!("value");
2825        let extensions = extensions::ExtensionsBuilder::new()
2826            .add("x-some-extension", expected.clone())
2827            .build();
2828        let json_value = ArrayBuilder::new().extensions(Some(extensions)).build();
2829
2830        let value = serde_json::to_value(&json_value).unwrap();
2831        assert_eq!(value.get("x-some-extension"), Some(&expected));
2832    }
2833
2834    #[test]
2835    fn oneof_with_extensions() {
2836        let expected = json!("value");
2837        let extensions = extensions::ExtensionsBuilder::new()
2838            .add("x-some-extension", expected.clone())
2839            .build();
2840        let json_value = OneOfBuilder::new().extensions(Some(extensions)).build();
2841
2842        let value = serde_json::to_value(&json_value).unwrap();
2843        assert_eq!(value.get("x-some-extension"), Some(&expected));
2844    }
2845
2846    #[test]
2847    fn allof_with_extensions() {
2848        let expected = json!("value");
2849        let extensions = extensions::ExtensionsBuilder::new()
2850            .add("x-some-extension", expected.clone())
2851            .build();
2852        let json_value = AllOfBuilder::new().extensions(Some(extensions)).build();
2853
2854        let value = serde_json::to_value(&json_value).unwrap();
2855        assert_eq!(value.get("x-some-extension"), Some(&expected));
2856    }
2857
2858    #[test]
2859    fn anyof_with_extensions() {
2860        let expected = json!("value");
2861        let extensions = extensions::ExtensionsBuilder::new()
2862            .add("x-some-extension", expected.clone())
2863            .build();
2864        let json_value = AnyOfBuilder::new().extensions(Some(extensions)).build();
2865
2866        let value = serde_json::to_value(&json_value).unwrap();
2867        assert_eq!(value.get("x-some-extension"), Some(&expected));
2868    }
2869}