utoipa_gen/component/features/attributes/
extensions.rs

1use syn::punctuated::Punctuated;
2use syn::Token;
3
4use crate::component::features::{Feature, Parse};
5use crate::features::impl_feature;
6use crate::{parse_utils, AnyValue};
7use quote::ToTokens;
8
9impl_feature! {
10    /// Parse the following into a set of extensions:
11    /// ```text
12    /// extensions(
13    ///   ("foo_extension" = json!("foo")),
14    ///   ("bar_extension" = json!("bar")),
15    /// )
16    /// ```
17    #[derive(Clone, Default)]
18    #[cfg_attr(feature = "debug", derive(Debug))]
19    pub struct Extensions {
20        extensions: Vec<Extension>,
21    }
22}
23
24impl Parse for Extensions {
25    fn parse(input: syn::parse::ParseStream, _: proc_macro2::Ident) -> syn::Result<Self> {
26        syn::parse::Parse::parse(input)
27    }
28}
29
30impl syn::parse::Parse for Extensions {
31    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
32        let params;
33        syn::parenthesized!(params in input);
34        let extensions = Punctuated::<Extension, Token![,]>::parse_terminated(&params)
35            .map(|punctuated| punctuated.into_iter().collect::<Vec<Extension>>())?;
36        Ok(Extensions { extensions })
37    }
38}
39
40impl ToTokens for Extensions {
41    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
42        let extensions = &self.extensions;
43        tokens.extend(quote::quote! {
44          utoipa::openapi::extensions::ExtensionsBuilder::new() #(#extensions)* .build()
45        });
46    }
47}
48
49impl From<Extensions> for Feature {
50    fn from(value: Extensions) -> Self {
51        Feature::Extensions(value)
52    }
53}
54
55/// Parse the following into an extension:
56/// ```text
57/// ("foo_extension" = json!("value"))
58/// ```
59#[derive(Clone)]
60#[cfg_attr(feature = "debug", derive(Debug))]
61pub struct Extension {
62    name: parse_utils::LitStrOrExpr,
63    value: AnyValue, // <- Expect variant AnyValue::Json
64}
65
66impl syn::parse::Parse for Extension {
67    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
68        let inner;
69        syn::parenthesized!(inner in input);
70        let name = inner.parse::<parse_utils::LitStrOrExpr>()?;
71
72        inner.parse::<Token![=]>()?;
73
74        let value = AnyValue::parse_json(&inner)?;
75        Ok(Extension { name, value })
76    }
77}
78
79impl ToTokens for Extension {
80    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
81        let name = &self.name;
82        let value = &self.value;
83        tokens.extend(quote::quote! {
84            .add(#name, #value)
85        });
86    }
87}