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