fastapi_gen/
lib.rs

1//! This is **private** fastapi codegen library and is not used alone.
2//!
3//! The library contains macro implementations for fastapi library. Content
4//! of the library documentation is available through **fastapi** library itself.
5//! Consider browsing via the **fastapi** crate so all links will work correctly.
6
7#![cfg_attr(doc_cfg, feature(doc_cfg))]
8#![warn(missing_docs)]
9#![warn(rustdoc::broken_intra_doc_links)]
10
11#[cfg(all(feature = "decimal", feature = "decimal_float"))]
12compile_error!("`decimal` and `decimal_float` are mutually exclusive feature flags");
13
14#[cfg(all(
15    feature = "actix_extras",
16    feature = "axum_extras",
17    feature = "rocket_extras"
18))]
19compile_error!(
20    "`actix_extras`, `axum_extras` and `rocket_extras` are mutually exclusive feature flags"
21);
22
23use std::{
24    borrow::{Borrow, Cow},
25    error::Error,
26    fmt::Display,
27    mem,
28    ops::Deref,
29};
30
31use component::schema::Schema;
32use doc_comment::CommentAttributes;
33
34use component::into_params::IntoParams;
35use ext::{PathOperationResolver, PathOperations, PathResolver};
36use openapi::OpenApi;
37use proc_macro::TokenStream;
38use quote::{quote, quote_spanned, ToTokens, TokenStreamExt};
39
40use proc_macro2::{Group, Ident, Punct, Span, TokenStream as TokenStream2};
41use syn::{
42    bracketed,
43    parse::{Parse, ParseStream},
44    punctuated::Punctuated,
45    token::Bracket,
46    DeriveInput, ExprPath, GenericParam, ItemFn, Lit, LitStr, Member, Token,
47};
48
49mod component;
50mod doc_comment;
51mod ext;
52mod openapi;
53mod path;
54mod schema_type;
55mod security_requirement;
56
57use crate::path::{Path, PathAttr};
58
59use self::{
60    component::{
61        features::{self, Feature},
62        ComponentSchema, ComponentSchemaProps, TypeTree,
63    },
64    openapi::parse_openapi_attrs,
65    path::response::derive::{IntoResponses, ToResponse},
66};
67
68#[cfg(feature = "config")]
69static CONFIG: once_cell::sync::Lazy<fastapi_config::Config> =
70    once_cell::sync::Lazy::new(fastapi_config::Config::read_from_file);
71
72#[proc_macro_derive(ToSchema, attributes(schema))]
73/// Generate reusable OpenAPI schema to be used
74/// together with [`OpenApi`][openapi_derive].
75///
76/// This is `#[derive]` implementation for [`ToSchema`][to_schema] trait. The macro accepts one
77/// `schema`
78/// attribute optionally which can be used to enhance generated documentation. The attribute can be placed
79/// at item level or field and variant levels in structs and enum.
80///
81/// You can use the Rust's own `#[deprecated]` attribute on any struct, enum or field to mark it as deprecated and it will
82/// reflect to the generated OpenAPI spec.
83///
84/// `#[deprecated]` attribute supports adding additional details such as a reason and or since version but this is is not supported in
85/// OpenAPI. OpenAPI has only a boolean flag to determine deprecation. While it is totally okay to declare deprecated with reason
86/// `#[deprecated  = "There is better way to do this"]` the reason would not render in OpenAPI spec.
87///
88/// Doc comments on fields will resolve to field descriptions in generated OpenAPI doc. On struct
89/// level doc comments will resolve to object descriptions.
90///
91/// Schemas derived with `ToSchema` will be automatically collected from usage. In case of looping
92/// schema tree _`no_recursion`_ attribute must be used to break from recurring into infinite loop.
93/// See [more details from example][derive@ToSchema#examples]. All arguments of generic schemas
94/// must implement `ToSchema` trait.
95///
96/// ```rust
97/// /// This is a pet
98/// #[derive(fastapi::ToSchema)]
99/// struct Pet {
100///     /// Name for your pet
101///     name: String,
102/// }
103/// ```
104///
105/// # Named Field Struct Optional Configuration Options for `#[schema(...)]`
106///
107/// * `description = ...` Can be literal string or Rust expression e.g. _`const`_ reference or
108///   `include_str!(...)` statement. This can be used to override **default** description what is
109///   resolved from doc comments of the type.
110/// * `example = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
111///   **Deprecated since OpenAPI 3.0, using `examples` is preferred instead.**
112/// * `examples(..., ...)` Comma separated list defining multiple _`examples`_ for the schema. Each
113///   _`example`_ Can be any value e.g. literal, method reference or _`json!(...)`_.
114/// * `xml(...)` Can be used to define [`Xml`][xml] object properties applicable to Structs.
115/// * `title = ...` Literal string value. Can be used to define title for struct in OpenAPI
116///   document. Some OpenAPI code generation libraries also use this field as a name for the
117///   struct.
118/// * `rename_all = ...` Supports same syntax as _serde_ _`rename_all`_ attribute. Will rename all fields
119///   of the structs accordingly. If both _serde_ `rename_all` and _schema_ _`rename_all`_ are defined
120///   __serde__ will take precedence.
121/// * `as = ...` Can be used to define alternative path and name for the schema what will be used in
122///   the OpenAPI. E.g _`as = path::to::Pet`_. This would make the schema appear in the generated
123///   OpenAPI spec as _`path.to.Pet`_. This same name will be used throughout the OpenAPI generated
124///   with `fastapi` when the type is being referenced in [`OpenApi`][openapi_derive] derive macro
125///   or in [`fastapi::path(...)`][path_macro] macro.
126/// * `bound = ...` Can be used to override default trait bounds on generated `impl`s.
127///   See [Generic schemas section](#generic-schemas) below for more details.
128/// * `default` Can be used to populate default values on all fields using the struct's
129///   [`Default`] implementation.
130/// * `deprecated` Can be used to mark all fields as deprecated in the generated OpenAPI spec but
131///   not in the code. If you'd like to mark the fields as deprecated in the code as well use
132///   Rust's own `#[deprecated]` attribute instead.
133/// * `max_properties = ...` Can be used to define maximum number of properties this struct can
134///   contain. Value must be a number.
135/// * `min_properties = ...` Can be used to define minimum number of properties this struct can
136///   contain. Value must be a number.
137///* `no_recursion` Is used to break from recursion in case of looping schema tree e.g. `Pet` ->
138///  `Owner` -> `Pet`. _`no_recursion`_ attribute must be used within `Ower` type not to allow
139///  recurring into `Pet`. Failing to do so will cause infinite loop and runtime **panic**. On
140///  struct level the _`no_recursion`_ rule will be applied to all of its fields.
141///
142/// ## Named Fields Optional Configuration Options for `#[schema(...)]`
143///
144/// * `example = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
145///   **Deprecated since OpenAPI 3.0, using `examples` is preferred instead.**
146/// * `examples(..., ...)` Comma separated list defining multiple _`examples`_ for the schema. Each
147///   _`example`_ Can be any value e.g. literal, method reference or _`json!(...)`_.
148/// * `default = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
149/// * `format = ...` May either be variant of the [`KnownFormat`][known_format] enum, or otherwise
150///   an open value as a string. By default the format is derived from the type of the property
151///   according OpenApi spec.
152/// * `write_only` Defines property is only used in **write** operations *POST,PUT,PATCH* but not in *GET*
153/// * `read_only` Defines property is only used in **read** operations *GET* but not in *POST,PUT,PATCH*
154/// * `xml(...)` Can be used to define [`Xml`][xml] object properties applicable to named fields.
155///    See configuration options at xml attributes of [`ToSchema`][to_schema_xml]
156/// * `value_type = ...` Can be used to override default type derived from type of the field used in OpenAPI spec.
157///   This is useful in cases where the default type does not correspond to the actual type e.g. when
158///   any third-party types are used which are not [`ToSchema`][to_schema]s nor [`primitive` types][primitive].
159///   The value can be any Rust type what normally could be used to serialize to JSON, or either virtual type _`Object`_
160///   or _`Value`_.
161///   _`Object`_ will be rendered as generic OpenAPI object _(`type: object`)_.
162///   _`Value`_ will be rendered as any OpenAPI value (i.e. no `type` restriction).
163/// * `inline` If the type of this field implements [`ToSchema`][to_schema], then the schema definition
164///   will be inlined. **warning:** Don't use this for recursive data types!
165///   
166///   **Note!**<br>Using `inline` with generic arguments might lead to incorrect spec generation.
167///   This is due to the fact that during compilation we cannot know how to treat the generic
168///   argument and there is difference whether it is a primitive type or another generic type.
169/// * `required = ...` Can be used to enforce required status for the field. [See
170///   rules][derive@ToSchema#field-nullability-and-required-rules]
171/// * `nullable` Defines property is nullable (note this is different to non-required).
172/// * `rename = ...` Supports same syntax as _serde_ _`rename`_ attribute. Will rename field
173///   accordingly. If both _serde_ `rename` and _schema_ _`rename`_ are defined __serde__ will take
174///   precedence.
175/// * `multiple_of = ...` Can be used to define multiplier for a value. Value is considered valid
176///   division will result an `integer`. Value must be strictly above _`0`_.
177/// * `maximum = ...` Can be used to define inclusive upper bound to a `number` value.
178/// * `minimum = ...` Can be used to define inclusive lower bound to a `number` value.
179/// * `exclusive_maximum = ...` Can be used to define exclusive upper bound to a `number` value.
180/// * `exclusive_minimum = ...` Can be used to define exclusive lower bound to a `number` value.
181/// * `max_length = ...` Can be used to define maximum length for `string` types.
182/// * `min_length = ...` Can be used to define minimum length for `string` types.
183/// * `pattern = ...` Can be used to define valid regular expression in _ECMA-262_ dialect the field value must match.
184/// * `max_items = ...` Can be used to define maximum items allowed for `array` fields. Value must
185///   be non-negative integer.
186/// * `min_items = ...` Can be used to define minimum items allowed for `array` fields. Value must
187///   be non-negative integer.
188/// * `schema_with = ...` Use _`schema`_ created by provided function reference instead of the
189///   default derived _`schema`_. The function must match to `fn() -> Into<RefOr<Schema>>`. It does
190///   not accept arguments and must return anything that can be converted into `RefOr<Schema>`.
191/// * `additional_properties = ...` Can be used to define free form types for maps such as
192///   [`HashMap`](std::collections::HashMap) and [`BTreeMap`](std::collections::BTreeMap).
193///   Free form type enables use of arbitrary types within map values.
194///   Supports formats _`additional_properties`_ and _`additional_properties = true`_.
195/// * `deprecated` Can be used to mark the field as deprecated in the generated OpenAPI spec but
196///   not in the code. If you'd like to mark the field as deprecated in the code as well use
197///   Rust's own `#[deprecated]` attribute instead.
198/// * `content_encoding = ...` Can be used to define content encoding used for underlying schema object.
199///   See [`Object::content_encoding`][schema_object_encoding]
200/// * `content_media_type = ...` Can be used to define MIME type of a string for underlying schema object.
201///   See [`Object::content_media_type`][schema_object_media_type]
202///* `ignore` or `ignore = ...` Can be used to skip the field from being serialized to OpenAPI schema. It accepts either a literal `bool` value
203///   or a path to a function that returns `bool` (`Fn() -> bool`).
204///* `no_recursion` Is used to break from recursion in case of looping schema tree e.g. `Pet` ->
205///  `Owner` -> `Pet`. _`no_recursion`_ attribute must be used within `Ower` type not to allow
206///  recurring into `Pet`. Failing to do so will cause infinite loop and runtime **panic**.
207///
208/// #### Field nullability and required rules
209///
210/// Field is considered _`required`_ if
211/// * it is not `Option` field
212/// * and it does not have _`skip_serializing_if`_ property
213/// * and it does not have _`serde_with`_ _[`double_option`](https://docs.rs/serde_with/latest/serde_with/rust/double_option/index.html)_
214/// * and it does not have default value provided with serde _`default`_
215///   attribute
216///
217/// Field is considered _`nullable`_ when field type is _`Option`_.
218///
219/// ## Xml attribute Configuration Options
220///
221/// * `xml(name = "...")` Will set name for property or type.
222/// * `xml(namespace = "...")` Will set namespace for xml element which needs to be valid uri.
223/// * `xml(prefix = "...")` Will set prefix for name.
224/// * `xml(attribute)` Will translate property to xml attribute instead of xml element.
225/// * `xml(wrapped)` Will make wrapped xml element.
226/// * `xml(wrapped(name = "wrap_name"))` Will override the wrapper elements name.
227///
228/// See [`Xml`][xml] for more details.
229///
230/// # Unnamed Field Struct Optional Configuration Options for `#[schema(...)]`
231///
232/// * `description = ...` Can be literal string or Rust expression e.g. [_`const`_][const] reference or
233///   `include_str!(...)` statement. This can be used to override **default** description what is
234///   resolved from doc comments of the type.
235/// * `example = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
236///   **Deprecated since OpenAPI 3.0, using `examples` is preferred instead.**
237/// * `examples(..., ...)` Comma separated list defining multiple _`examples`_ for the schema. Each
238///   _`example`_ Can be any value e.g. literal, method reference or _`json!(...)`_.
239/// * `default = ...` Can be any value e.g. literal, method reference or _`json!(...)`_. If no value
240///   is specified, and the struct has only one field, the field's default value in the schema will be
241///   set from the struct's [`Default`] implementation.
242/// * `format = ...` May either be variant of the [`KnownFormat`][known_format] enum, or otherwise
243///   an open value as a string. By default the format is derived from the type of the property
244///   according OpenApi spec.
245/// * `value_type = ...` Can be used to override default type derived from type of the field used in OpenAPI spec.
246///   This is useful in cases where the default type does not correspond to the actual type e.g. when
247///   any third-party types are used which are not [`ToSchema`][to_schema]s nor [`primitive` types][primitive].
248///   The value can be any Rust type what normally could be used to serialize to JSON or either virtual type _`Object`_
249///   or _`Value`_.
250///   _`Object`_ will be rendered as generic OpenAPI object _(`type: object`)_.
251///   _`Value`_ will be rendered as any OpenAPI value (i.e. no `type` restriction).
252/// * `title = ...` Literal string value. Can be used to define title for struct in OpenAPI
253///   document. Some OpenAPI code generation libraries also use this field as a name for the
254///   struct.
255/// * `as = ...` Can be used to define alternative path and name for the schema what will be used in
256///   the OpenAPI. E.g _`as = path::to::Pet`_. This would make the schema appear in the generated
257///   OpenAPI spec as _`path.to.Pet`_. This same name will be used throughout the OpenAPI generated
258///   with `fastapi` when the type is being referenced in [`OpenApi`][openapi_derive] derive macro
259///   or in [`fastapi::path(...)`][path_macro] macro.
260/// * `bound = ...` Can be used to override default trait bounds on generated `impl`s.
261///   See [Generic schemas section](#generic-schemas) below for more details.
262/// * `deprecated` Can be used to mark the field as deprecated in the generated OpenAPI spec but
263///   not in the code. If you'd like to mark the field as deprecated in the code as well use
264///   Rust's own `#[deprecated]` attribute instead.
265/// * `content_encoding = ...` Can be used to define content encoding used for underlying schema object.
266///   See [`Object::content_encoding`][schema_object_encoding]
267/// * `content_media_type = ...` Can be used to define MIME type of a string for underlying schema object.
268///   See [`Object::content_media_type`][schema_object_media_type]
269///* `no_recursion` Is used to break from recursion in case of looping schema tree e.g. `Pet` ->
270///  `Owner` -> `Pet`. _`no_recursion`_ attribute must be used within `Ower` type not to allow
271///  recurring into `Pet`. Failing to do so will cause infinite loop and runtime **panic**.
272///
273/// # Enum Optional Configuration Options for `#[schema(...)]`
274///
275/// ## Plain Enum having only `Unit` variants Optional Configuration Options for `#[schema(...)]`
276///
277/// * `description = ...` Can be literal string or Rust expression e.g. [_`const`_][const] reference or
278///   `include_str!(...)` statement. This can be used to override **default** description what is
279///   resolved from doc comments of the type.
280/// * `example = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
281///   **Deprecated since OpenAPI 3.0, using `examples` is preferred instead.**
282/// * `examples(..., ...)` Comma separated list defining multiple _`examples`_ for the schema. Each
283///   _`example`_ Can be any value e.g. literal, method reference or _`json!(...)`_.
284/// * `default = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
285/// * `title = ...` Literal string value. Can be used to define title for enum in OpenAPI
286///   document. Some OpenAPI code generation libraries also use this field as a name for the
287///   enum.
288/// * `rename_all = ...` Supports same syntax as _serde_ _`rename_all`_ attribute. Will rename all
289///   variants of the enum accordingly. If both _serde_ `rename_all` and _schema_ _`rename_all`_
290///   are defined __serde__ will take precedence.
291/// * `as = ...` Can be used to define alternative path and name for the schema what will be used in
292///   the OpenAPI. E.g _`as = path::to::Pet`_. This would make the schema appear in the generated
293///   OpenAPI spec as _`path.to.Pet`_. This same name will be used throughout the OpenAPI generated
294///   with `fastapi` when the type is being referenced in [`OpenApi`][openapi_derive] derive macro
295///   or in [`fastapi::path(...)`][path_macro] macro.
296/// * `bound = ...` Can be used to override default trait bounds on generated `impl`s.
297///   See [Generic schemas section](#generic-schemas) below for more details.
298/// * `deprecated` Can be used to mark the enum as deprecated in the generated OpenAPI spec but
299///   not in the code. If you'd like to mark the enum as deprecated in the code as well use
300///   Rust's own `#[deprecated]` attribute instead.
301///
302/// ### Plain Enum Variant Optional Configuration Options for `#[schema(...)]`
303///
304/// * `rename = ...` Supports same syntax as _serde_ _`rename`_ attribute. Will rename variant
305///   accordingly. If both _serde_ `rename` and _schema_ _`rename`_ are defined __serde__ will take
306///   precedence. **Note!** [`Repr enum`][macro@ToSchema#repr-attribute-support] variant does not
307///   support _`rename`_.
308///
309/// ## Mixed Enum Optional Configuration Options for `#[schema(...)]`
310///
311/// * `description = ...` Can be literal string or Rust expression e.g. [_`const`_][const] reference or
312///   `include_str!(...)` statement. This can be used to override **default** description what is
313///   resolved from doc comments of the type.
314/// * `example = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
315///   **Deprecated since OpenAPI 3.0, using `examples` is preferred instead.**
316/// * `examples(..., ...)` Comma separated list defining multiple _`examples`_ for the schema. Each
317/// * `default = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
318/// * `title = ...` Literal string value. Can be used to define title for enum in OpenAPI
319///   document. Some OpenAPI code generation libraries also use this field as a name for the
320///   enum.
321/// * `rename_all = ...` Supports same syntax as _serde_ _`rename_all`_ attribute. Will rename all
322///   variants of the enum accordingly. If both _serde_ `rename_all` and _schema_ _`rename_all`_
323///   are defined __serde__ will take precedence.
324/// * `as = ...` Can be used to define alternative path and name for the schema what will be used in
325///   the OpenAPI. E.g _`as = path::to::Pet`_. This would make the schema appear in the generated
326///   OpenAPI spec as _`path.to.Pet`_. This same name will be used throughout the OpenAPI generated
327///   with `fastapi` when the type is being referenced in [`OpenApi`][openapi_derive] derive macro
328///   or in [`fastapi::path(...)`][path_macro] macro.
329/// * `bound = ...` Can be used to override default trait bounds on generated `impl`s.
330///   See [Generic schemas section](#generic-schemas) below for more details.
331/// * `deprecated` Can be used to mark the enum as deprecated in the generated OpenAPI spec but
332///   not in the code. If you'd like to mark the enum as deprecated in the code as well use
333///   Rust's own `#[deprecated]` attribute instead.
334/// * `discriminator = ...` or `discriminator(...)` Can be used to define OpenAPI discriminator
335///   field for enums with single unnamed _`ToSchema`_ reference field. See the [discriminator
336///   syntax][derive@ToSchema#schemadiscriminator-syntax].
337///* `no_recursion` Is used to break from recursion in case of looping schema tree e.g. `Pet` ->
338///  `Owner` -> `Pet`. _`no_recursion`_ attribute must be used within `Ower` type not to allow
339///  recurring into `Pet`. Failing to do so will cause infinite loop and runtime **panic**. On
340///  enum level the _`no_recursion`_ rule will be applied to all of its variants.
341///
342///  ### `#[schema(discriminator)]` syntax
343///
344///  Discriminator can **only** be used with enums having **`#[serde(untagged)]`** attribute and
345///  each variant must have only one unnamed field schema reference to type implementing
346///  _`ToSchema`_.
347///
348///  **Simple form `discriminator = ...`**
349///
350///  Can be literal string or expression e.g. [_`const`_][const] reference. It can be defined as
351///  _`discriminator = "value"`_ where the assigned value is the
352///  discriminator field that must exists in each variant referencing schema.
353///
354/// **Complex form `discriminator(...)`**
355///
356/// * `property_name = ...` Can be literal string or expression e.g. [_`const`_][const] reference.
357/// * mapping `key` Can be literal string or expression e.g. [_`const`_][const] reference.
358/// * mapping `value` Can be literal string or expression e.g. [_`const`_][const] reference.
359///
360/// Additionally discriminator can be defined with custom mappings as show below. The _`mapping`_
361/// values defines _**key = value**_ pairs where _**key**_ is the expected value for _**property_name**_ field
362/// and _**value**_ is schema to map.
363/// ```text
364/// discriminator(property_name = "my_field", mapping(
365///      ("value" = "#/components/schemas/Schema1"),
366///      ("value2" = "#/components/schemas/Schema2")
367/// ))
368/// ```
369///
370/// ### Mixed Enum Named Field Variant Optional Configuration Options for `#[serde(schema)]`
371///
372/// * `example = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
373///   **Deprecated since OpenAPI 3.0, using `examples` is preferred instead.**
374/// * `examples(..., ...)` Comma separated list defining multiple _`examples`_ for the schema. Each
375/// * `default = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
376/// * `title = ...` Literal string value. Can be used to define title for enum variant in OpenAPI
377///   document. Some OpenAPI code generation libraries also use this field as a name for the
378///   enum.
379/// * `xml(...)` Can be used to define [`Xml`][xml] object properties applicable to Structs.
380/// * `rename = ...` Supports same syntax as _serde_ _`rename`_ attribute. Will rename variant
381///   accordingly. If both _serde_ `rename` and _schema_ _`rename`_ are defined __serde__ will take
382///   precedence.
383/// * `rename_all = ...` Supports same syntax as _serde_ _`rename_all`_ attribute. Will rename all
384///   variant fields accordingly. If both _serde_ `rename_all` and _schema_ _`rename_all`_
385///   are defined __serde__ will take precedence.
386/// * `deprecated` Can be used to mark the enum as deprecated in the generated OpenAPI spec but
387///   not in the code. If you'd like to mark the enum as deprecated in the code as well use
388///   Rust's own `#[deprecated]` attribute instead.
389/// * `max_properties = ...` Can be used to define maximum number of properties this struct can
390///   contain. Value must be a number.
391/// * `min_properties = ...` Can be used to define minimum number of properties this struct can
392///   contain. Value must be a number.
393///* `no_recursion` Is used to break from recursion in case of looping schema tree e.g. `Pet` ->
394///  `Owner` -> `Pet`. _`no_recursion`_ attribute must be used within `Ower` type not to allow
395///  recurring into `Pet`. Failing to do so will cause infinite loop and runtime **panic**. On
396///  named field variant level the _`no_recursion`_ rule will be applied to all of its fields.
397///
398/// ## Mixed Enum Unnamed Field Variant Optional Configuration Options for `#[serde(schema)]`
399///
400/// * `example = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
401///   **Deprecated since OpenAPI 3.0, using `examples` is preferred instead.**
402/// * `examples(..., ...)` Comma separated list defining multiple _`examples`_ for the schema. Each
403///   _`example`_ Can be any value e.g. literal, method reference or _`json!(...)`_.
404/// * `default = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
405/// * `title = ...` Literal string value. Can be used to define title for enum variant in OpenAPI
406///   document. Some OpenAPI code generation libraries also use this field as a name for the
407///   struct.
408/// * `rename = ...` Supports same syntax as _serde_ _`rename`_ attribute. Will rename variant
409///   accordingly. If both _serde_ `rename` and _schema_ _`rename`_ are defined __serde__ will take
410///   precedence.
411/// * `format = ...` May either be variant of the [`KnownFormat`][known_format] enum, or otherwise
412///   an open value as a string. By default the format is derived from the type of the property
413///   according OpenApi spec.
414/// * `value_type = ...` Can be used to override default type derived from type of the field used in OpenAPI spec.
415///   This is useful in cases where the default type does not correspond to the actual type e.g. when
416///   any third-party types are used which are not [`ToSchema`][to_schema]s nor [`primitive` types][primitive].
417///   The value can be any Rust type what normally could be used to serialize to JSON or either virtual type _`Object`_
418///   or _`Value`_.
419///   _`Object`_ will be rendered as generic OpenAPI object _(`type: object`)_.
420///   _`Value`_ will be rendered as any OpenAPI value (i.e. no `type` restriction).
421/// * `deprecated` Can be used to mark the field as deprecated in the generated OpenAPI spec but
422///   not in the code. If you'd like to mark the field as deprecated in the code as well use
423///   Rust's own `#[deprecated]` attribute instead.
424///* `no_recursion` Is used to break from recursion in case of looping schema tree e.g. `Pet` ->
425///  `Owner` -> `Pet`. _`no_recursion`_ attribute must be used within `Ower` type not to allow
426///  recurring into `Pet`. Failing to do so will cause infinite loop and runtime **panic**.
427///
428/// #### Mixed Enum Unnamed Field Variant's Field Configuration Options
429///
430/// * `inline` If the type of this field implements [`ToSchema`][to_schema], then the schema definition
431///   will be inlined. **warning:** Don't use this for recursive data types!
432///
433///   **Note!**<br>Using `inline` with generic arguments might lead to incorrect spec generation.
434///   This is due to the fact that during compilation we cannot know how to treat the generic
435///   argument and there is difference whether it is a primitive type or another generic type.
436///
437///   _**Inline unnamed field variant schemas.**_
438///   ```rust
439///   # use fastapi::ToSchema;
440///   # #[derive(ToSchema)]
441///   # enum Number {
442///   #     One,
443///   # }
444///   #
445///   # #[derive(ToSchema)]
446///   # enum Color {
447///   #     Spade,
448///   # }
449///    #[derive(ToSchema)]
450///    enum Card {
451///        Number(#[schema(inline)] Number),
452///        Color(#[schema(inline)] Color),
453///    }
454///   ```
455///
456/// ## Mixed Enum Unit Field Variant Optional Configuration Options for `#[serde(schema)]`
457///
458/// * `example = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
459///   **Deprecated since OpenAPI 3.0, using `examples` is preferred instead.**
460/// * `examples(..., ...)` Comma separated list defining multiple _`examples`_ for the schema. Each
461///   _`example`_ Can be any value e.g. literal, method reference or _`json!(...)`_.
462/// * `title = ...` Literal string value. Can be used to define title for enum variant in OpenAPI
463///   document. Some OpenAPI code generation libraries also use this field as a name for the
464///   struct.
465/// * `rename = ...` Supports same syntax as _serde_ _`rename`_ attribute. Will rename variant
466///   accordingly. If both _serde_ `rename` and _schema_ _`rename`_ are defined __serde__ will take
467///   precedence.
468/// * `deprecated` Can be used to mark the field as deprecated in the generated OpenAPI spec but
469///   not in the code. If you'd like to mark the field as deprecated in the code as well use
470///   Rust's own `#[deprecated]` attribute instead.
471///
472/// # Partial `#[serde(...)]` attributes support
473///
474/// ToSchema derive has partial support for [serde attributes]. These supported attributes will reflect to the
475/// generated OpenAPI doc. For example if _`#[serde(skip)]`_ is defined the attribute will not show up in the OpenAPI spec at all since it will not never
476/// be serialized anyway. Similarly the _`rename`_ and _`rename_all`_ will reflect to the generated OpenAPI doc.
477///
478/// * `rename_all = "..."` Supported at the container level.
479/// * `rename = "..."` Supported **only** at the field or variant level.
480/// * `skip = "..."` Supported  **only** at the field or variant level.
481/// * `skip_serializing = "..."` Supported  **only** at the field or variant level.
482/// * `skip_deserializing = "..."` Supported  **only** at the field or variant level.
483/// * `skip_serializing_if = "..."` Supported  **only** at the field level.
484/// * `with = ...` Supported **only at field level.**
485/// * `tag = "..."` Supported at the container level.
486/// * `content = "..."` Supported at the container level, allows [adjacently-tagged enums](https://serde.rs/enum-representations.html#adjacently-tagged).
487///   This attribute requires that a `tag` is present, otherwise serde will trigger a compile-time
488///   failure.
489/// * `untagged` Supported at the container level. Allows [untagged
490///    enum representation](https://serde.rs/enum-representations.html#untagged).
491/// * `default` Supported at the container level and field level according to [serde attributes].
492/// * `deny_unknown_fields` Supported at the container level.
493/// * `flatten` Supported at the field level.
494///
495/// Other _`serde`_ attributes works as is but does not have any effect on the generated OpenAPI doc.
496///
497/// **Note!** `tag` attribute has some limitations like it cannot be used with **tuple types**. See more at
498/// [enum representation docs](https://serde.rs/enum-representations.html).
499///
500/// **Note!** `with` attribute is used in tandem with [serde_with](https://github.com/jonasbb/serde_with) to recognize
501/// _[`double_option`](https://docs.rs/serde_with/latest/serde_with/rust/double_option/index.html)_ from **field value**.
502/// _`double_option`_ is **only** supported attribute from _`serde_with`_ crate.
503///
504/// ```rust
505/// # use serde::Serialize;
506/// # use fastapi::ToSchema;
507/// #[derive(Serialize, ToSchema)]
508/// struct Foo(String);
509///
510/// #[derive(Serialize, ToSchema)]
511/// #[serde(rename_all = "camelCase")]
512/// enum Bar {
513///     UnitValue,
514///     #[serde(rename_all = "camelCase")]
515///     NamedFields {
516///         #[serde(rename = "id")]
517///         named_id: &'static str,
518///         name_list: Option<Vec<String>>
519///     },
520///     UnnamedFields(Foo),
521///     #[serde(skip)]
522///     SkipMe,
523/// }
524/// ```
525///
526/// _**Add custom `tag` to change JSON representation to be internally tagged.**_
527/// ```rust
528/// # use serde::Serialize;
529/// # use fastapi::ToSchema;
530/// #[derive(Serialize, ToSchema)]
531/// struct Foo(String);
532///
533/// #[derive(Serialize, ToSchema)]
534/// #[serde(tag = "tag")]
535/// enum Bar {
536///     UnitValue,
537///     NamedFields {
538///         id: &'static str,
539///         names: Option<Vec<String>>
540///     },
541/// }
542/// ```
543///
544/// _**Add serde `default` attribute for MyValue struct. Similarly `default` could be added to
545/// individual fields as well. If `default` is given the field's affected will be treated
546/// as optional.**_
547/// ```rust
548///  #[derive(fastapi::ToSchema, serde::Deserialize, Default)]
549///  #[serde(default)]
550///  struct MyValue {
551///      field: String
552///  }
553/// ```
554///
555/// # `#[repr(...)]` attribute support
556///
557/// [Serde repr](https://github.com/dtolnay/serde-repr) allows field-less enums be represented by
558/// their numeric value.
559///
560/// * `repr(u*)` for unsigned integer.
561/// * `repr(i*)` for signed integer.
562///
563/// **Supported schema attributes**
564///
565/// * `example = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
566///   **Deprecated since OpenAPI 3.0, using `examples` is preferred instead.**
567/// * `examples(..., ...)` Comma separated list defining multiple _`examples`_ for the schema. Each
568///   _`example`_ Can be any value e.g. literal, method reference or _`json!(...)`_.
569/// * `title = ...` Literal string value. Can be used to define title for enum in OpenAPI
570///   document. Some OpenAPI code generation libraries also use this field as a name for the
571///   struct.
572/// * `as = ...` Can be used to define alternative path and name for the schema what will be used in
573///   the OpenAPI. E.g _`as = path::to::Pet`_. This would make the schema appear in the generated
574///   OpenAPI spec as _`path.to.Pet`_. This same name will be used throughout the OpenAPI generated
575///   with `fastapi` when the type is being referenced in [`OpenApi`][openapi_derive] derive macro
576///   or in [`fastapi::path(...)`][path_macro] macro.
577///
578/// _**Create enum with numeric values.**_
579/// ```rust
580/// # use fastapi::ToSchema;
581/// #[derive(ToSchema)]
582/// #[repr(u8)]
583/// #[schema(default = default_value, example = 2)]
584/// enum Mode {
585///     One = 1,
586///     Two,
587///  }
588///
589/// fn default_value() -> u8 {
590///     1
591/// }
592/// ```
593///
594/// _**You can use `skip` and `tag` attributes from serde.**_
595/// ```rust
596/// # use fastapi::ToSchema;
597/// #[derive(ToSchema, serde::Serialize)]
598/// #[repr(i8)]
599/// #[serde(tag = "code")]
600/// enum ExitCode {
601///     Error = -1,
602///     #[serde(skip)]
603///     Unknown = 0,
604///     Ok = 1,
605///  }
606/// ```
607///
608/// # Generic schemas
609///
610/// Fastapi supports full set of deeply nested generics as shown below. The type will implement
611/// [`ToSchema`][to_schema] if and only if all the generic types implement `ToSchema` by default.
612/// That is in Rust `impl<T> ToSchema for MyType<T> where T: Schema { ... }`.
613/// You can also specify `bound = ...` on the item to override the default auto bounds.
614///
615/// The _`as = ...`_ attribute is used to define the prefixed or alternative name for the component
616/// in question. This same name will be used throughout the OpenAPI generated with `fastapi` when
617/// the type is being referenced in [`OpenApi`][openapi_derive] derive macro or in [`fastapi::path(...)`][path_macro] macro.
618///
619/// ```rust
620/// # use fastapi::ToSchema;
621/// # use std::borrow::Cow;
622///  #[derive(ToSchema)]
623///  #[schema(as = path::MyType<T>)]
624///  struct Type<T> {
625///      t: T,
626///  }
627///
628///  #[derive(ToSchema)]
629///  struct Person<'p, T: Sized, P> {
630///      id: usize,
631///      name: Option<Cow<'p, str>>,
632///      field: T,
633///      t: P,
634///  }
635///
636///  #[derive(ToSchema)]
637///  #[schema(as = path::to::PageList)]
638///  struct Page<T> {
639///      total: usize,
640///      page: usize,
641///      pages: usize,
642///      items: Vec<T>,
643///  }
644///
645///  #[derive(ToSchema)]
646///  #[schema(as = path::to::Element<T>)]
647///  enum E<T> {
648///      One(T),
649///      Many(Vec<T>),
650///  }
651/// ```
652/// When generic types are registered to the `OpenApi` the full type declaration must be provided.
653/// See the full example in test [schema_generics.rs](https://github.com/nxpkg/fastapi/blob/master/fastapi-gen/tests/schema_generics.rs)
654///
655/// # Examples
656///
657/// _**Simple example of a Pet with descriptions and object level example.**_
658/// ```rust
659/// # use fastapi::ToSchema;
660/// /// This is a pet.
661/// #[derive(ToSchema)]
662/// #[schema(example = json!({"name": "bob the cat", "id": 0}))]
663/// struct Pet {
664///     /// Unique id of a pet.
665///     id: u64,
666///     /// Name of a pet.
667///     name: String,
668///     /// Age of a pet if known.
669///     age: Option<i32>,
670/// }
671/// ```
672///
673/// _**The `schema` attribute can also be placed at field level as follows.**_
674/// ```rust
675/// # use fastapi::ToSchema;
676/// #[derive(ToSchema)]
677/// struct Pet {
678///     #[schema(example = 1, default = 0)]
679///     id: u64,
680///     name: String,
681///     age: Option<i32>,
682/// }
683/// ```
684///
685/// _**You can also use method reference for attribute values.**_
686/// ```rust
687/// # use fastapi::ToSchema;
688/// #[derive(ToSchema)]
689/// struct Pet {
690///     #[schema(example = u64::default, default = u64::default)]
691///     id: u64,
692///     #[schema(default = default_name)]
693///     name: String,
694///     age: Option<i32>,
695/// }
696///
697/// fn default_name() -> String {
698///     "bob".to_string()
699/// }
700/// ```
701///
702/// _**For enums and unnamed field structs you can define `schema` at type level.**_
703/// ```rust
704/// # use fastapi::ToSchema;
705/// #[derive(ToSchema)]
706/// #[schema(example = "Bus")]
707/// enum VehicleType {
708///     Rocket, Car, Bus, Submarine
709/// }
710/// ```
711///
712/// _**Also you write mixed enum combining all above types.**_
713/// ```rust
714/// # use fastapi::ToSchema;
715/// #[derive(ToSchema)]
716/// enum ErrorResponse {
717///     InvalidCredentials,
718///     #[schema(default = String::default, example = "Pet not found")]
719///     NotFound(String),
720///     System {
721///         #[schema(example = "Unknown system failure")]
722///         details: String,
723///     }
724/// }
725/// ```
726///
727/// _**It is possible to specify the title of each variant to help generators create named structures.**_
728/// ```rust
729/// # use fastapi::ToSchema;
730/// #[derive(ToSchema)]
731/// enum ErrorResponse {
732///     #[schema(title = "InvalidCredentials")]
733///     InvalidCredentials,
734///     #[schema(title = "NotFound")]
735///     NotFound(String),
736/// }
737/// ```
738///
739/// _**Use `xml` attribute to manipulate xml output.**_
740/// ```rust
741/// # use fastapi::ToSchema;
742/// #[derive(ToSchema)]
743/// #[schema(xml(name = "user", prefix = "u", namespace = "https://user.xml.schema.test"))]
744/// struct User {
745///     #[schema(xml(attribute, prefix = "u"))]
746///     id: i64,
747///     #[schema(xml(name = "user_name", prefix = "u"))]
748///     username: String,
749///     #[schema(xml(wrapped(name = "linkList"), name = "link"))]
750///     links: Vec<String>,
751///     #[schema(xml(wrapped, name = "photo_url"))]
752///     photos_urls: Vec<String>
753/// }
754/// ```
755///
756/// _**Use of Rust's own `#[deprecated]` attribute will reflect to generated OpenAPI spec.**_
757/// ```rust
758/// # use fastapi::ToSchema;
759/// #[derive(ToSchema)]
760/// #[deprecated]
761/// struct User {
762///     id: i64,
763///     username: String,
764///     links: Vec<String>,
765///     #[deprecated]
766///     photos_urls: Vec<String>
767/// }
768/// ```
769///
770/// _**Enforce type being used in OpenAPI spec to [`String`] with `value_type` and set format to octet stream
771/// with [`SchemaFormat::KnownFormat(KnownFormat::Binary)`][binary].**_
772/// ```rust
773/// # use fastapi::ToSchema;
774/// #[derive(ToSchema)]
775/// struct Post {
776///     id: i32,
777///     #[schema(value_type = String, format = Binary)]
778///     value: Vec<u8>,
779/// }
780/// ```
781///
782/// _**Enforce type being used in OpenAPI spec to [`String`] with `value_type` option.**_
783/// ```rust
784/// # use fastapi::ToSchema;
785/// #[derive(ToSchema)]
786/// #[schema(value_type = String)]
787/// struct Value(i64);
788/// ```
789///
790/// _**Override the `Bar` reference with a `custom::NewBar` reference.**_
791/// ```rust
792/// # use fastapi::ToSchema;
793/// #  mod custom {
794/// #      #[derive(fastapi::ToSchema)]
795/// #      pub struct NewBar;
796/// #  }
797/// #
798/// # struct Bar;
799/// #[derive(ToSchema)]
800/// struct Value {
801///     #[schema(value_type = custom::NewBar)]
802///     field: Bar,
803/// };
804/// ```
805///
806/// _**Use a virtual `Object` type to render generic `object` _(`type: object`)_ in OpenAPI spec.**_
807/// ```rust
808/// # use fastapi::ToSchema;
809/// # mod custom {
810/// #    struct NewBar;
811/// # }
812/// #
813/// # struct Bar;
814/// #[derive(ToSchema)]
815/// struct Value {
816///     #[schema(value_type = Object)]
817///     field: Bar,
818/// };
819/// ```
820/// More examples for _`value_type`_ in [`IntoParams` derive docs][into_params].
821///
822/// _**Serde `rename` / `rename_all` will take precedence over schema `rename` / `rename_all`.**_
823/// ```rust
824/// #[derive(fastapi::ToSchema, serde::Deserialize)]
825/// #[serde(rename_all = "lowercase")]
826/// #[schema(rename_all = "UPPERCASE")]
827/// enum Random {
828///     #[serde(rename = "string_value")]
829///     #[schema(rename = "custom_value")]
830///     String(String),
831///
832///     Number {
833///         id: i32,
834///     }
835/// }
836/// ```
837///
838/// _**Add `title` to the enum.**_
839/// ```rust
840/// #[derive(fastapi::ToSchema)]
841/// #[schema(title = "UserType")]
842/// enum UserType {
843///     Admin,
844///     Moderator,
845///     User,
846/// }
847/// ```
848///
849/// _**Example with validation attributes.**_
850/// ```rust
851/// #[derive(fastapi::ToSchema)]
852/// struct Item {
853///     #[schema(maximum = 10, minimum = 5, multiple_of = 2.5)]
854///     id: i32,
855///     #[schema(max_length = 10, min_length = 5, pattern = "[a-z]*")]
856///     value: String,
857///     #[schema(max_items = 5, min_items = 1)]
858///     items: Vec<String>,
859/// }
860/// ````
861///
862/// _**Use `schema_with` to manually implement schema for a field.**_
863/// ```rust
864/// # use fastapi::openapi::schema::{Object, ObjectBuilder};
865/// fn custom_type() -> Object {
866///     ObjectBuilder::new()
867///         .schema_type(fastapi::openapi::schema::Type::String)
868///         .format(Some(fastapi::openapi::SchemaFormat::Custom(
869///             "email".to_string(),
870///         )))
871///         .description(Some("this is the description"))
872///         .build()
873/// }
874///
875/// #[derive(fastapi::ToSchema)]
876/// struct Value {
877///     #[schema(schema_with = custom_type)]
878///     id: String,
879/// }
880/// ```
881///
882/// _**Use `as` attribute to change the name and the path of the schema in the generated OpenAPI
883/// spec.**_
884/// ```rust
885///  #[derive(fastapi::ToSchema)]
886///  #[schema(as = api::models::person::Person)]
887///  struct Person {
888///      name: String,
889///  }
890/// ```
891///
892/// _**Use `bound` attribute to override the default impl bounds.**_
893///
894/// `bound = ...` accepts a string containing zero or more where-predicates separated by comma, as
895/// the similar syntax to [`serde(bound = ...)`](https://serde.rs/container-attrs.html#bound).
896/// If `bound = ...` exists, the default auto bounds (requiring all generic types to implement
897/// `ToSchema`) will not be applied anymore, and only the specified predicates are added to the
898/// `where` clause of generated `impl` blocks.
899///
900/// ```rust
901/// // Override the default bounds to only require `T: ToSchema`, ignoring unused `U`.
902/// #[derive(fastapi::ToSchema, serde::Serialize)]
903/// #[schema(bound = "T: fastapi::ToSchema")]
904/// struct Partial<T, U> {
905///     used_in_api: T,
906///     #[serde(skip)]
907///     not_in_api: std::marker::PhantomData<U>,
908/// }
909///
910/// // Just remove the auto-bounds. So we got `Unused<T>: ToSchema` for any `T`.
911/// #[derive(fastapi::ToSchema, serde::Serialize)]
912/// #[schema(bound = "")]
913/// struct Unused<T> {
914///     #[serde(skip)]
915///     _marker: std::marker::PhantomData<T>,
916/// }
917/// ```
918///
919/// _**Use `no_recursion` attribute to break from looping schema tree e.g. `Pet` -> `Owner` ->
920/// `Pet`.**_
921///
922/// `no_recursion` attribute can be provided on named field of a struct, on unnamed struct or unnamed
923/// enum variant. It must be provided in case of looping schema tree in order to stop recursion.
924/// Failing to do so will cause runtime **panic**.
925/// ```rust
926/// # use fastapi::ToSchema;
927/// #
928/// #[derive(ToSchema)]
929/// pub struct Pet {
930///     name: String,
931///     owner: Owner,
932/// }
933///
934/// #[derive(ToSchema)]
935/// pub struct Owner {
936///     name: String,
937///     #[schema(no_recursion)]
938///     pets: Vec<Pet>,
939/// }
940/// ```
941///
942/// [to_schema]: trait.ToSchema.html
943/// [known_format]: openapi/schema/enum.KnownFormat.html
944/// [binary]: openapi/schema/enum.KnownFormat.html#variant.Binary
945/// [xml]: openapi/xml/struct.Xml.html
946/// [into_params]: derive.IntoParams.html
947/// [primitive]: https://doc.rust-lang.org/std/primitive/index.html
948/// [serde attributes]: https://serde.rs/attributes.html
949/// [discriminator]: openapi/schema/struct.Discriminator.html
950/// [enum_schema]: derive.ToSchema.html#enum-optional-configuration-options-for-schema
951/// [openapi_derive]: derive.OpenApi.html
952/// [to_schema_xml]: macro@ToSchema#xml-attribute-configuration-options
953/// [schema_object_encoding]: openapi/schema/struct.Object.html#structfield.content_encoding
954/// [schema_object_media_type]: openapi/schema/struct.Object.html#structfield.content_media_type
955/// [path_macro]: macro@path
956/// [const]: https://doc.rust-lang.org/std/keyword.const.html
957pub fn derive_to_schema(input: TokenStream) -> TokenStream {
958    let DeriveInput {
959        attrs,
960        ident,
961        data,
962        generics,
963        ..
964    } = syn::parse_macro_input!(input);
965
966    Schema::new(&data, &attrs, &ident, &generics)
967        .as_ref()
968        .map_or_else(Diagnostics::to_token_stream, Schema::to_token_stream)
969        .into()
970}
971
972#[proc_macro_attribute]
973/// Path attribute macro implements OpenAPI path for the decorated function.
974///
975/// This is a `#[derive]` implementation for [`Path`][path] trait. Macro accepts set of attributes that can
976/// be used to configure and override default values what are resolved automatically.
977///
978/// You can use the Rust's own `#[deprecated]` attribute on functions to mark it as deprecated and it will
979/// reflect to the generated OpenAPI spec. Only **parameters** has a special **deprecated** attribute to define them as deprecated.
980///
981/// `#[deprecated]` attribute supports adding additional details such as a reason and or since version but this is is not supported in
982/// OpenAPI. OpenAPI has only a boolean flag to determine deprecation. While it is totally okay to declare deprecated with reason
983/// `#[deprecated  = "There is better way to do this"]` the reason would not render in OpenAPI spec.
984///
985/// Doc comment at decorated function will be used for _`description`_ and _`summary`_ of the path.
986/// First line of the doc comment will be used as the _`summary`_ while the remaining lines will be
987/// used as _`description`_.
988/// ```rust
989/// /// This is a summary of the operation
990/// ///
991/// /// The rest of the doc comment will be included to operation description.
992/// #[fastapi::path(get, path = "/operation")]
993/// fn operation() {}
994/// ```
995///
996/// # Path Attributes
997///
998/// * `operation` _**Must be first parameter!**_ Accepted values are known HTTP operations such as
999///   _`get, post, put, delete, head, options, patch, trace`_.
1000///
1001/// * `method(get, head, ...)` Http methods for the operation. This allows defining multiple
1002///   HTTP methods at once for single operation. Either _`operation`_ or _`method(...)`_ _**must be
1003///   provided.**_
1004///
1005/// * `path = "..."` Must be OpenAPI format compatible str with arguments within curly braces. E.g _`{id}`_
1006///
1007/// * `impl_for = ...` Optional type to implement the [`Path`][path] trait. By default a new type
1008///   is used for the implementation.
1009///
1010/// * `operation_id = ...` Unique operation id for the endpoint. By default this is mapped to function name.
1011///   The operation_id can be any valid expression (e.g. string literals, macro invocations, variables) so long
1012///   as its result can be converted to a `String` using `String::from`.
1013///
1014/// * `context_path = "..."` Can add optional scope for **path**. The **context_path** will be prepended to beginning of **path**.
1015///   This is particularly useful when **path** does not contain the full path to the endpoint. For example if web framework
1016///   allows operation to be defined under some context path or scope which does not reflect to the resolved path then this
1017///   **context_path** can become handy to alter the path.
1018///
1019/// * `tag = "..."` Can be used to group operations. Operations with same tag are grouped together. By default
1020///   this is derived from the module path of the handler that is given to [`OpenApi`][openapi].
1021///
1022/// * `tags = ["tag1", ...]` Can be used to group operations. Operations with same tag are grouped
1023///   together. Tags attribute can be used to add additional _tags_ for the operation. If both
1024///   _`tag`_ and _`tags`_ are provided then they will be combined to a single _`tags`_ array.
1025///
1026/// * `request_body = ... | request_body(...)` Defining request body indicates that the request is expecting request body within
1027///   the performed request.
1028///
1029/// * `responses(...)` Slice of responses the endpoint is going to possibly return to the caller.
1030///
1031/// * `params(...)` Slice of params that the endpoint accepts.
1032///
1033/// * `security(...)` List of [`SecurityRequirement`][security]s local to the path operation.
1034///
1035/// # Request Body Attributes
1036///
1037/// ## Simple format definition by `request_body = ...`
1038/// * _`request_body = Type`_, _`request_body = inline(Type)`_ or _`request_body = ref("...")`_.
1039///   The given _`Type`_ can be any Rust type that is JSON parseable. It can be Option, Vec or Map etc.
1040///   With _`inline(...)`_ the schema will be inlined instead of a referenced which is the default for
1041///   [`ToSchema`][to_schema] types. _`ref("./external.json")`_ can be used to reference external
1042///   json file for body schema. **Note!** Fastapi does **not** guarantee that free form _`ref`_ is accessible via
1043///   OpenAPI doc or Swagger UI, users are responsible for making these guarantees.
1044///
1045/// ## Advanced format definition by `request_body(...)`
1046///
1047/// With advanced format the request body supports defining either one or multiple request bodies by `content` attribute.
1048///
1049/// ### Common request body attributes
1050///
1051/// * `description = "..."` Define the description for the request body object as str.
1052///
1053/// * `example = ...` Can be _`json!(...)`_. _`json!(...)`_ should be something that
1054///   _`serde_json::json!`_ can parse as a _`serde_json::Value`_.
1055///
1056/// * `examples(...)` Define multiple examples for single request body. This attribute is mutually
1057///   exclusive to the _`example`_ attribute and if both are defined this will override the _`example`_.
1058///   This has same syntax as _`examples(...)`_ in [Response Attributes](#response-attributes)
1059///   _examples(...)_
1060///
1061/// ### Single request body content
1062///
1063/// * `content = ...` Can be _`content = Type`_, _`content = inline(Type)`_ or _`content = ref("...")`_. The
1064///   given _`Type`_ can be any Rust type that is JSON parseable. It can be Option, Vec
1065///   or Map etc. With _`inline(...)`_ the schema will be inlined instead of a referenced
1066///   which is the default for [`ToSchema`][to_schema] types. _`ref("./external.json")`_
1067///   can be used to reference external json file for body schema. **Note!** Fastapi does **not** guarantee
1068///   that free form _`ref`_ is accessible via OpenAPI doc or Swagger UI, users are responsible for making
1069///   these guarantees.
1070///
1071/// * `content_type = "..."` Can be used to override the default behavior
1072///   of auto resolving the content type from the `content` attribute. If defined the value should be valid
1073///   content type such as _`application/json`_ . By default the content type is _`text/plain`_
1074///   for [primitive Rust types][primitive], `application/octet-stream` for _`[u8]`_ and _`application/json`_
1075///   for struct and mixed enum types.
1076///
1077/// _**Example of single request body definitions.**_
1078/// ```text
1079///  request_body(content = String, description = "Xml as string request", content_type = "text/xml"),
1080///  request_body(content_type = "application/json"),
1081///  request_body = Pet,
1082///  request_body = Option<[Pet]>,
1083/// ```
1084///
1085/// ### Multiple request body content
1086///
1087/// * `content(...)` Can be tuple of content tuples according to format below.
1088///   ```text
1089///   ( schema )
1090///   ( schema = "content/type", example = ..., examples(..., ...)  )
1091///   ( "content/type", ),
1092///   ( "content/type", example = ..., examples(..., ...) )
1093///   ```
1094///
1095///   First argument of content tuple is _`schema`_, which is optional as long as either _`schema`_
1096///   or _`content/type`_ is defined. The _`schema`_ and _`content/type`_ is separated with equals
1097///   (=) sign. Optionally content tuple supports defining _`example`_  and _`examples`_ arguments. See
1098///   [common request body attributes][macro@path#common-request-body-attributes]
1099///
1100/// _**Example of multiple request body definitions.**_
1101///
1102/// ```text
1103///  // guess the content type for Pet and Pet2
1104///  request_body(description = "Common description",
1105///     content(
1106///         (Pet),
1107///         (Pet2)
1108///     )
1109///  ),
1110///  // define explicit content types
1111///  request_body(description = "Common description",
1112///     content(
1113///         (Pet = "application/json", examples(..., ...), example = ...),
1114///         (Pet2 = "text/xml", examples(..., ...), example = ...)
1115///     )
1116///  ),
1117///  // omit schema and accept arbitrary content types
1118///  request_body(description = "Common description",
1119///     content(
1120///         ("application/json"),
1121///         ("text/xml", examples(..., ...), example = ...)
1122///     )
1123///  ),
1124/// ```
1125///
1126/// # Response Attributes
1127///
1128/// * `status = ...` Is either a valid http status code integer. E.g. _`200`_ or a string value representing
1129///   a range such as _`"4XX"`_ or `"default"` or a valid _`http::status::StatusCode`_.
1130///   _`StatusCode`_ can either be use path to the status code or _status code_ constant directly.
1131///
1132/// * `description = "..."` Define description for the response as str.
1133///
1134/// * `body = ...` Optional response body object type. When left empty response does not expect to send any
1135///   response body. Can be _`body = Type`_, _`body = inline(Type)`_, or _`body = ref("...")`_.
1136///   The given _`Type`_ can be any Rust type that is JSON parseable. It can be Option, Vec or Map etc.
1137///   With _`inline(...)`_ the schema will be inlined instead of a referenced which is the default for
1138///   [`ToSchema`][to_schema] types. _`ref("./external.json")`_
1139///   can be used to reference external json file for body schema. **Note!** Fastapi does **not** guarantee
1140///   that free form _`ref`_ is accessible via OpenAPI doc or Swagger UI, users are responsible for making
1141///   these guarantees.
1142///
1143/// * `content_type = "..."` Can be used to override the default behavior
1144///   of auto resolving the content type from the `body` attribute. If defined the value should be valid
1145///   content type such as _`application/json`_ . By default the content type is _`text/plain`_
1146///   for [primitive Rust types][primitive], `application/octet-stream` for _`[u8]`_ and _`application/json`_
1147///   for struct and mixed enum types.
1148///
1149/// * `headers(...)` Slice of response headers that are returned back to a caller.
1150///
1151/// * `example = ...` Can be _`json!(...)`_. _`json!(...)`_ should be something that
1152///   _`serde_json::json!`_ can parse as a _`serde_json::Value`_.
1153///
1154/// * `response = ...` Type what implements [`ToResponse`][to_response_trait] trait. This can alternatively be used to
1155///    define response attributes. _`response`_ attribute cannot co-exist with other than _`status`_ attribute.
1156///
1157/// * `content((...), (...))` Can be used to define multiple return types for single response status. Supports same syntax as
1158///   [multiple request body content][`macro@path#multiple-request-body-content`].
1159///
1160/// * `examples(...)` Define multiple examples for single response. This attribute is mutually
1161///   exclusive to the _`example`_ attribute and if both are defined this will override the _`example`_.
1162///
1163/// * `links(...)` Define a map of operations links that can be followed from the response.
1164///
1165/// ## Response `examples(...)` syntax
1166///
1167/// * `name = ...` This is first attribute and value must be literal string.
1168/// * `summary = ...` Short description of example. Value must be literal string.
1169/// * `description = ...` Long description of example. Attribute supports markdown for rich text
1170///   representation. Value must be literal string.
1171/// * `value = ...` Example value. It must be _`json!(...)`_. _`json!(...)`_ should be something that
1172///   _`serde_json::json!`_ can parse as a _`serde_json::Value`_.
1173/// * `external_value = ...` Define URI to literal example value. This is mutually exclusive to
1174///   the _`value`_ attribute. Value must be literal string.
1175///
1176///  _**Example of example definition.**_
1177/// ```text
1178///  ("John" = (summary = "This is John", value = json!({"name": "John"})))
1179/// ```
1180///
1181/// ## Response `links(...)` syntax
1182///
1183/// * `operation_ref = ...` Define a relative or absolute URI reference to an OAS operation. This field is
1184///   mutually exclusive of the _`operation_id`_ field, and **must** point to an [Operation Object][operation].
1185///   Value can be be [`str`] or an expression such as [`include_str!`][include_str] or static
1186///   [`const`][const] reference.
1187///
1188/// * `operation_id = ...` Define the name of an existing, resolvable OAS operation, as defined with a unique
1189///   _`operation_id`_. This field is mutually exclusive of the _`operation_ref`_ field.
1190///   Value can be be [`str`] or an expression such as [`include_str!`][include_str] or static
1191///   [`const`][const] reference.
1192///
1193/// * `parameters(...)` A map representing parameters to pass to an operation as specified with _`operation_id`_
1194///   or identified by _`operation_ref`_. The key is parameter name to be used and value can
1195///   be any value supported by JSON or an [expression][expression] e.g. `$path.id`
1196///     * `name = ...` Define name for the parameter.
1197///       Value can be be [`str`] or an expression such as [`include_str!`][include_str] or static
1198///       [`const`][const] reference.
1199///     * `value` = Any value that can be supported by JSON or an [expression][expression].
1200///
1201///     _**Example of parameters syntax:**_
1202///     ```text
1203///     parameters(
1204///          ("name" = value),
1205///          ("name" = value)
1206///     ),
1207///     ```
1208///
1209/// * `request_body = ...` Define a literal value or an [expression][expression] to be used as request body when
1210///   operation is called
1211///
1212/// * `description = ...` Define description of the link. Value supports Markdown syntax.Value can be be [`str`] or
1213///   an expression such as [`include_str!`][include_str] or static [`const`][const] reference.
1214///
1215/// * `server(...)` Define [Server][server] object to be used by the target operation. See
1216///   [server syntax][server_derive_syntax]
1217///
1218/// **Links syntax example:** See the full example below in [examples](#examples).
1219/// ```text
1220/// responses(
1221///     (status = 200, description = "success response",
1222///         links(
1223///             ("link_name" = (
1224///                 operation_id = "test_links",
1225///                 parameters(("key" = "value"), ("json_value" = json!(1))),
1226///                 request_body = "this is body",
1227///                 server(url = "http://localhost")
1228///             ))
1229///         )
1230///     )
1231/// )
1232/// ```
1233///
1234/// **Minimal response format:**
1235/// ```text
1236/// responses(
1237///     (status = 200, description = "success response"),
1238///     (status = 404, description = "resource missing"),
1239///     (status = "5XX", description = "server error"),
1240///     (status = StatusCode::INTERNAL_SERVER_ERROR, description = "internal server error"),
1241///     (status = IM_A_TEAPOT, description = "happy easter")
1242/// )
1243/// ```
1244///
1245/// **More complete Response:**
1246/// ```text
1247/// responses(
1248///     (status = 200, description = "Success response", body = Pet, content_type = "application/json",
1249///         headers(...),
1250///         example = json!({"id": 1, "name": "bob the cat"})
1251///     )
1252/// )
1253/// ```
1254///
1255/// **Multiple response return types with _`content(...)`_ attribute:**
1256///
1257/// _**Define multiple response return types for single response status with their own example.**_
1258/// ```text
1259/// responses(
1260///    (status = 200, content(
1261///            (User = "application/vnd.user.v1+json", example = json!(User {id: "id".to_string()})),
1262///            (User2 = "application/vnd.user.v2+json", example = json!(User2 {id: 2}))
1263///        )
1264///    )
1265/// )
1266/// ```
1267///
1268/// ### Using `ToResponse` for reusable responses
1269///
1270/// _**`ReusableResponse` must be a type that implements [`ToResponse`][to_response_trait].**_
1271/// ```text
1272/// responses(
1273///     (status = 200, response = ReusableResponse)
1274/// )
1275/// ```
1276///
1277/// _**[`ToResponse`][to_response_trait] can also be inlined to the responses map.**_
1278/// ```text
1279/// responses(
1280///     (status = 200, response = inline(ReusableResponse))
1281/// )
1282/// ```
1283///
1284/// ## Responses from `IntoResponses`
1285///
1286/// _**Responses for a path can be specified with one or more types that implement
1287/// [`IntoResponses`][into_responses_trait].**_
1288/// ```text
1289/// responses(MyResponse)
1290/// ```
1291///
1292/// # Response Header Attributes
1293///
1294/// * `name` Name of the header. E.g. _`x-csrf-token`_
1295///
1296/// * `type` Additional type of the header value. Can be `Type` or `inline(Type)`.
1297///   The given _`Type`_ can be any Rust type that is JSON parseable. It can be Option, Vec or Map etc.
1298///   With _`inline(...)`_ the schema will be inlined instead of a referenced which is the default for
1299///   [`ToSchema`][to_schema] types. **Reminder!** It's up to the user to use valid type for the
1300///   response header.
1301///
1302/// * `description = "..."` Can be used to define optional description for the response header as str.
1303///
1304/// **Header supported formats:**
1305///
1306/// ```text
1307/// ("x-csrf-token"),
1308/// ("x-csrf-token" = String, description = "New csrf token"),
1309/// ```
1310///
1311/// # Params Attributes
1312///
1313/// The list of attributes inside the `params(...)` attribute can take two forms: [Tuples](#tuples) or [IntoParams
1314/// Type](#intoparams-type).
1315///
1316/// ## Tuples
1317///
1318/// In the tuples format, parameters are specified using the following attributes inside a list of
1319/// tuples separated by commas:
1320///
1321/// * `name` _**Must be the first argument**_. Define the name for parameter.
1322///
1323/// * `parameter_type` Define possible type for the parameter. Can be `Type` or `inline(Type)`.
1324///   The given _`Type`_ can be any Rust type that is JSON parseable. It can be Option, Vec or Map etc.
1325///   With _`inline(...)`_ the schema will be inlined instead of a referenced which is the default for
1326///   [`ToSchema`][to_schema] types. Parameter type is placed after `name` with
1327///   equals sign E.g. _`"id" = string`_
1328///
1329/// * `in` _**Must be placed after name or parameter_type**_. Define the place of the parameter.
1330///   This must be one of the variants of [`openapi::path::ParameterIn`][in_enum].
1331///   E.g. _`Path, Query, Header, Cookie`_
1332///
1333/// * `deprecated` Define whether the parameter is deprecated or not. Can optionally be defined
1334///    with explicit `bool` value as _`deprecated = bool`_.
1335///
1336/// * `description = "..."` Define possible description for the parameter as str.
1337///
1338/// * `style = ...` Defines how parameters are serialized by [`ParameterStyle`][style]. Default values are based on _`in`_ attribute.
1339///
1340/// * `explode` Defines whether new _`parameter=value`_ is created for each parameter within _`object`_ or _`array`_.
1341///
1342/// * `allow_reserved` Defines whether reserved characters _`:/?#[]@!$&'()*+,;=`_ is allowed within value.
1343///
1344/// * `example = ...` Can method reference or _`json!(...)`_. Given example
1345///   will override any example in underlying parameter type.
1346///
1347/// ##### Parameter type attributes
1348///
1349/// These attributes supported when _`parameter_type`_ is present. Either by manually providing one
1350/// or otherwise resolved e.g from path macro argument when _`actix_extras`_ crate feature is
1351/// enabled.
1352///
1353/// * `format = ...` May either be variant of the [`KnownFormat`][known_format] enum, or otherwise
1354///   an open value as a string. By default the format is derived from the type of the property
1355///   according OpenApi spec.
1356///
1357/// * `write_only` Defines property is only used in **write** operations *POST,PUT,PATCH* but not in *GET*
1358///
1359/// * `read_only` Defines property is only used in **read** operations *GET* but not in *POST,PUT,PATCH*
1360///
1361/// * `xml(...)` Can be used to define [`Xml`][xml] object properties for the parameter type.
1362///    See configuration options at xml attributes of [`ToSchema`][to_schema_xml]
1363///
1364/// * `nullable` Defines property is nullable (note this is different to non-required).
1365///
1366/// * `multiple_of = ...` Can be used to define multiplier for a value. Value is considered valid
1367///   division will result an `integer`. Value must be strictly above _`0`_.
1368///
1369/// * `maximum = ...` Can be used to define inclusive upper bound to a `number` value.
1370///
1371/// * `minimum = ...` Can be used to define inclusive lower bound to a `number` value.
1372///
1373/// * `exclusive_maximum = ...` Can be used to define exclusive upper bound to a `number` value.
1374///
1375/// * `exclusive_minimum = ...` Can be used to define exclusive lower bound to a `number` value.
1376///
1377/// * `max_length = ...` Can be used to define maximum length for `string` types.
1378///
1379/// * `min_length = ...` Can be used to define minimum length for `string` types.
1380///
1381/// * `pattern = ...` Can be used to define valid regular expression in _ECMA-262_ dialect the field value must match.
1382///
1383/// * `max_items = ...` Can be used to define maximum items allowed for `array` fields. Value must
1384///   be non-negative integer.
1385///
1386/// * `min_items = ...` Can be used to define minimum items allowed for `array` fields. Value must
1387///   be non-negative integer.
1388///
1389/// ##### Parameter Formats
1390/// ```test
1391/// ("name" = ParameterType, ParameterIn, ...)
1392/// ("name", ParameterIn, ...)
1393/// ```
1394///
1395/// **For example:**
1396///
1397/// ```text
1398/// params(
1399///     ("limit" = i32, Query),
1400///     ("x-custom-header" = String, Header, description = "Custom header"),
1401///     ("id" = String, Path, deprecated, description = "Pet database id"),
1402///     ("name", Path, deprecated, description = "Pet name"),
1403///     (
1404///         "value" = inline(Option<[String]>),
1405///         Query,
1406///         description = "Value description",
1407///         style = Form,
1408///         allow_reserved,
1409///         deprecated,
1410///         explode,
1411///         example = json!(["Value"])),
1412///         max_length = 10,
1413///         min_items = 1
1414///     )
1415/// )
1416/// ```
1417///
1418/// ## IntoParams Type
1419///
1420/// In the IntoParams parameters format, the parameters are specified using an identifier for a type
1421/// that implements [`IntoParams`][into_params]. See [`IntoParams`][into_params] for an
1422/// example.
1423///
1424/// ```text
1425/// params(MyParameters)
1426/// ```
1427///
1428/// **Note!** that `MyParameters` can also be used in combination with the [tuples
1429/// representation](#tuples) or other structs.
1430/// ```text
1431/// params(
1432///     MyParameters1,
1433///     MyParameters2,
1434///     ("id" = String, Path, deprecated, description = "Pet database id"),
1435/// )
1436/// ```
1437///
1438/// # Security Requirement Attributes
1439///
1440/// * `name` Define the name for security requirement. This must match to name of existing
1441///   [`SecurityScheme`][security_scheme].
1442/// * `scopes = [...]` Define the list of scopes needed. These must be scopes defined already in
1443///   existing [`SecurityScheme`][security_scheme].
1444///
1445/// **Security Requirement supported formats:**
1446///
1447/// ```text
1448/// (),
1449/// ("name" = []),
1450/// ("name" = ["scope1", "scope2"]),
1451/// ("name" = ["scope1", "scope2"], "name2" = []),
1452/// ```
1453///
1454/// Leaving empty _`()`_ creates an empty [`SecurityRequirement`][security] this is useful when
1455/// security requirement is optional for operation.
1456///
1457/// You can define multiple security requirements within same parenthesis separated by comma. This
1458/// allows you to define keys that must be simultaneously provided for the endpoint / API.
1459///
1460/// _**Following could be explained as: Security is optional and if provided it must either contain
1461/// `api_key` or `key AND key2`.**_
1462/// ```text
1463/// (),
1464/// ("api_key" = []),
1465/// ("key" = [], "key2" = []),
1466/// ```
1467///
1468/// # actix_extras feature support for actix-web
1469///
1470/// **actix_extras** feature gives **fastapi** ability to parse path operation information from **actix-web** types and macros.
1471///
1472/// 1. Ability to parse `path` from **actix-web** path attribute macros e.g. _`#[get(...)]`_ or
1473///    `#[route(...)]`.
1474/// 2. Ability to parse [`std::primitive`]  or [`String`] or [`tuple`] typed `path` parameters from **actix-web** _`web::Path<...>`_.
1475/// 3. Ability to parse `path` and `query` parameters form **actix-web** _`web::Path<...>`_, _`web::Query<...>`_ types
1476///    with [`IntoParams`][into_params] trait.
1477///
1478/// See the **actix_extras** in action in examples [todo-actix](https://github.com/nxpkg/fastapi/tree/master/examples/todo-actix).
1479///
1480/// With **actix_extras** feature enabled the you can leave out definitions for **path**, **operation**
1481/// and **parameter types**.
1482/// ```rust
1483/// use actix_web::{get, web, HttpResponse, Responder};
1484/// use serde_json::json;
1485///
1486/// /// Get Pet by id
1487/// #[fastapi::path(
1488///     responses(
1489///         (status = 200, description = "Pet found from database")
1490///     ),
1491///     params(
1492///         ("id", description = "Pet id"),
1493///     )
1494/// )]
1495/// #[get("/pet/{id}")]
1496/// async fn get_pet_by_id(id: web::Path<i32>) -> impl Responder {
1497///     HttpResponse::Ok().json(json!({ "pet": format!("{:?}", &id.into_inner()) }))
1498/// }
1499/// ```
1500///
1501/// With **actix_extras** you may also not to list any _**params**_ if you do not want to specify any description for them. Params are
1502/// resolved from path and the argument types of handler
1503/// ```rust
1504/// use actix_web::{get, web, HttpResponse, Responder};
1505/// use serde_json::json;
1506///
1507/// /// Get Pet by id
1508/// #[fastapi::path(
1509///     responses(
1510///         (status = 200, description = "Pet found from database")
1511///     )
1512/// )]
1513/// #[get("/pet/{id}")]
1514/// async fn get_pet_by_id(id: web::Path<i32>) -> impl Responder {
1515///     HttpResponse::Ok().json(json!({ "pet": format!("{:?}", &id.into_inner()) }))
1516/// }
1517/// ```
1518///
1519/// # rocket_extras feature support for rocket
1520///
1521/// **rocket_extras** feature enhances path operation parameter support. It gives **fastapi** ability to parse `path`, `path parameters`
1522/// and `query parameters` based on arguments given to **rocket**  proc macros such as _**`#[get(...)]`**_.
1523///
1524/// 1. It is able to parse parameter types for [primitive types][primitive], [`String`], [`Vec`], [`Option`] or [`std::path::PathBuf`]
1525///    type.
1526/// 2. It is able to determine `parameter_in` for [`IntoParams`][into_params] trait used for `FromForm` type of query parameters.
1527///
1528/// See the **rocket_extras** in action in examples [rocket-todo](https://github.com/nxpkg/fastapi/tree/master/examples/rocket-todo).
1529///
1530///
1531/// # axum_extras feature support for axum
1532///
1533/// **axum_extras** feature enhances parameter support for path operation in following ways.
1534///
1535/// 1. It allows users to use tuple style path parameters e.g. _`Path((id, name)): Path<(i32, String)>`_ and resolves
1536///    parameter names and types from it.
1537/// 2. It enhances [`IntoParams` derive][into_params_derive] functionality by automatically resolving _`parameter_in`_ from
1538///     _`Path<...>`_ or _`Query<...>`_ handler function arguments.
1539///
1540/// _**Resole path argument types from tuple style handler arguments.**_
1541/// ```rust
1542/// # use axum::extract::Path;
1543/// /// Get todo by id and name.
1544/// #[fastapi::path(
1545///     get,
1546///     path = "/todo/{id}",
1547///     params(
1548///         ("id", description = "Todo id"),
1549///         ("name", description = "Todo name")
1550///     ),
1551///     responses(
1552///         (status = 200, description = "Get todo success", body = String)
1553///     )
1554/// )]
1555/// async fn get_todo(
1556///     Path((id, name)): Path<(i32, String)>
1557/// ) -> String {
1558///     String::new()
1559/// }
1560/// ```
1561///
1562/// _**Use `IntoParams` to resolve query parameters.**_
1563/// ```rust
1564/// # use serde::Deserialize;
1565/// # use fastapi::IntoParams;
1566/// # use axum::{extract::Query, Json};
1567/// #[derive(Deserialize, IntoParams)]
1568/// struct TodoSearchQuery {
1569///     /// Search by value. Search is incase sensitive.
1570///     value: String,
1571///     /// Search by `done` status.
1572///     done: bool,
1573/// }
1574///
1575/// /// Search Todos by query params.
1576/// #[fastapi::path(
1577///     get,
1578///     path = "/todo/search",
1579///     params(
1580///         TodoSearchQuery
1581///     ),
1582///     responses(
1583///         (status = 200, description = "List matching todos by query", body = [String])
1584///     )
1585/// )]
1586/// async fn search_todos(
1587///     query: Query<TodoSearchQuery>,
1588/// ) -> Json<Vec<String>> {
1589///     Json(vec![])
1590/// }
1591/// ```
1592///
1593/// # Defining file uploads
1594///
1595/// File uploads can be defined in accordance to Open API specification [file uploads][file_uploads].
1596///
1597///
1598/// _**Example sending `jpg` and `png` images as `application/octet-stream`.**_
1599/// ```rust
1600/// #[fastapi::path(
1601///     post,
1602///     request_body(
1603///         content(
1604///             ("image/png"),
1605///             ("image/jpg"),
1606///         ),
1607///     ),
1608///     path = "/test_images"
1609/// )]
1610/// async fn test_images(_body: Vec<u8>) {}
1611/// ```
1612///
1613/// _**Example of sending `multipart` form.**_
1614/// ```rust
1615/// #[derive(fastapi::ToSchema)]
1616/// struct MyForm {
1617///     order_id: i32,
1618///     #[schema(content_media_type = "application/octet-stream")]
1619///     file_bytes: Vec<u8>,
1620/// }
1621///
1622/// #[fastapi::path(
1623///     post,
1624///     request_body(content = inline(MyForm), content_type = "multipart/form-data"),
1625///     path = "/test_multipart"
1626/// )]
1627/// async fn test_multipart(_body: MyForm) {}
1628/// ```
1629///
1630/// _**Example of sending arbitrary binary content as `application/octet-stream`.**_
1631/// ```rust
1632/// #[fastapi::path(
1633///     post,
1634///     request_body = Vec<u8>,
1635///     path = "/test-octet-stream",
1636///     responses(
1637///         (status = 200, description = "success response")
1638///     ),
1639/// )]
1640/// async fn test_octet_stream(_body: Vec<u8>) {}
1641/// ```
1642///
1643/// _**Example of sending `png` image as `base64` encoded.**_
1644/// ```rust
1645/// #[derive(fastapi::ToSchema)]
1646/// #[schema(content_encoding = "base64")]
1647/// struct MyPng(String);
1648///
1649/// #[fastapi::path(
1650///     post,
1651///     request_body(content = inline(MyPng), content_type = "image/png"),
1652///     path = "/test_png",
1653///     responses(
1654///         (status = 200, description = "success response")
1655///     ),
1656/// )]
1657/// async fn test_png(_body: MyPng) {}
1658/// ```
1659///
1660/// # Examples
1661///
1662/// _**More complete example.**_
1663/// ```rust
1664/// # #[derive(fastapi::ToSchema)]
1665/// # struct Pet {
1666/// #    id: u64,
1667/// #    name: String,
1668/// # }
1669/// #
1670/// #[fastapi::path(
1671///    post,
1672///    operation_id = "custom_post_pet",
1673///    path = "/pet",
1674///    tag = "pet_handlers",
1675///    request_body(content = Pet, description = "Pet to store the database", content_type = "application/json"),
1676///    responses(
1677///         (status = 200, description = "Pet stored successfully", body = Pet, content_type = "application/json",
1678///             headers(
1679///                 ("x-cache-len" = String, description = "Cache length")
1680///             ),
1681///             example = json!({"id": 1, "name": "bob the cat"})
1682///         ),
1683///    ),
1684///    params(
1685///      ("x-csrf-token" = String, Header, deprecated, description = "Current csrf token of user"),
1686///    ),
1687///    security(
1688///        (),
1689///        ("my_auth" = ["read:items", "edit:items"]),
1690///        ("token_jwt" = [])
1691///    )
1692/// )]
1693/// fn post_pet(pet: Pet) -> Pet {
1694///     Pet {
1695///         id: 4,
1696///         name: "bob the cat".to_string(),
1697///     }
1698/// }
1699/// ```
1700///
1701/// _**More minimal example with the defaults.**_
1702/// ```rust
1703/// # #[derive(fastapi::ToSchema)]
1704/// # struct Pet {
1705/// #    id: u64,
1706/// #    name: String,
1707/// # }
1708/// #
1709/// #[fastapi::path(
1710///    post,
1711///    path = "/pet",
1712///    request_body = Pet,
1713///    responses(
1714///         (status = 200, description = "Pet stored successfully", body = Pet,
1715///             headers(
1716///                 ("x-cache-len", description = "Cache length")
1717///             )
1718///         ),
1719///    ),
1720///    params(
1721///      ("x-csrf-token", Header, description = "Current csrf token of user"),
1722///    )
1723/// )]
1724/// fn post_pet(pet: Pet) -> Pet {
1725///     Pet {
1726///         id: 4,
1727///         name: "bob the cat".to_string(),
1728///     }
1729/// }
1730/// ```
1731///
1732/// _**Use of Rust's own `#[deprecated]` attribute will reflect to the generated OpenAPI spec and mark this operation as deprecated.**_
1733/// ```rust
1734/// # use actix_web::{get, web, HttpResponse, Responder};
1735/// # use serde_json::json;
1736/// #[fastapi::path(
1737///     responses(
1738///         (status = 200, description = "Pet found from database")
1739///     ),
1740///     params(
1741///         ("id", description = "Pet id"),
1742///     )
1743/// )]
1744/// #[get("/pet/{id}")]
1745/// #[deprecated]
1746/// async fn get_pet_by_id(id: web::Path<i32>) -> impl Responder {
1747///     HttpResponse::Ok().json(json!({ "pet": format!("{:?}", &id.into_inner()) }))
1748/// }
1749/// ```
1750///
1751/// _**Define context path for endpoint. The resolved **path** shown in OpenAPI doc will be `/api/pet/{id}`.**_
1752/// ```rust
1753/// # use actix_web::{get, web, HttpResponse, Responder};
1754/// # use serde_json::json;
1755/// #[fastapi::path(
1756///     context_path = "/api",
1757///     responses(
1758///         (status = 200, description = "Pet found from database")
1759///     )
1760/// )]
1761/// #[get("/pet/{id}")]
1762/// async fn get_pet_by_id(id: web::Path<i32>) -> impl Responder {
1763///     HttpResponse::Ok().json(json!({ "pet": format!("{:?}", &id.into_inner()) }))
1764/// }
1765/// ```
1766///
1767/// _**Example with multiple return types**_
1768/// ```rust
1769/// # trait User {}
1770/// # #[derive(fastapi::ToSchema)]
1771/// # struct User1 {
1772/// #   id: String
1773/// # }
1774/// # impl User for User1 {}
1775/// # #[derive(fastapi::ToSchema)]
1776/// # struct User2 {
1777/// #   id: String
1778/// # }
1779/// # impl User for User2 {}
1780/// #[fastapi::path(
1781///     get,
1782///     path = "/user",
1783///     responses(
1784///         (status = 200, content(
1785///                 (User1 = "application/vnd.user.v1+json", example = json!({"id": "id".to_string()})),
1786///                 (User2 = "application/vnd.user.v2+json", example = json!({"id": 2}))
1787///             )
1788///         )
1789///     )
1790/// )]
1791/// fn get_user() -> Box<dyn User> {
1792///   Box::new(User1 {id: "id".to_string()})
1793/// }
1794/// ````
1795///
1796/// _**Example with multiple examples on single response.**_
1797/// ```rust
1798/// # #[derive(serde::Serialize, serde::Deserialize, fastapi::ToSchema)]
1799/// # struct User {
1800/// #   name: String
1801/// # }
1802/// #[fastapi::path(
1803///     get,
1804///     path = "/user",
1805///     responses(
1806///         (status = 200, body = User,
1807///             examples(
1808///                 ("Demo" = (summary = "This is summary", description = "Long description",
1809///                             value = json!(User{name: "Demo".to_string()}))),
1810///                 ("John" = (summary = "Another user", value = json!({"name": "John"})))
1811///              )
1812///         )
1813///     )
1814/// )]
1815/// fn get_user() -> User {
1816///   User {name: "John".to_string()}
1817/// }
1818/// ```
1819///
1820/// _**Example of using links in response.**_
1821/// ```rust
1822/// # use serde_json::json;
1823///  #[fastapi::path(
1824///     get,
1825///     path = "/test-links",
1826///     responses(
1827///         (status = 200, description = "success response",
1828///             links(
1829///                 ("getFoo" = (
1830///                     operation_id = "test_links",
1831///                     parameters(("key" = "value"), ("json_value" = json!(1))),
1832///                     request_body = "this is body",
1833///                     server(url = "http://localhost")
1834///                 )),
1835///                 ("getBar" = (
1836///                     operation_ref = "this is ref"
1837///                 ))
1838///             )
1839///         )
1840///     ),
1841/// )]
1842/// async fn test_links() -> &'static str {
1843///     ""
1844/// }
1845/// ```
1846///
1847/// [in_enum]: openapi/path/enum.ParameterIn.html
1848/// [path]: trait.Path.html
1849/// [to_schema]: trait.ToSchema.html
1850/// [openapi]: derive.OpenApi.html
1851/// [security]: openapi/security/struct.SecurityRequirement.html
1852/// [security_scheme]: openapi/security/enum.SecurityScheme.html
1853/// [primitive]: https://doc.rust-lang.org/std/primitive/index.html
1854/// [into_params]: trait.IntoParams.html
1855/// [style]: openapi/path/enum.ParameterStyle.html
1856/// [into_responses_trait]: trait.IntoResponses.html
1857/// [into_params_derive]: derive.IntoParams.html
1858/// [to_response_trait]: trait.ToResponse.html
1859/// [known_format]: openapi/schema/enum.KnownFormat.html
1860/// [xml]: openapi/xml/struct.Xml.html
1861/// [to_schema_xml]: macro@ToSchema#xml-attribute-configuration-options
1862/// [relative_references]: https://spec.openapis.org/oas/latest.html#relative-references-in-uris
1863/// [operation]: openapi/path/struct.Operation.html
1864/// [expression]: https://spec.openapis.org/oas/latest.html#runtime-expressions
1865/// [const]: https://doc.rust-lang.org/std/keyword.const.html
1866/// [include_str]: https://doc.rust-lang.org/std/macro.include_str.html
1867/// [server_derive_syntax]: derive.OpenApi.html#servers-attribute-syntax
1868/// [server]: openapi/server/struct.Server.html
1869/// [file_uploads]: <https://spec.openapis.org/oas/v3.1.0.html#considerations-for-file-uploads>
1870pub fn path(attr: TokenStream, item: TokenStream) -> TokenStream {
1871    let path_attribute = syn::parse_macro_input!(attr as PathAttr);
1872
1873    #[cfg(any(
1874        feature = "actix_extras",
1875        feature = "rocket_extras",
1876        feature = "axum_extras",
1877        feature = "auto_into_responses"
1878    ))]
1879    let mut path_attribute = path_attribute;
1880
1881    let ast_fn = match syn::parse::<ItemFn>(item) {
1882        Ok(ast_fn) => ast_fn,
1883        Err(error) => return error.into_compile_error().into_token_stream().into(),
1884    };
1885
1886    #[cfg(feature = "auto_into_responses")]
1887    {
1888        if let Some(responses) = ext::auto_types::parse_fn_operation_responses(&ast_fn) {
1889            path_attribute.responses_from_into_responses(responses);
1890        };
1891    }
1892
1893    let mut resolved_methods = match PathOperations::resolve_operation(&ast_fn) {
1894        Ok(operation) => operation,
1895        Err(diagnostics) => return diagnostics.into_token_stream().into(),
1896    };
1897    let resolved_path = PathOperations::resolve_path(
1898        &resolved_methods
1899            .as_mut()
1900            .map(|operation| mem::take(&mut operation.path).to_string())
1901            .or_else(|| path_attribute.path.as_ref().map(|path| path.to_string())), // cannot use mem take because we need this later
1902    );
1903
1904    #[cfg(any(
1905        feature = "actix_extras",
1906        feature = "rocket_extras",
1907        feature = "axum_extras"
1908    ))]
1909    let mut resolved_path = resolved_path;
1910
1911    #[cfg(any(
1912        feature = "actix_extras",
1913        feature = "rocket_extras",
1914        feature = "axum_extras"
1915    ))]
1916    {
1917        use ext::ArgumentResolver;
1918        use path::parameter::Parameter;
1919        let path_args = resolved_path.as_mut().map(|path| mem::take(&mut path.args));
1920        let body = resolved_methods
1921            .as_mut()
1922            .map(|path| mem::take(&mut path.body))
1923            .unwrap_or_default();
1924
1925        let (arguments, into_params_types, body) =
1926            match PathOperations::resolve_arguments(&ast_fn.sig.inputs, path_args, body) {
1927                Ok(args) => args,
1928                Err(diagnostics) => return diagnostics.into_token_stream().into(),
1929            };
1930
1931        let parameters = arguments
1932            .into_iter()
1933            .flatten()
1934            .map(Parameter::from)
1935            .chain(into_params_types.into_iter().flatten().map(Parameter::from));
1936        path_attribute.update_parameters_ext(parameters);
1937
1938        path_attribute.update_request_body(body);
1939    }
1940
1941    let path = Path::new(path_attribute, &ast_fn.sig.ident)
1942        .ext_methods(resolved_methods.map(|operation| operation.methods))
1943        .path(resolved_path.map(|path| path.path))
1944        .doc_comments(CommentAttributes::from_attributes(&ast_fn.attrs).0)
1945        .deprecated(ast_fn.attrs.has_deprecated());
1946
1947    let handler = path::handler::Handler {
1948        path,
1949        handler_fn: &ast_fn,
1950    };
1951    handler.to_token_stream().into()
1952}
1953
1954#[proc_macro_derive(OpenApi, attributes(openapi))]
1955/// Generate OpenApi base object with defaults from
1956/// project settings.
1957///
1958/// This is `#[derive]` implementation for [`OpenApi`][openapi] trait. The macro accepts one `openapi` argument.
1959///
1960/// # OpenApi `#[openapi(...)]` attributes
1961///
1962/// * `paths(...)`  List of method references having attribute [`#[fastapi::path]`][path] macro.
1963/// * `components(schemas(...), responses(...))` Takes available _`component`_ configurations. Currently only
1964///    _`schema`_ and _`response`_ components are supported.
1965///    * `schemas(...)` List of [`ToSchema`][to_schema]s in OpenAPI schema.
1966///    * `responses(...)` List of types that implement [`ToResponse`][to_response_trait].
1967/// * `modifiers(...)` List of items implementing [`Modify`][modify] trait for runtime OpenApi modification.
1968///   See the [trait documentation][modify] for more details.
1969/// * `security(...)` List of [`SecurityRequirement`][security]s global to all operations.
1970///   See more details in [`#[fastapi::path(...)]`][path] [attribute macro security options][path_security].
1971/// * `tags(...)` List of [`Tag`][tags]s which must match the tag _**path operation**_.  Tags can be used to
1972///   define extra information for the API to produce richer documentation. See [tags attribute syntax][tags_syntax].
1973/// * `external_docs(...)` Can be used to reference external resource to the OpenAPI doc for extended documentation.
1974///   External docs can be in [`OpenApi`][openapi_struct] or in [`Tag`][tags] level.
1975/// * `servers(...)` Define [`servers`][servers] as derive argument to the _`OpenApi`_. Servers
1976///   are completely optional and thus can be omitted from the declaration. See [servers attribute
1977///   syntax][servers_syntax]
1978/// * `info(...)` Declare [`Info`][info] attribute values used to override the default values
1979///   generated from Cargo environment variables. **Note!** Defined attributes will override the
1980///   whole attribute from generated values of Cargo environment variables. E.g. defining
1981///   `contact(name = ...)` will ultimately override whole contact of info and not just partially
1982///   the name. See [info attribute syntax][info_syntax]
1983/// * `nest(...)` Allows nesting [`OpenApi`][openapi_struct]s to this _`OpenApi`_ instance. Nest
1984///   takes comma separated list of tuples of nested `OpenApi`s. _`OpenApi`_ instance must
1985///   implement [`OpenApi`][openapi] trait. Nesting allows defining one `OpenApi` per defined path.
1986///   If more instances is defined only latest one will be rentained.
1987///   See the _[nest(...) attribute syntax below]( #nest-attribute-syntax )_
1988///
1989///
1990/// OpenApi derive macro will also derive [`Info`][info] for OpenApi specification using Cargo
1991/// environment variables.
1992///
1993/// * env `CARGO_PKG_NAME` map to info `title`
1994/// * env `CARGO_PKG_VERSION` map to info `version`
1995/// * env `CARGO_PKG_DESCRIPTION` map info `description`
1996/// * env `CARGO_PKG_AUTHORS` map to contact `name` and `email` **only first author will be used**
1997/// * env `CARGO_PKG_LICENSE` map to info `license`
1998///
1999/// # `info(...)` attribute syntax
2000///
2001/// * `title = ...` Define title of the API. It can be [`str`] or an
2002///   expression such as [`include_str!`][include_str] or static [`const`][const] reference.
2003/// * `terms_of_service = ...` Define URL to the Terms of Service for the API. It can be [`str`] or an
2004///   expression such as [`include_str!`][include_str] or static [`const`][const] reference. Value
2005///   must be valid URL.
2006/// * `description = ...` Define description of the API. Markdown can be used for rich text
2007///   representation. It can be [`str`] or an expression such as [`include_str!`][include_str] or static
2008///   [`const`][const] reference.
2009/// * `version = ...` Override default version from _`Cargo.toml`_. Value can be [`str`] or an
2010///   expression such as [`include_str!`][include_str] or static [`const`][const] reference.
2011/// * `contact(...)` Used to override the whole contact generated from environment variables.
2012///     * `name = ...` Define identifying name of contact person / organization. It Can be a literal string.
2013///     * `email = ...` Define email address of the contact person / organization. It can be a literal string.
2014///     * `url = ...` Define URL pointing to the contact information. It must be in URL formatted string.
2015/// * `license(...)` Used to override the whole license generated from environment variables.
2016///     * `name = ...` License name of the API. It can be a literal string.
2017///     * `url = ...` Define optional URL of the license. It must be URL formatted string.
2018///
2019/// # `tags(...)` attribute syntax
2020///
2021/// * `name = ...` Must be provided, can be [`str`] or an expression such as [`include_str!`][include_str]
2022///   or static [`const`][const] reference.
2023/// * `description = ...` Optional description for the tag. Can be either or static [`str`]
2024///   or an expression e.g. _`include_str!(...)`_ macro call or reference to static [`const`][const].
2025/// * `external_docs(...)` Optional links to external documents.
2026///      * `url = ...` Mandatory URL for external documentation.
2027///      * `description = ...` Optional description for the _`url`_ link.
2028///
2029/// # `servers(...)` attribute syntax
2030///
2031/// * `url = ...` Define the url for server. It can be literal string.
2032/// * `description = ...` Define description for the server. It can be literal string.
2033/// * `variables(...)` Can be used to define variables for the url.
2034///     * `name = ...` Is the first argument within parentheses. It must be literal string.
2035///     * `default = ...` Defines a default value for the variable if nothing else will be
2036///       provided. If _`enum_values`_ is defined the _`default`_ must be found within the enum
2037///       options. It can be a literal string.
2038///     * `description = ...` Define the description for the variable. It can be a literal string.
2039///     * `enum_values(...)` Define list of possible values for the variable. Values must be
2040///       literal strings.
2041///
2042/// _**Example server variable definition.**_
2043/// ```text
2044/// ("username" = (default = "demo", description = "Default username for API")),
2045/// ("port" = (enum_values("8080", "5000", "4545")))
2046/// ```
2047///
2048/// # `nest(...)` attribute syntax
2049///
2050/// * `path = ...` Define mandatory path for nesting the [`OpenApi`][openapi_struct].
2051/// * `api = ...` Define mandatory path to struct that implements [`OpenApi`][openapi] trait.
2052///    The fully qualified path (_`path::to`_) will become the default _`tag`_ for the nested
2053///    `OpenApi` endpoints if provided.
2054/// * `tags = [...]` Define optional tags what are appended to the existing list of tags.
2055///
2056///  _**Example of nest definition**_
2057///  ```text
2058///  (path = "path/to/nest", api = path::to::NestableApi),
2059///  (path = "path/to/nest", api = path::to::NestableApi, tags = ["nestableapi", ...])
2060///  ```
2061///
2062/// # Examples
2063///
2064/// _**Define OpenApi schema with some paths and components.**_
2065/// ```rust
2066/// # use fastapi::{OpenApi, ToSchema};
2067/// #
2068/// #[derive(ToSchema)]
2069/// struct Pet {
2070///     name: String,
2071///     age: i32,
2072/// }
2073///
2074/// #[derive(ToSchema)]
2075/// enum Status {
2076///     Active, InActive, Locked,
2077/// }
2078///
2079/// #[fastapi::path(get, path = "/pet")]
2080/// fn get_pet() -> Pet {
2081///     Pet {
2082///         name: "bob".to_string(),
2083///         age: 8,
2084///     }
2085/// }
2086///
2087/// #[fastapi::path(get, path = "/status")]
2088/// fn get_status() -> Status {
2089///     Status::Active
2090/// }
2091///
2092/// #[derive(OpenApi)]
2093/// #[openapi(
2094///     paths(get_pet, get_status),
2095///     components(schemas(Pet, Status)),
2096///     security(
2097///         (),
2098///         ("my_auth" = ["read:items", "edit:items"]),
2099///         ("token_jwt" = [])
2100///     ),
2101///     tags(
2102///         (name = "pets::api", description = "All about pets",
2103///             external_docs(url = "http://more.about.pets.api", description = "Find out more"))
2104///     ),
2105///     external_docs(url = "http://more.about.our.apis", description = "More about our APIs")
2106/// )]
2107/// struct ApiDoc;
2108/// ```
2109///
2110/// _**Define servers to OpenApi.**_
2111/// ```rust
2112/// # use fastapi::OpenApi;
2113/// #[derive(OpenApi)]
2114/// #[openapi(
2115///     servers(
2116///         (url = "http://localhost:8989", description = "Local server"),
2117///         (url = "http://api.{username}:{port}", description = "Remote API",
2118///             variables(
2119///                 ("username" = (default = "demo", description = "Default username for API")),
2120///                 ("port" = (default = "8080", enum_values("8080", "5000", "3030"), description = "Supported ports for API"))
2121///             )
2122///         )
2123///     )
2124/// )]
2125/// struct ApiDoc;
2126/// ```
2127///
2128/// _**Define info attribute values used to override auto generated ones from Cargo environment
2129/// variables.**_
2130/// ```compile_fail
2131/// # use fastapi::OpenApi;
2132/// #[derive(OpenApi)]
2133/// #[openapi(info(
2134///     title = "title override",
2135///     description = include_str!("./path/to/content"), // fail compile cause no such file
2136///     contact(name = "Test")
2137/// ))]
2138/// struct ApiDoc;
2139/// ```
2140///
2141/// _**Create OpenAPI with reusable response.**_
2142/// ```rust
2143/// #[derive(fastapi::ToSchema)]
2144/// struct Person {
2145///     name: String,
2146/// }
2147///
2148/// /// Person list response
2149/// #[derive(fastapi::ToResponse)]
2150/// struct PersonList(Vec<Person>);
2151///
2152/// #[fastapi::path(
2153///     get,
2154///     path = "/person-list",
2155///     responses(
2156///         (status = 200, response = PersonList)
2157///     )
2158/// )]
2159/// fn get_persons() -> Vec<Person> {
2160///     vec![]
2161/// }
2162///
2163/// #[derive(fastapi::OpenApi)]
2164/// #[openapi(
2165///     components(
2166///         schemas(Person),
2167///         responses(PersonList)
2168///     )
2169/// )]
2170/// struct ApiDoc;
2171/// ```
2172///
2173/// _**Nest _`UserApi`_ to the current api doc instance.**_
2174/// ```rust
2175/// # use fastapi::OpenApi;
2176/// #
2177///  #[fastapi::path(get, path = "/api/v1/status")]
2178///  fn test_path_status() {}
2179///
2180///  #[fastapi::path(get, path = "/test")]
2181///  fn user_test_path() {}
2182///
2183///  #[derive(OpenApi)]
2184///  #[openapi(paths(user_test_path))]
2185///  struct UserApi;
2186///
2187///  #[derive(OpenApi)]
2188///  #[openapi(
2189///      paths(
2190///          test_path_status
2191///      ),
2192///      nest(
2193///          (path = "/api/v1/user", api = UserApi),
2194///      )
2195///  )]
2196///  struct ApiDoc;
2197/// ```
2198///
2199/// [openapi]: trait.OpenApi.html
2200/// [openapi_struct]: openapi/struct.OpenApi.html
2201/// [to_schema]: derive.ToSchema.html
2202/// [path]: attr.path.html
2203/// [modify]: trait.Modify.html
2204/// [info]: openapi/info/struct.Info.html
2205/// [security]: openapi/security/struct.SecurityRequirement.html
2206/// [path_security]: attr.path.html#security-requirement-attributes
2207/// [tags]: openapi/tag/struct.Tag.html
2208/// [to_response_trait]: trait.ToResponse.html
2209/// [servers]: openapi/server/index.html
2210/// [const]: https://doc.rust-lang.org/std/keyword.const.html
2211/// [tags_syntax]: #tags-attribute-syntax
2212/// [info_syntax]: #info-attribute-syntax
2213/// [servers_syntax]: #servers-attribute-syntax
2214/// [include_str]: https://doc.rust-lang.org/std/macro.include_str.html
2215pub fn openapi(input: TokenStream) -> TokenStream {
2216    let DeriveInput { attrs, ident, .. } = syn::parse_macro_input!(input);
2217
2218    parse_openapi_attrs(&attrs)
2219        .map(|openapi_attr| OpenApi(openapi_attr, ident).to_token_stream())
2220        .map_or_else(syn::Error::into_compile_error, ToTokens::into_token_stream)
2221        .into()
2222}
2223
2224#[proc_macro_derive(IntoParams, attributes(param, into_params))]
2225/// Generate [path parameters][path_params] from struct's
2226/// fields.
2227///
2228/// This is `#[derive]` implementation for [`IntoParams`][into_params] trait.
2229///
2230/// Typically path parameters need to be defined within [`#[fastapi::path(...params(...))]`][path_params] section
2231/// for the endpoint. But this trait eliminates the need for that when [`struct`][struct]s are used to define parameters.
2232/// Still [`std::primitive`] and [`String`] path parameters or [`tuple`] style path parameters need to be defined
2233/// within `params(...)` section if description or other than default configuration need to be given.
2234///
2235/// You can use the Rust's own `#[deprecated]` attribute on field to mark it as
2236/// deprecated and it will reflect to the generated OpenAPI spec.
2237///
2238/// `#[deprecated]` attribute supports adding additional details such as a reason and or since version
2239/// but this is is not supported in OpenAPI. OpenAPI has only a boolean flag to determine deprecation.
2240/// While it is totally okay to declare deprecated with reason
2241/// `#[deprecated  = "There is better way to do this"]` the reason would not render in OpenAPI spec.
2242///
2243/// Doc comment on struct fields will be used as description for the generated parameters.
2244/// ```rust
2245/// #[derive(fastapi::IntoParams)]
2246/// struct Query {
2247///     /// Query todo items by name.
2248///     name: String
2249/// }
2250/// ```
2251///
2252/// # IntoParams Container Attributes for `#[into_params(...)]`
2253///
2254/// The following attributes are available for use in on the container attribute `#[into_params(...)]` for the struct
2255/// deriving `IntoParams`:
2256///
2257/// * `names(...)` Define comma separated list of names for unnamed fields of struct used as a path parameter.
2258///    __Only__ supported on __unnamed structs__.
2259/// * `style = ...` Defines how all parameters are serialized by [`ParameterStyle`][style]. Default
2260///    values are based on _`parameter_in`_ attribute.
2261/// * `parameter_in = ...` =  Defines where the parameters of this field are used with a value from
2262///    [`openapi::path::ParameterIn`][in_enum]. There is no default value, if this attribute is not
2263///    supplied, then the value is determined by the `parameter_in_provider` in
2264///    [`IntoParams::into_params()`](trait.IntoParams.html#tymethod.into_params).
2265/// * `rename_all = ...` Can be provided to alternatively to the serde's `rename_all` attribute. Effectively provides same functionality.
2266///
2267/// Use `names` to define name for single unnamed argument.
2268/// ```rust
2269/// # use fastapi::IntoParams;
2270/// #
2271/// #[derive(IntoParams)]
2272/// #[into_params(names("id"))]
2273/// struct Id(u64);
2274/// ```
2275///
2276/// Use `names` to define names for multiple unnamed arguments.
2277/// ```rust
2278/// # use fastapi::IntoParams;
2279/// #
2280/// #[derive(IntoParams)]
2281/// #[into_params(names("id", "name"))]
2282/// struct IdAndName(u64, String);
2283/// ```
2284///
2285/// # IntoParams Field Attributes for `#[param(...)]`
2286///
2287/// The following attributes are available for use in the `#[param(...)]` on struct fields:
2288///
2289/// * `style = ...` Defines how the parameter is serialized by [`ParameterStyle`][style]. Default values are based on _`parameter_in`_ attribute.
2290///
2291/// * `explode` Defines whether new _`parameter=value`_ pair is created for each parameter within _`object`_ or _`array`_.
2292///
2293/// * `allow_reserved` Defines whether reserved characters _`:/?#[]@!$&'()*+,;=`_ is allowed within value.
2294///
2295/// * `example = ...` Can be method reference or _`json!(...)`_. Given example
2296///   will override any example in underlying parameter type.
2297///
2298/// * `value_type = ...` Can be used to override default type derived from type of the field used in OpenAPI spec.
2299///   This is useful in cases where the default type does not correspond to the actual type e.g. when
2300///   any third-party types are used which are not [`ToSchema`][to_schema]s nor [`primitive` types][primitive].
2301///   The value can be any Rust type what normally could be used to serialize to JSON, or either virtual type _`Object`_
2302///   or _`Value`_.
2303///   _`Object`_ will be rendered as generic OpenAPI object _(`type: object`)_.
2304///   _`Value`_ will be rendered as any OpenAPI value (i.e. no `type` restriction).
2305///
2306/// * `inline` If set, the schema for this field's type needs to be a [`ToSchema`][to_schema], and
2307///   the schema definition will be inlined.
2308///
2309/// * `default = ...` Can be method reference or _`json!(...)`_.
2310///
2311/// * `format = ...` May either be variant of the [`KnownFormat`][known_format] enum, or otherwise
2312///   an open value as a string. By default the format is derived from the type of the property
2313///   according OpenApi spec.
2314///
2315/// * `write_only` Defines property is only used in **write** operations *POST,PUT,PATCH* but not in *GET*.
2316///
2317/// * `read_only` Defines property is only used in **read** operations *GET* but not in *POST,PUT,PATCH*.
2318///
2319/// * `xml(...)` Can be used to define [`Xml`][xml] object properties applicable to named fields.
2320///    See configuration options at xml attributes of [`ToSchema`][to_schema_xml]
2321///
2322/// * `nullable` Defines property is nullable (note this is different to non-required).
2323///
2324/// * `required = ...` Can be used to enforce required status for the parameter. [See
2325///    rules][derive@IntoParams#field-nullability-and-required-rules]
2326///
2327/// * `rename = ...` Can be provided to alternatively to the serde's `rename` attribute. Effectively provides same functionality.
2328///
2329/// * `multiple_of = ...` Can be used to define multiplier for a value. Value is considered valid
2330///   division will result an `integer`. Value must be strictly above _`0`_.
2331///
2332/// * `maximum = ...` Can be used to define inclusive upper bound to a `number` value.
2333///
2334/// * `minimum = ...` Can be used to define inclusive lower bound to a `number` value.
2335///
2336/// * `exclusive_maximum = ...` Can be used to define exclusive upper bound to a `number` value.
2337///
2338/// * `exclusive_minimum = ...` Can be used to define exclusive lower bound to a `number` value.
2339///
2340/// * `max_length = ...` Can be used to define maximum length for `string` types.
2341///
2342/// * `min_length = ...` Can be used to define minimum length for `string` types.
2343///
2344/// * `pattern = ...` Can be used to define valid regular expression in _ECMA-262_ dialect the field value must match.
2345///
2346/// * `max_items = ...` Can be used to define maximum items allowed for `array` fields. Value must
2347///   be non-negative integer.
2348///
2349/// * `min_items = ...` Can be used to define minimum items allowed for `array` fields. Value must
2350///   be non-negative integer.
2351///
2352/// * `schema_with = ...` Use _`schema`_ created by provided function reference instead of the
2353///   default derived _`schema`_. The function must match to `fn() -> Into<RefOr<Schema>>`. It does
2354///   not accept arguments and must return anything that can be converted into `RefOr<Schema>`.
2355///
2356/// * `additional_properties = ...` Can be used to define free form types for maps such as
2357///   [`HashMap`](std::collections::HashMap) and [`BTreeMap`](std::collections::BTreeMap).
2358///   Free form type enables use of arbitrary types within map values.
2359///   Supports formats _`additional_properties`_ and _`additional_properties = true`_.
2360///
2361/// * `ignore` or `ignore = ...` Can be used to skip the field from being serialized to OpenAPI schema. It accepts either a literal `bool` value
2362///   or a path to a function that returns `bool` (`Fn() -> bool`).
2363///
2364/// #### Field nullability and required rules
2365///
2366/// Same rules for nullability and required status apply for _`IntoParams`_ field attributes as for
2367/// _`ToSchema`_ field attributes. [See the rules][`derive@ToSchema#field-nullability-and-required-rules`].
2368///
2369/// # Partial `#[serde(...)]` attributes support
2370///
2371/// IntoParams derive has partial support for [serde attributes]. These supported attributes will reflect to the
2372/// generated OpenAPI doc. The following attributes are currently supported:
2373///
2374/// * `rename_all = "..."` Supported at the container level.
2375/// * `rename = "..."` Supported **only** at the field level.
2376/// * `default` Supported at the container level and field level according to [serde attributes].
2377/// * `skip_serializing_if = "..."` Supported  **only** at the field level.
2378/// * `with = ...` Supported **only** at field level.
2379/// * `skip_serializing = "..."` Supported  **only** at the field or variant level.
2380/// * `skip_deserializing = "..."` Supported  **only** at the field or variant level.
2381/// * `skip = "..."` Supported  **only** at the field level.
2382///
2383/// Other _`serde`_ attributes will impact the serialization but will not be reflected on the generated OpenAPI doc.
2384///
2385/// # Examples
2386///
2387/// _**Demonstrate [`IntoParams`][into_params] usage with resolving `Path` and `Query` parameters
2388/// with _`actix-web`_**_.
2389/// ```rust
2390/// use actix_web::{get, HttpResponse, Responder};
2391/// use actix_web::web::{Path, Query};
2392/// use serde::Deserialize;
2393/// use serde_json::json;
2394/// use fastapi::IntoParams;
2395///
2396/// #[derive(Deserialize, IntoParams)]
2397/// struct PetPathArgs {
2398///     /// Id of pet
2399///     id: i64,
2400///     /// Name of pet
2401///     name: String,
2402/// }
2403///
2404/// #[derive(Deserialize, IntoParams)]
2405/// struct Filter {
2406///     /// Age filter for pets
2407///     #[deprecated]
2408///     #[param(style = Form, explode, allow_reserved, example = json!([10]))]
2409///     age: Option<Vec<i32>>,
2410/// }
2411///
2412/// #[fastapi::path(
2413///     params(PetPathArgs, Filter),
2414///     responses(
2415///         (status = 200, description = "success response")
2416///     )
2417/// )]
2418/// #[get("/pet/{id}/{name}")]
2419/// async fn get_pet(pet: Path<PetPathArgs>, query: Query<Filter>) -> impl Responder {
2420///     HttpResponse::Ok().json(json!({ "id": pet.id }))
2421/// }
2422/// ```
2423///
2424/// _**Demonstrate [`IntoParams`][into_params] usage with the `#[into_params(...)]` container attribute to
2425/// be used as a path query, and inlining a schema query field:**_
2426/// ```rust
2427/// use serde::Deserialize;
2428/// use fastapi::{IntoParams, ToSchema};
2429///
2430/// #[derive(Deserialize, ToSchema)]
2431/// #[serde(rename_all = "snake_case")]
2432/// enum PetKind {
2433///     Dog,
2434///     Cat,
2435/// }
2436///
2437/// #[derive(Deserialize, IntoParams)]
2438/// #[into_params(style = Form, parameter_in = Query)]
2439/// struct PetQuery {
2440///     /// Name of pet
2441///     name: Option<String>,
2442///     /// Age of pet
2443///     age: Option<i32>,
2444///     /// Kind of pet
2445///     #[param(inline)]
2446///     kind: PetKind
2447/// }
2448///
2449/// #[fastapi::path(
2450///     get,
2451///     path = "/get_pet",
2452///     params(PetQuery),
2453///     responses(
2454///         (status = 200, description = "success response")
2455///     )
2456/// )]
2457/// async fn get_pet(query: PetQuery) {
2458///     // ...
2459/// }
2460/// ```
2461///
2462/// _**Override `String` with `i64` using `value_type` attribute.**_
2463/// ```rust
2464/// # use fastapi::IntoParams;
2465/// #
2466/// #[derive(IntoParams)]
2467/// #[into_params(parameter_in = Query)]
2468/// struct Filter {
2469///     #[param(value_type = i64)]
2470///     id: String,
2471/// }
2472/// ```
2473///
2474/// _**Override `String` with `Object` using `value_type` attribute. _`Object`_ will render as `type: object` in OpenAPI spec.**_
2475/// ```rust
2476/// # use fastapi::IntoParams;
2477/// #
2478/// #[derive(IntoParams)]
2479/// #[into_params(parameter_in = Query)]
2480/// struct Filter {
2481///     #[param(value_type = Object)]
2482///     id: String,
2483/// }
2484/// ```
2485///
2486/// _**You can use a generic type to override the default type of the field.**_
2487/// ```rust
2488/// # use fastapi::IntoParams;
2489/// #
2490/// #[derive(IntoParams)]
2491/// #[into_params(parameter_in = Query)]
2492/// struct Filter {
2493///     #[param(value_type = Option<String>)]
2494///     id: String
2495/// }
2496/// ```
2497///
2498/// _**You can even override a [`Vec`] with another one.**_
2499/// ```rust
2500/// # use fastapi::IntoParams;
2501/// #
2502/// #[derive(IntoParams)]
2503/// #[into_params(parameter_in = Query)]
2504/// struct Filter {
2505///     #[param(value_type = Vec<i32>)]
2506///     id: Vec<String>
2507/// }
2508/// ```
2509///
2510/// _**We can override value with another [`ToSchema`][to_schema].**_
2511/// ```rust
2512/// # use fastapi::{IntoParams, ToSchema};
2513/// #
2514/// #[derive(ToSchema)]
2515/// struct Id {
2516///     value: i64,
2517/// }
2518///
2519/// #[derive(IntoParams)]
2520/// #[into_params(parameter_in = Query)]
2521/// struct Filter {
2522///     #[param(value_type = Id)]
2523///     id: String
2524/// }
2525/// ```
2526///
2527/// _**Example with validation attributes.**_
2528/// ```rust
2529/// #[derive(fastapi::IntoParams)]
2530/// struct Item {
2531///     #[param(maximum = 10, minimum = 5, multiple_of = 2.5)]
2532///     id: i32,
2533///     #[param(max_length = 10, min_length = 5, pattern = "[a-z]*")]
2534///     value: String,
2535///     #[param(max_items = 5, min_items = 1)]
2536///     items: Vec<String>,
2537/// }
2538/// ````
2539///
2540/// _**Use `schema_with` to manually implement schema for a field.**_
2541/// ```rust
2542/// # use fastapi::openapi::schema::{Object, ObjectBuilder};
2543/// fn custom_type() -> Object {
2544///     ObjectBuilder::new()
2545///         .schema_type(fastapi::openapi::schema::Type::String)
2546///         .format(Some(fastapi::openapi::SchemaFormat::Custom(
2547///             "email".to_string(),
2548///         )))
2549///         .description(Some("this is the description"))
2550///         .build()
2551/// }
2552///
2553/// #[derive(fastapi::IntoParams)]
2554/// #[into_params(parameter_in = Query)]
2555/// struct Query {
2556///     #[param(schema_with = custom_type)]
2557///     email: String,
2558/// }
2559/// ```
2560///
2561/// [to_schema]: trait.ToSchema.html
2562/// [known_format]: openapi/schema/enum.KnownFormat.html
2563/// [xml]: openapi/xml/struct.Xml.html
2564/// [into_params]: trait.IntoParams.html
2565/// [path_params]: attr.path.html#params-attributes
2566/// [struct]: https://doc.rust-lang.org/std/keyword.struct.html
2567/// [style]: openapi/path/enum.ParameterStyle.html
2568/// [in_enum]: openapi/path/enum.ParameterIn.html
2569/// [primitive]: https://doc.rust-lang.org/std/primitive/index.html
2570/// [serde attributes]: https://serde.rs/attributes.html
2571/// [to_schema_xml]: macro@ToSchema#xml-attribute-configuration-options
2572pub fn into_params(input: TokenStream) -> TokenStream {
2573    let DeriveInput {
2574        attrs,
2575        ident,
2576        generics,
2577        data,
2578        ..
2579    } = syn::parse_macro_input!(input);
2580
2581    let into_params = IntoParams {
2582        attrs,
2583        generics,
2584        data,
2585        ident,
2586    };
2587
2588    into_params.to_token_stream().into()
2589}
2590
2591#[proc_macro_derive(ToResponse, attributes(response, content, to_schema))]
2592/// Generate reusable OpenAPI response that can be used
2593/// in [`fastapi::path`][path] or in [`OpenApi`][openapi].
2594///
2595/// This is `#[derive]` implementation for [`ToResponse`][to_response] trait.
2596///
2597///
2598/// _`#[response]`_ attribute can be used to alter and add [response attributes](#toresponse-response-attributes).
2599///
2600/// _`#[content]`_ attributes is used to make enum variant a content of a specific type for the
2601/// response.
2602///
2603/// _`#[to_schema]`_ attribute is used to inline a schema for a response in unnamed structs or
2604/// enum variants with `#[content]` attribute. **Note!** [`ToSchema`] need to be implemented for
2605/// the field or variant type.
2606///
2607/// Type derived with _`ToResponse`_ uses provided doc comment as a description for the response. It
2608/// can alternatively be overridden with _`description = ...`_ attribute.
2609///
2610/// _`ToResponse`_ can be used in four different ways to generate OpenAPI response component.
2611///
2612/// 1. By decorating `struct` or `enum` with [`derive@ToResponse`] derive macro. This will create a
2613///    response with inlined schema resolved from the fields of the `struct` or `variants` of the
2614///    enum.
2615///
2616///    ```rust
2617///     # use fastapi::ToResponse;
2618///     #[derive(ToResponse)]
2619///     #[response(description = "Person response returns single Person entity")]
2620///     struct Person {
2621///         name: String,
2622///     }
2623///    ```
2624///
2625/// 2. By decorating unnamed field `struct` with [`derive@ToResponse`] derive macro. Unnamed field struct
2626///    allows users to use new type pattern to define one inner field which is used as a schema for
2627///    the generated response. This allows users to define `Vec` and `Option` response types.
2628///    Additionally these types can also be used with `#[to_schema]` attribute to inline the
2629///    field's type schema if it implements [`ToSchema`] derive macro.
2630///
2631///    ```rust
2632///     # #[derive(fastapi::ToSchema)]
2633///     # struct Person {
2634///     #     name: String,
2635///     # }
2636///     /// Person list response
2637///     #[derive(fastapi::ToResponse)]
2638///     struct PersonList(Vec<Person>);
2639///    ```
2640///
2641/// 3. By decorating unit struct with [`derive@ToResponse`] derive macro. Unit structs will produce a
2642///    response without body.
2643///
2644///    ```rust
2645///     /// Success response which does not have body.
2646///     #[derive(fastapi::ToResponse)]
2647///     struct SuccessResponse;
2648///    ```
2649///
2650/// 4. By decorating `enum` with variants having `#[content(...)]` attribute. This allows users to
2651///    define multiple response content schemas to single response according to OpenAPI spec.
2652///    **Note!** Enum with _`content`_ attribute in variants cannot have enum level _`example`_ or
2653///    _`examples`_ defined. Instead examples need to be defined per variant basis. Additionally
2654///    these variants can also be used with `#[to_schema]` attribute to inline the variant's type schema
2655///    if it implements [`ToSchema`] derive macro.
2656///
2657///    ```rust
2658///     #[derive(fastapi::ToSchema)]
2659///     struct Admin {
2660///         name: String,
2661///     }
2662///     #[derive(fastapi::ToSchema)]
2663///     struct Admin2 {
2664///         name: String,
2665///         id: i32,
2666///     }
2667///
2668///     #[derive(fastapi::ToResponse)]
2669///     enum Person {
2670///         #[response(examples(
2671///             ("Person1" = (value = json!({"name": "name1"}))),
2672///             ("Person2" = (value = json!({"name": "name2"})))
2673///         ))]
2674///         Admin(#[content("application/vnd-custom-v1+json")] Admin),
2675///
2676///         #[response(example = json!({"name": "name3", "id": 1}))]
2677///         Admin2(#[content("application/vnd-custom-v2+json")] #[to_schema] Admin2),
2678///     }
2679///    ```
2680///
2681/// # ToResponse `#[response(...)]` attributes
2682///
2683/// * `description = "..."` Define description for the response as str. This can be used to
2684///   override the default description resolved from doc comments if present.
2685///
2686/// * `content_type = "..."` Can be used to override the default behavior
2687///   of auto resolving the content type from the `body` attribute. If defined the value should be valid
2688///   content type such as _`application/json`_ . By default the content type is _`text/plain`_
2689///   for [primitive Rust types][primitive], `application/octet-stream` for _`[u8]`_ and _`application/json`_
2690///   for struct and mixed enum types.
2691///
2692/// * `headers(...)` Slice of response headers that are returned back to a caller.
2693///
2694/// * `example = ...` Can be _`json!(...)`_. _`json!(...)`_ should be something that
2695///   _`serde_json::json!`_ can parse as a _`serde_json::Value`_.
2696///
2697/// * `examples(...)` Define multiple examples for single response. This attribute is mutually
2698///   exclusive to the _`example`_ attribute and if both are defined this will override the _`example`_.
2699///     * `name = ...` This is first attribute and value must be literal string.
2700///     * `summary = ...` Short description of example. Value must be literal string.
2701///     * `description = ...` Long description of example. Attribute supports markdown for rich text
2702///       representation. Value must be literal string.
2703///     * `value = ...` Example value. It must be _`json!(...)`_. _`json!(...)`_ should be something that
2704///       _`serde_json::json!`_ can parse as a _`serde_json::Value`_.
2705///     * `external_value = ...` Define URI to literal example value. This is mutually exclusive to
2706///       the _`value`_ attribute. Value must be literal string.
2707///
2708///      _**Example of example definition.**_
2709///     ```text
2710///      ("John" = (summary = "This is John", value = json!({"name": "John"})))
2711///     ```
2712///
2713/// # Examples
2714///
2715/// _**Use reusable response in operation handler.**_
2716/// ```rust
2717/// #[derive(fastapi::ToResponse)]
2718/// struct PersonResponse {
2719///    value: String
2720/// }
2721///
2722/// #[derive(fastapi::OpenApi)]
2723/// #[openapi(components(responses(PersonResponse)))]
2724/// struct Doc;
2725///
2726/// #[fastapi::path(
2727///     get,
2728///     path = "/api/person",
2729///     responses(
2730///         (status = 200, response = PersonResponse)
2731///     )
2732/// )]
2733/// fn get_person() -> PersonResponse {
2734///     PersonResponse { value: "person".to_string() }
2735/// }
2736/// ```
2737///
2738/// _**Create a response from named struct.**_
2739/// ```rust
2740///  /// This is description
2741///  ///
2742///  /// It will also be used in `ToSchema` if present
2743///  #[derive(fastapi::ToSchema, fastapi::ToResponse)]
2744///  #[response(
2745///      description = "Override description for response",
2746///      content_type = "text/xml"
2747///  )]
2748///  #[response(
2749///      example = json!({"name": "the name"}),
2750///      headers(
2751///          ("csrf-token", description = "response csrf token"),
2752///          ("random-id" = i32)
2753///      )
2754///  )]
2755///  struct Person {
2756///      name: String,
2757///  }
2758/// ```
2759///
2760/// _**Create inlined person list response.**_
2761/// ```rust
2762///  # #[derive(fastapi::ToSchema)]
2763///  # struct Person {
2764///  #     name: String,
2765///  # }
2766///  /// Person list response
2767///  #[derive(fastapi::ToResponse)]
2768///  struct PersonList(#[to_schema] Vec<Person>);
2769/// ```
2770///
2771/// _**Create enum response from variants.**_
2772/// ```rust
2773///  #[derive(fastapi::ToResponse)]
2774///  enum PersonType {
2775///      Value(String),
2776///      Foobar,
2777///  }
2778/// ```
2779///
2780/// [to_response]: trait.ToResponse.html
2781/// [primitive]: https://doc.rust-lang.org/std/primitive/index.html
2782/// [path]: attr.path.html
2783/// [openapi]: derive.OpenApi.html
2784pub fn to_response(input: TokenStream) -> TokenStream {
2785    let DeriveInput {
2786        attrs,
2787        ident,
2788        generics,
2789        data,
2790        ..
2791    } = syn::parse_macro_input!(input);
2792
2793    ToResponse::new(attrs, &data, generics, ident)
2794        .as_ref()
2795        .map_or_else(Diagnostics::to_token_stream, ToResponse::to_token_stream)
2796        .into()
2797}
2798
2799#[proc_macro_derive(
2800    IntoResponses,
2801    attributes(response, to_schema, ref_response, to_response)
2802)]
2803/// Generate responses with status codes what
2804/// can be attached to the [`fastapi::path`][path_into_responses].
2805///
2806/// This is `#[derive]` implementation of [`IntoResponses`][into_responses] trait. [`derive@IntoResponses`]
2807/// can be used to decorate _`structs`_ and _`enums`_ to generate response maps that can be used in
2808/// [`fastapi::path`][path_into_responses]. If _`struct`_ is decorated with [`derive@IntoResponses`] it will be
2809/// used to create a map of responses containing single response. Decorating _`enum`_ with
2810/// [`derive@IntoResponses`] will create a map of responses with a response for each variant of the _`enum`_.
2811///
2812/// Named field _`struct`_ decorated with [`derive@IntoResponses`] will create a response with inlined schema
2813/// generated from the body of the struct. This is a conveniency which allows users to directly
2814/// create responses with schemas without first creating a separate [response][to_response] type.
2815///
2816/// Unit _`struct`_ behaves similarly to then named field struct. Only difference is that it will create
2817/// a response without content since there is no inner fields.
2818///
2819/// Unnamed field _`struct`_ decorated with [`derive@IntoResponses`] will by default create a response with
2820/// referenced [schema][to_schema] if field is object or schema if type is [primitive
2821/// type][primitive]. _`#[to_schema]`_ attribute at field of unnamed _`struct`_ can be used to inline
2822/// the schema if type of the field implements [`ToSchema`][to_schema] trait. Alternatively
2823/// _`#[to_response]`_ and _`#[ref_response]`_ can be used at field to either reference a reusable
2824/// [response][to_response] or inline a reusable [response][to_response]. In both cases the field
2825/// type is expected to implement [`ToResponse`][to_response] trait.
2826///
2827///
2828/// Enum decorated with [`derive@IntoResponses`] will create a response for each variant of the _`enum`_.
2829/// Each variant must have it's own _`#[response(...)]`_ definition. Unit variant will behave same
2830/// as unit _`struct`_ by creating a response without content. Similarly named field variant and
2831/// unnamed field variant behaves the same as it was named field _`struct`_ and unnamed field
2832/// _`struct`_.
2833///
2834/// _`#[response]`_ attribute can be used at named structs, unnamed structs, unit structs and enum
2835/// variants to alter [response attributes](#intoresponses-response-attributes) of responses.
2836///
2837/// Doc comment on a _`struct`_ or _`enum`_ variant will be used as a description for the response.
2838/// It can also be overridden with _`description = "..."`_ attribute.
2839///
2840/// # IntoResponses `#[response(...)]` attributes
2841///
2842/// * `status = ...` Must be provided. Is either a valid http status code integer. E.g. _`200`_ or a
2843///   string value representing a range such as _`"4XX"`_ or `"default"` or a valid _`http::status::StatusCode`_.
2844///   _`StatusCode`_ can either be use path to the status code or _status code_ constant directly.
2845///
2846/// * `description = "..."` Define description for the response as str. This can be used to
2847///   override the default description resolved from doc comments if present.
2848///
2849/// * `content_type = "..."` Can be used to override the default behavior
2850///   of auto resolving the content type from the `body` attribute. If defined the value should be valid
2851///   content type such as _`application/json`_ . By default the content type is _`text/plain`_
2852///   for [primitive Rust types][primitive], `application/octet-stream` for _`[u8]`_ and _`application/json`_
2853///   for struct and mixed enum types.
2854///
2855/// * `headers(...)` Slice of response headers that are returned back to a caller.
2856///
2857/// * `example = ...` Can be _`json!(...)`_. _`json!(...)`_ should be something that
2858///   _`serde_json::json!`_ can parse as a _`serde_json::Value`_.
2859///
2860/// * `examples(...)` Define multiple examples for single response. This attribute is mutually
2861///   exclusive to the _`example`_ attribute and if both are defined this will override the _`example`_.
2862///     * `name = ...` This is first attribute and value must be literal string.
2863///     * `summary = ...` Short description of example. Value must be literal string.
2864///     * `description = ...` Long description of example. Attribute supports markdown for rich text
2865///       representation. Value must be literal string.
2866///     * `value = ...` Example value. It must be _`json!(...)`_. _`json!(...)`_ should be something that
2867///       _`serde_json::json!`_ can parse as a _`serde_json::Value`_.
2868///     * `external_value = ...` Define URI to literal example value. This is mutually exclusive to
2869///       the _`value`_ attribute. Value must be literal string.
2870///
2871///      _**Example of example definition.**_
2872///     ```text
2873///      ("John" = (summary = "This is John", value = json!({"name": "John"})))
2874///     ```
2875///
2876/// # Examples
2877///
2878/// _**Use `IntoResponses` to define [`fastapi::path`][path] responses.**_
2879/// ```rust
2880/// #[derive(fastapi::ToSchema)]
2881/// struct BadRequest {
2882///     message: String,
2883/// }
2884///
2885/// #[derive(fastapi::IntoResponses)]
2886/// enum UserResponses {
2887///     /// Success response
2888///     #[response(status = 200)]
2889///     Success { value: String },
2890///
2891///     #[response(status = 404)]
2892///     NotFound,
2893///
2894///     #[response(status = 400)]
2895///     BadRequest(BadRequest),
2896/// }
2897///
2898/// #[fastapi::path(
2899///     get,
2900///     path = "/api/user",
2901///     responses(
2902///         UserResponses
2903///     )
2904/// )]
2905/// fn get_user() -> UserResponses {
2906///    UserResponses::NotFound
2907/// }
2908/// ```
2909/// _**Named struct response with inlined schema.**_
2910/// ```rust
2911/// /// This is success response
2912/// #[derive(fastapi::IntoResponses)]
2913/// #[response(status = 200)]
2914/// struct SuccessResponse {
2915///     value: String,
2916/// }
2917/// ```
2918///
2919/// _**Unit struct response without content.**_
2920/// ```rust
2921/// #[derive(fastapi::IntoResponses)]
2922/// #[response(status = NOT_FOUND)]
2923/// struct NotFound;
2924/// ```
2925///
2926/// _**Unnamed struct response with inlined response schema.**_
2927/// ```rust
2928/// # #[derive(fastapi::ToSchema)]
2929/// # struct Foo;
2930/// #[derive(fastapi::IntoResponses)]
2931/// #[response(status = 201)]
2932/// struct CreatedResponse(#[to_schema] Foo);
2933/// ```
2934///
2935/// _**Enum with multiple responses.**_
2936/// ```rust
2937/// # #[derive(fastapi::ToResponse)]
2938/// # struct Response {
2939/// #     message: String,
2940/// # }
2941/// # #[derive(fastapi::ToSchema)]
2942/// # struct BadRequest {}
2943/// #[derive(fastapi::IntoResponses)]
2944/// enum UserResponses {
2945///     /// Success response description.
2946///     #[response(status = 200)]
2947///     Success { value: String },
2948///
2949///     #[response(status = 404)]
2950///     NotFound,
2951///
2952///     #[response(status = 400)]
2953///     BadRequest(BadRequest),
2954///
2955///     #[response(status = 500)]
2956///     ServerError(#[ref_response] Response),
2957///
2958///     #[response(status = 418)]
2959///     TeaPot(#[to_response] Response),
2960/// }
2961/// ```
2962///
2963/// [into_responses]: trait.IntoResponses.html
2964/// [to_schema]: trait.ToSchema.html
2965/// [to_response]: trait.ToResponse.html
2966/// [path_into_responses]: attr.path.html#responses-from-intoresponses
2967/// [primitive]: https://doc.rust-lang.org/std/primitive/index.html
2968/// [path]: macro@crate::path
2969pub fn into_responses(input: TokenStream) -> TokenStream {
2970    let DeriveInput {
2971        attrs,
2972        ident,
2973        generics,
2974        data,
2975        ..
2976    } = syn::parse_macro_input!(input);
2977
2978    let into_responses = IntoResponses {
2979        attributes: attrs,
2980        ident,
2981        generics,
2982        data,
2983    };
2984
2985    into_responses.to_token_stream().into()
2986}
2987
2988/// Create OpenAPI Schema from arbitrary type.
2989///
2990/// This macro provides a quick way to render arbitrary types as OpenAPI Schema Objects. It
2991/// supports two call formats.
2992/// 1. With type only
2993/// 2. With _`#[inline]`_ attribute to inline the referenced schemas.
2994///
2995/// By default the macro will create references `($ref)` for non primitive types like _`Pet`_.
2996/// However when used with _`#[inline]`_ the non [`primitive`][primitive] type schemas will
2997/// be inlined to the schema output.
2998///
2999/// ```rust
3000/// # use fastapi::openapi::{RefOr, schema::Schema};
3001/// # #[derive(fastapi::ToSchema)]
3002/// # struct Pet {id: i32};
3003/// let schema: RefOr<Schema> = fastapi::schema!(Vec<Pet>).into();
3004///
3005/// // with inline
3006/// let schema: RefOr<Schema> = fastapi::schema!(#[inline] Vec<Pet>).into();
3007/// ```
3008///
3009/// # Examples
3010///
3011/// _**Create vec of pets schema.**_
3012/// ```rust
3013/// # use fastapi::openapi::schema::{Schema, Array, Object, ObjectBuilder, SchemaFormat,
3014/// # KnownFormat, Type};
3015/// # use fastapi::openapi::RefOr;
3016/// #[derive(fastapi::ToSchema)]
3017/// struct Pet {
3018///     id: i32,
3019///     name: String,
3020/// }
3021///
3022/// let schema: RefOr<Schema> = fastapi::schema!(#[inline] Vec<Pet>).into();
3023/// // will output
3024/// let generated = RefOr::T(Schema::Array(
3025///     Array::new(
3026///         ObjectBuilder::new()
3027///             .property("id", ObjectBuilder::new()
3028///                 .schema_type(Type::Integer)
3029///                 .format(Some(SchemaFormat::KnownFormat(KnownFormat::Int32)))
3030///                 .build())
3031///             .required("id")
3032///             .property("name", Object::with_type(Type::String))
3033///             .required("name")
3034///     )
3035/// ));
3036/// # assert_json_diff::assert_json_eq!(serde_json::to_value(&schema).unwrap(), serde_json::to_value(&generated).unwrap());
3037/// ```
3038///
3039/// [primitive]: https://doc.rust-lang.org/std/primitive/index.html
3040#[proc_macro]
3041pub fn schema(input: TokenStream) -> TokenStream {
3042    struct Schema {
3043        inline: bool,
3044        ty: syn::Type,
3045    }
3046    impl Parse for Schema {
3047        fn parse(input: ParseStream) -> syn::Result<Self> {
3048            let inline = if input.peek(Token![#]) && input.peek2(Bracket) {
3049                input.parse::<Token![#]>()?;
3050
3051                let inline;
3052                bracketed!(inline in input);
3053                let i = inline.parse::<Ident>()?;
3054                i == "inline"
3055            } else {
3056                false
3057            };
3058
3059            let ty = input.parse()?;
3060
3061            Ok(Self { inline, ty })
3062        }
3063    }
3064
3065    let schema = syn::parse_macro_input!(input as Schema);
3066    let type_tree = match TypeTree::from_type(&schema.ty) {
3067        Ok(type_tree) => type_tree,
3068        Err(diagnostics) => return diagnostics.into_token_stream().into(),
3069    };
3070
3071    let generics = match type_tree.get_path_generics() {
3072        Ok(generics) => generics,
3073        Err(error) => return error.into_compile_error().into(),
3074    };
3075
3076    let schema = ComponentSchema::new(ComponentSchemaProps {
3077        features: vec![Feature::Inline(schema.inline.into())],
3078        type_tree: &type_tree,
3079        description: None,
3080        container: &component::Container {
3081            generics: &generics,
3082        },
3083    });
3084
3085    let schema = match schema {
3086        Ok(schema) => schema.to_token_stream(),
3087        Err(diagnostics) => return diagnostics.to_token_stream().into(),
3088    };
3089
3090    quote! {
3091        {
3092            let mut generics: Vec<fastapi::openapi::RefOr<fastapi::openapi::schema::Schema>> = Vec::new();
3093            #schema
3094        }
3095    }
3096    .into()
3097}
3098
3099/// Tokenizes slice or Vec of tokenizable items as array either with reference (`&[...]`)
3100/// or without correctly to OpenAPI JSON.
3101#[cfg_attr(feature = "debug", derive(Debug))]
3102enum Array<'a, T>
3103where
3104    T: Sized + ToTokens,
3105{
3106    Owned(Vec<T>),
3107    #[allow(dead_code)]
3108    Borrowed(&'a [T]),
3109}
3110
3111impl<V> FromIterator<V> for Array<'_, V>
3112where
3113    V: Sized + ToTokens,
3114{
3115    fn from_iter<T: IntoIterator<Item = V>>(iter: T) -> Self {
3116        Self::Owned(iter.into_iter().collect())
3117    }
3118}
3119
3120impl<'a, T> Deref for Array<'a, T>
3121where
3122    T: Sized + ToTokens,
3123{
3124    type Target = [T];
3125
3126    fn deref(&self) -> &Self::Target {
3127        match self {
3128            Self::Owned(vec) => vec.as_slice(),
3129            Self::Borrowed(slice) => slice,
3130        }
3131    }
3132}
3133
3134impl<T> ToTokens for Array<'_, T>
3135where
3136    T: Sized + ToTokens,
3137{
3138    fn to_tokens(&self, tokens: &mut TokenStream2) {
3139        let values = match self {
3140            Self::Owned(values) => values.iter(),
3141            Self::Borrowed(values) => values.iter(),
3142        };
3143
3144        tokens.append(Group::new(
3145            proc_macro2::Delimiter::Bracket,
3146            values
3147                .fold(Punctuated::new(), |mut punctuated, item| {
3148                    punctuated.push_value(item);
3149                    punctuated.push_punct(Punct::new(',', proc_macro2::Spacing::Alone));
3150
3151                    punctuated
3152                })
3153                .to_token_stream(),
3154        ));
3155    }
3156}
3157
3158#[cfg_attr(feature = "debug", derive(Debug))]
3159enum Deprecated {
3160    True,
3161    False,
3162}
3163
3164impl From<bool> for Deprecated {
3165    fn from(bool: bool) -> Self {
3166        if bool {
3167            Self::True
3168        } else {
3169            Self::False
3170        }
3171    }
3172}
3173
3174impl ToTokens for Deprecated {
3175    fn to_tokens(&self, tokens: &mut TokenStream2) {
3176        tokens.extend(match self {
3177            Self::False => quote! { fastapi::openapi::Deprecated::False },
3178            Self::True => quote! { fastapi::openapi::Deprecated::True },
3179        })
3180    }
3181}
3182
3183#[derive(PartialEq, Eq)]
3184#[cfg_attr(feature = "debug", derive(Debug))]
3185enum Required {
3186    True,
3187    False,
3188}
3189
3190impl From<bool> for Required {
3191    fn from(bool: bool) -> Self {
3192        if bool {
3193            Self::True
3194        } else {
3195            Self::False
3196        }
3197    }
3198}
3199
3200impl From<features::attributes::Required> for Required {
3201    fn from(value: features::attributes::Required) -> Self {
3202        let features::attributes::Required(required) = value;
3203        crate::Required::from(required)
3204    }
3205}
3206
3207impl ToTokens for Required {
3208    fn to_tokens(&self, tokens: &mut TokenStream2) {
3209        tokens.extend(match self {
3210            Self::False => quote! { fastapi::openapi::Required::False },
3211            Self::True => quote! { fastapi::openapi::Required::True },
3212        })
3213    }
3214}
3215
3216#[derive(Default)]
3217#[cfg_attr(feature = "debug", derive(Debug))]
3218struct ExternalDocs {
3219    url: String,
3220    description: Option<String>,
3221}
3222
3223impl Parse for ExternalDocs {
3224    fn parse(input: ParseStream) -> syn::Result<Self> {
3225        const EXPECTED_ATTRIBUTE: &str = "unexpected attribute, expected any of: url, description";
3226
3227        let mut external_docs = ExternalDocs::default();
3228
3229        while !input.is_empty() {
3230            let ident = input.parse::<Ident>().map_err(|error| {
3231                syn::Error::new(error.span(), format!("{EXPECTED_ATTRIBUTE}, {error}"))
3232            })?;
3233            let attribute_name = &*ident.to_string();
3234
3235            match attribute_name {
3236                "url" => {
3237                    external_docs.url = parse_utils::parse_next_literal_str(input)?;
3238                }
3239                "description" => {
3240                    external_docs.description = Some(parse_utils::parse_next_literal_str(input)?);
3241                }
3242                _ => return Err(syn::Error::new(ident.span(), EXPECTED_ATTRIBUTE)),
3243            }
3244
3245            if !input.is_empty() {
3246                input.parse::<Token![,]>()?;
3247            }
3248        }
3249
3250        Ok(external_docs)
3251    }
3252}
3253
3254impl ToTokens for ExternalDocs {
3255    fn to_tokens(&self, tokens: &mut TokenStream2) {
3256        let url = &self.url;
3257        tokens.extend(quote! {
3258            fastapi::openapi::external_docs::ExternalDocsBuilder::new()
3259                .url(#url)
3260        });
3261
3262        if let Some(ref description) = self.description {
3263            tokens.extend(quote! {
3264                .description(Some(#description))
3265            });
3266        }
3267
3268        tokens.extend(quote! { .build() })
3269    }
3270}
3271
3272/// Represents OpenAPI Any value used in example and default fields.
3273#[derive(Clone)]
3274#[cfg_attr(feature = "debug", derive(Debug))]
3275enum AnyValue {
3276    String(TokenStream2),
3277    Json(TokenStream2),
3278    DefaultTrait {
3279        struct_ident: Ident,
3280        field_ident: Member,
3281    },
3282}
3283
3284impl AnyValue {
3285    /// Parse `json!(...)` as [`AnyValue::Json`]
3286    fn parse_json(input: ParseStream) -> syn::Result<Self> {
3287        parse_utils::parse_json_token_stream(input).map(AnyValue::Json)
3288    }
3289
3290    fn parse_any(input: ParseStream) -> syn::Result<Self> {
3291        if input.peek(Lit) {
3292            let punct = input.parse::<Option<Token![-]>>()?;
3293            let lit = input.parse::<Lit>().unwrap();
3294
3295            Ok(AnyValue::Json(quote! { #punct #lit}))
3296        } else {
3297            let fork = input.fork();
3298            let is_json = if fork.peek(syn::Ident) && fork.peek2(Token![!]) {
3299                let ident = fork.parse::<Ident>().unwrap();
3300                ident == "json"
3301            } else {
3302                false
3303            };
3304
3305            if is_json {
3306                let json = parse_utils::parse_json_token_stream(input)?;
3307
3308                Ok(AnyValue::Json(json))
3309            } else {
3310                let method = input.parse::<ExprPath>().map_err(|error| {
3311                    syn::Error::new(
3312                        error.span(),
3313                        "expected literal value, json!(...) or method reference",
3314                    )
3315                })?;
3316
3317                Ok(AnyValue::Json(quote! { #method() }))
3318            }
3319        }
3320    }
3321
3322    fn parse_lit_str_or_json(input: ParseStream) -> syn::Result<Self> {
3323        if input.peek(LitStr) {
3324            Ok(AnyValue::String(
3325                input.parse::<LitStr>().unwrap().to_token_stream(),
3326            ))
3327        } else {
3328            Ok(AnyValue::Json(parse_utils::parse_json_token_stream(input)?))
3329        }
3330    }
3331
3332    fn new_default_trait(struct_ident: Ident, field_ident: Member) -> Self {
3333        Self::DefaultTrait {
3334            struct_ident,
3335            field_ident,
3336        }
3337    }
3338}
3339
3340impl ToTokens for AnyValue {
3341    fn to_tokens(&self, tokens: &mut TokenStream2) {
3342        match self {
3343            Self::Json(json) => tokens.extend(quote! {
3344                serde_json::json!(#json)
3345            }),
3346            Self::String(string) => string.to_tokens(tokens),
3347            Self::DefaultTrait {
3348                struct_ident,
3349                field_ident,
3350            } => tokens.extend(quote! {
3351                serde_json::to_value(#struct_ident::default().#field_ident).unwrap()
3352            }),
3353        }
3354    }
3355}
3356
3357trait OptionExt<T> {
3358    fn map_try<F, U, E>(self, f: F) -> Result<Option<U>, E>
3359    where
3360        F: FnOnce(T) -> Result<U, E>;
3361    fn and_then_try<F, U, E>(self, f: F) -> Result<Option<U>, E>
3362    where
3363        F: FnOnce(T) -> Result<Option<U>, E>;
3364    fn or_else_try<F, U>(self, f: F) -> Result<Option<T>, U>
3365    where
3366        F: FnOnce() -> Result<Option<T>, U>;
3367}
3368
3369impl<T> OptionExt<T> for Option<T> {
3370    fn map_try<F, U, E>(self, f: F) -> Result<Option<U>, E>
3371    where
3372        F: FnOnce(T) -> Result<U, E>,
3373    {
3374        if let Some(v) = self {
3375            f(v).map(Some)
3376        } else {
3377            Ok(None)
3378        }
3379    }
3380
3381    fn and_then_try<F, U, E>(self, f: F) -> Result<Option<U>, E>
3382    where
3383        F: FnOnce(T) -> Result<Option<U>, E>,
3384    {
3385        if let Some(v) = self {
3386            match f(v) {
3387                Ok(inner) => Ok(inner),
3388                Err(error) => Err(error),
3389            }
3390        } else {
3391            Ok(None)
3392        }
3393    }
3394
3395    fn or_else_try<F, U>(self, f: F) -> Result<Option<T>, U>
3396    where
3397        F: FnOnce() -> Result<Option<T>, U>,
3398    {
3399        if self.is_none() {
3400            f()
3401        } else {
3402            Ok(self)
3403        }
3404    }
3405}
3406
3407trait GenericsExt {
3408    /// Get index of `GenericParam::Type` ignoring other generic param types.
3409    fn get_generic_type_param_index(&self, type_tree: &TypeTree) -> Option<usize>;
3410}
3411
3412impl<'g> GenericsExt for &'g syn::Generics {
3413    fn get_generic_type_param_index(&self, type_tree: &TypeTree) -> Option<usize> {
3414        let ident = &type_tree
3415            .path
3416            .as_ref()
3417            .expect("TypeTree of generic object must have a path")
3418            .segments
3419            .last()
3420            .expect("Generic object path must have at least one segment")
3421            .ident;
3422
3423        self.params
3424            .iter()
3425            .filter(|generic| matches!(generic, GenericParam::Type(_)))
3426            .enumerate()
3427            .find_map(|(index, generic)| {
3428                if matches!(generic, GenericParam::Type(ty) if ty.ident == *ident) {
3429                    Some(index)
3430                } else {
3431                    None
3432                }
3433            })
3434    }
3435}
3436
3437trait ToTokensDiagnostics {
3438    fn to_tokens(&self, tokens: &mut TokenStream2) -> Result<(), Diagnostics>;
3439
3440    #[allow(unused)]
3441    fn into_token_stream(self) -> TokenStream2
3442    where
3443        Self: std::marker::Sized,
3444    {
3445        ToTokensDiagnostics::to_token_stream(&self)
3446    }
3447
3448    fn to_token_stream(&self) -> TokenStream2 {
3449        let mut tokens = TokenStream2::new();
3450        match ToTokensDiagnostics::to_tokens(self, &mut tokens) {
3451            Ok(_) => tokens,
3452            Err(error_stream) => Into::<Diagnostics>::into(error_stream).into_token_stream(),
3453        }
3454    }
3455
3456    fn try_to_token_stream(&self) -> Result<TokenStream2, Diagnostics> {
3457        let mut tokens = TokenStream2::new();
3458        match ToTokensDiagnostics::to_tokens(self, &mut tokens) {
3459            Ok(_) => Ok(tokens),
3460            Err(diagnostics) => Err(diagnostics),
3461        }
3462    }
3463}
3464
3465macro_rules! as_tokens_or_diagnostics {
3466    ( $type:expr ) => {{
3467        let mut _tokens = proc_macro2::TokenStream::new();
3468        match crate::ToTokensDiagnostics::to_tokens($type, &mut _tokens) {
3469            Ok(_) => _tokens,
3470            Err(diagnostics) => return Err(diagnostics),
3471        }
3472    }};
3473}
3474
3475use as_tokens_or_diagnostics;
3476
3477#[derive(Debug)]
3478struct Diagnostics {
3479    diagnostics: Vec<DiangosticsInner>,
3480}
3481
3482#[derive(Debug)]
3483struct DiangosticsInner {
3484    span: Span,
3485    message: Cow<'static, str>,
3486    suggestions: Vec<Suggestion>,
3487}
3488
3489#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
3490enum Suggestion {
3491    Help(Cow<'static, str>),
3492    Note(Cow<'static, str>),
3493}
3494
3495impl Display for Diagnostics {
3496    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3497        write!(f, "{}", self.message())
3498    }
3499}
3500
3501impl Display for Suggestion {
3502    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3503        match self {
3504            Self::Help(help) => {
3505                let s: &str = help.borrow();
3506                write!(f, "help = {}", s)
3507            }
3508            Self::Note(note) => {
3509                let s: &str = note.borrow();
3510                write!(f, "note = {}", s)
3511            }
3512        }
3513    }
3514}
3515
3516impl Diagnostics {
3517    fn message(&self) -> Cow<'static, str> {
3518        self.diagnostics
3519            .first()
3520            .as_ref()
3521            .map(|diagnostics| diagnostics.message.clone())
3522            .unwrap_or_else(|| Cow::Borrowed(""))
3523    }
3524
3525    pub fn new<S: Into<Cow<'static, str>>>(message: S) -> Self {
3526        Self::with_span(Span::call_site(), message)
3527    }
3528
3529    pub fn with_span<S: Into<Cow<'static, str>>>(span: Span, message: S) -> Self {
3530        Self {
3531            diagnostics: vec![DiangosticsInner {
3532                span,
3533                message: message.into(),
3534                suggestions: Vec::new(),
3535            }],
3536        }
3537    }
3538
3539    pub fn help<S: Into<Cow<'static, str>>>(mut self, help: S) -> Self {
3540        if let Some(diagnostics) = self.diagnostics.first_mut() {
3541            diagnostics.suggestions.push(Suggestion::Help(help.into()));
3542            diagnostics.suggestions.sort();
3543        }
3544
3545        self
3546    }
3547
3548    pub fn note<S: Into<Cow<'static, str>>>(mut self, note: S) -> Self {
3549        if let Some(diagnostics) = self.diagnostics.first_mut() {
3550            diagnostics.suggestions.push(Suggestion::Note(note.into()));
3551            diagnostics.suggestions.sort();
3552        }
3553
3554        self
3555    }
3556}
3557
3558impl From<syn::Error> for Diagnostics {
3559    fn from(value: syn::Error) -> Self {
3560        Self::with_span(value.span(), value.to_string())
3561    }
3562}
3563
3564impl ToTokens for Diagnostics {
3565    fn to_tokens(&self, tokens: &mut TokenStream2) {
3566        for diagnostics in &self.diagnostics {
3567            let span = diagnostics.span;
3568            let message: &str = diagnostics.message.borrow();
3569
3570            let suggestions = diagnostics
3571                .suggestions
3572                .iter()
3573                .map(Suggestion::to_string)
3574                .collect::<Vec<_>>()
3575                .join("\n");
3576
3577            let diagnostics = if !suggestions.is_empty() {
3578                Cow::Owned(format!("{message}\n\n{suggestions}"))
3579            } else {
3580                Cow::Borrowed(message)
3581            };
3582
3583            tokens.extend(quote_spanned! {span=>
3584                ::core::compile_error!(#diagnostics);
3585            })
3586        }
3587    }
3588}
3589
3590impl Error for Diagnostics {}
3591
3592impl FromIterator<Diagnostics> for Option<Diagnostics> {
3593    fn from_iter<T: IntoIterator<Item = Diagnostics>>(iter: T) -> Self {
3594        iter.into_iter().reduce(|mut acc, diagnostics| {
3595            acc.diagnostics.extend(diagnostics.diagnostics);
3596            acc
3597        })
3598    }
3599}
3600
3601trait AttributesExt {
3602    fn has_deprecated(&self) -> bool;
3603}
3604
3605impl AttributesExt for Vec<syn::Attribute> {
3606    fn has_deprecated(&self) -> bool {
3607        let this = &**self;
3608        this.has_deprecated()
3609    }
3610}
3611
3612impl<'a> AttributesExt for &'a [syn::Attribute] {
3613    fn has_deprecated(&self) -> bool {
3614        self.iter().any(|attr| {
3615            matches!(attr.path().get_ident(), Some(ident) if &*ident.to_string() == "deprecated")
3616        })
3617    }
3618}
3619
3620#[cfg(test)]
3621mod tests {
3622    use super::*;
3623
3624    #[test]
3625    fn diagnostics_ordering_help_comes_before_note() {
3626        let diagnostics = Diagnostics::new("this an error")
3627            .note("you could do this to solve the error")
3628            .help("try this thing");
3629
3630        let tokens = diagnostics.into_token_stream();
3631
3632        let expected_tokens = quote::quote!(::core::compile_error!(
3633            "this an error\n\nhelp = try this thing\nnote = you could do this to solve the error"
3634        ););
3635
3636        assert_eq!(tokens.to_string(), expected_tokens.to_string());
3637    }
3638}
3639
3640/// Parsing utils
3641mod parse_utils {
3642    use std::fmt::Display;
3643
3644    use proc_macro2::{Group, Ident, TokenStream};
3645    use quote::{quote, ToTokens};
3646    use syn::{
3647        parenthesized,
3648        parse::{Parse, ParseStream},
3649        punctuated::Punctuated,
3650        spanned::Spanned,
3651        token::Comma,
3652        Error, Expr, ExprPath, LitBool, LitStr, Token,
3653    };
3654
3655    #[cfg_attr(feature = "debug", derive(Debug))]
3656    #[derive(Clone)]
3657    pub enum LitStrOrExpr {
3658        LitStr(LitStr),
3659        Expr(Expr),
3660    }
3661
3662    impl From<String> for LitStrOrExpr {
3663        fn from(value: String) -> Self {
3664            Self::LitStr(LitStr::new(&value, proc_macro2::Span::call_site()))
3665        }
3666    }
3667
3668    impl LitStrOrExpr {
3669        pub(crate) fn is_empty_litstr(&self) -> bool {
3670            matches!(self, Self::LitStr(s) if s.value().is_empty())
3671        }
3672    }
3673
3674    impl Default for LitStrOrExpr {
3675        fn default() -> Self {
3676            Self::LitStr(LitStr::new("", proc_macro2::Span::call_site()))
3677        }
3678    }
3679
3680    impl Parse for LitStrOrExpr {
3681        fn parse(input: ParseStream) -> syn::Result<Self> {
3682            if input.peek(LitStr) {
3683                Ok::<LitStrOrExpr, Error>(LitStrOrExpr::LitStr(input.parse::<LitStr>()?))
3684            } else {
3685                Ok(LitStrOrExpr::Expr(input.parse::<Expr>()?))
3686            }
3687        }
3688    }
3689
3690    impl ToTokens for LitStrOrExpr {
3691        fn to_tokens(&self, tokens: &mut TokenStream) {
3692            match self {
3693                Self::LitStr(str) => str.to_tokens(tokens),
3694                Self::Expr(expr) => expr.to_tokens(tokens),
3695            }
3696        }
3697    }
3698
3699    impl Display for LitStrOrExpr {
3700        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3701            match self {
3702                Self::LitStr(str) => write!(f, "{str}", str = str.value()),
3703                Self::Expr(expr) => write!(f, "{expr}", expr = expr.into_token_stream()),
3704            }
3705        }
3706    }
3707
3708    pub fn parse_next<T: FnOnce() -> Result<R, syn::Error>, R: Sized>(
3709        input: ParseStream,
3710        next: T,
3711    ) -> Result<R, syn::Error> {
3712        input.parse::<Token![=]>()?;
3713        next()
3714    }
3715
3716    pub fn parse_next_literal_str(input: ParseStream) -> syn::Result<String> {
3717        Ok(parse_next(input, || input.parse::<LitStr>())?.value())
3718    }
3719
3720    pub fn parse_next_literal_str_or_expr(input: ParseStream) -> syn::Result<LitStrOrExpr> {
3721        parse_next(input, || LitStrOrExpr::parse(input)).map_err(|error| {
3722            syn::Error::new(
3723                error.span(),
3724                format!("expected literal string or expression argument: {error}"),
3725            )
3726        })
3727    }
3728
3729    pub fn parse_groups_collect<T, R>(input: ParseStream) -> syn::Result<R>
3730    where
3731        T: Sized,
3732        T: Parse,
3733        R: FromIterator<T>,
3734    {
3735        Punctuated::<Group, Comma>::parse_terminated(input).and_then(|groups| {
3736            groups
3737                .into_iter()
3738                .map(|group| syn::parse2::<T>(group.stream()))
3739                .collect::<syn::Result<R>>()
3740        })
3741    }
3742
3743    pub fn parse_parethesized_terminated<T: Parse, S: Parse>(
3744        input: ParseStream,
3745    ) -> syn::Result<Punctuated<T, S>> {
3746        let group;
3747        syn::parenthesized!(group in input);
3748        Punctuated::parse_terminated(&group)
3749    }
3750
3751    pub fn parse_comma_separated_within_parethesis_with<T>(
3752        input: ParseStream,
3753        with: fn(ParseStream) -> syn::Result<T>,
3754    ) -> syn::Result<Punctuated<T, Comma>>
3755    where
3756        T: Parse,
3757    {
3758        let content;
3759        parenthesized!(content in input);
3760        Punctuated::<T, Comma>::parse_terminated_with(&content, with)
3761    }
3762
3763    pub fn parse_comma_separated_within_parenthesis<T>(
3764        input: ParseStream,
3765    ) -> syn::Result<Punctuated<T, Comma>>
3766    where
3767        T: Parse,
3768    {
3769        let content;
3770        parenthesized!(content in input);
3771        Punctuated::<T, Comma>::parse_terminated(&content)
3772    }
3773
3774    pub fn parse_bool_or_true(input: ParseStream) -> syn::Result<bool> {
3775        if input.peek(Token![=]) && input.peek2(LitBool) {
3776            input.parse::<Token![=]>()?;
3777
3778            Ok(input.parse::<LitBool>()?.value())
3779        } else {
3780            Ok(true)
3781        }
3782    }
3783
3784    /// Parse `json!(...)` as a [`TokenStream`].
3785    pub fn parse_json_token_stream(input: ParseStream) -> syn::Result<TokenStream> {
3786        if input.peek(syn::Ident) && input.peek2(Token![!]) {
3787            input.parse::<Ident>().and_then(|ident| {
3788                if ident != "json" {
3789                    return Err(Error::new(
3790                        ident.span(),
3791                        format!("unexpected token {ident}, expected: json!(...)"),
3792                    ));
3793                }
3794
3795                Ok(ident)
3796            })?;
3797            input.parse::<Token![!]>()?;
3798
3799            Ok(input.parse::<Group>()?.stream())
3800        } else {
3801            Err(Error::new(
3802                input.span(),
3803                "unexpected token, expected json!(...)",
3804            ))
3805        }
3806    }
3807
3808    #[cfg_attr(feature = "debug", derive(Debug))]
3809    #[derive(Clone)]
3810    pub enum LitBoolOrExprPath {
3811        LitBool(LitBool),
3812        ExprPath(ExprPath),
3813    }
3814
3815    impl From<bool> for LitBoolOrExprPath {
3816        fn from(value: bool) -> Self {
3817            Self::LitBool(LitBool::new(value, proc_macro2::Span::call_site()))
3818        }
3819    }
3820
3821    impl Default for LitBoolOrExprPath {
3822        fn default() -> Self {
3823            Self::LitBool(LitBool::new(false, proc_macro2::Span::call_site()))
3824        }
3825    }
3826
3827    impl Parse for LitBoolOrExprPath {
3828        fn parse(input: ParseStream) -> syn::Result<Self> {
3829            if input.peek(LitBool) {
3830                Ok(LitBoolOrExprPath::LitBool(input.parse::<LitBool>()?))
3831            } else {
3832                let expr = input.parse::<Expr>()?;
3833
3834                match expr {
3835                    Expr::Path(expr_path) => Ok(LitBoolOrExprPath::ExprPath(expr_path)),
3836                    _ => Err(syn::Error::new(
3837                        expr.span(),
3838                        format!(
3839                            "expected literal bool or path to a function that returns bool, found: {}",
3840                            quote! {#expr}
3841                        ),
3842                    )),
3843                }
3844            }
3845        }
3846    }
3847
3848    impl ToTokens for LitBoolOrExprPath {
3849        fn to_tokens(&self, tokens: &mut TokenStream) {
3850            match self {
3851                Self::LitBool(bool) => bool.to_tokens(tokens),
3852                Self::ExprPath(call) => call.to_tokens(tokens),
3853            }
3854        }
3855    }
3856
3857    pub fn parse_next_literal_bool_or_call(input: ParseStream) -> syn::Result<LitBoolOrExprPath> {
3858        if input.peek(Token![=]) {
3859            parse_next(input, || LitBoolOrExprPath::parse(input))
3860        } else {
3861            Ok(LitBoolOrExprPath::from(true))
3862        }
3863    }
3864}