Skip to main content

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