utoipa_gen/path/media_type/
encoding.rs

1use proc_macro2::{Ident, TokenStream};
2use quote::{quote, ToTokens};
3use syn::parse::{Parse, ParseStream};
4use syn::{parenthesized, Error, Token};
5
6use crate::parse_utils;
7
8// (content_type = "...", explode = true, allow_reserved = false,)
9#[derive(Default)]
10#[cfg_attr(feature = "debug", derive(Debug))]
11pub struct Encoding {
12    pub(super) content_type: Option<parse_utils::LitStrOrExpr>,
13    // pub(super) headers: BTreeMap<String, Header>,
14    // pub(super) style: Option<ParameterStyle>,
15    pub(super) explode: Option<bool>,
16    pub(super) allow_reserved: Option<bool>,
17    // pub(super) extensions: Option<Extensions>,
18}
19
20impl Parse for Encoding {
21    fn parse(input: ParseStream) -> syn::Result<Self> {
22        let content;
23        parenthesized!(content in input);
24
25        let mut encoding = Encoding::default();
26
27        while !content.is_empty() {
28            let ident = content.parse::<Ident>()?;
29            let attribute_name = &*ident.to_string();
30            match attribute_name {
31                "content_type" => {
32                    encoding.content_type = Some(
33                        parse_utils::parse_next_literal_str_or_expr(&content)?
34                    )
35                }
36                // "headers" => {}
37                // "style" => {}
38                "explode" => {
39                    encoding.explode = Some(
40                        parse_utils::parse_bool_or_true(&content)?
41                    )
42                }
43                "allow_reserved" => {
44                    encoding.allow_reserved = Some(
45                        parse_utils::parse_bool_or_true(&content)?
46                    )
47                }
48                // "extensions"  => {}
49                _ => {
50                    return Err(
51                        Error::new(
52                            ident.span(),
53                            format!("unexpected attribute: {attribute_name}, expected one of: content_type, explode, allow_reserved")
54                        )
55                    )
56                }
57            }
58
59            if !content.is_empty() {
60                content.parse::<Token![,]>()?;
61            }
62        }
63
64        Ok(encoding)
65    }
66}
67
68impl ToTokens for Encoding {
69    fn to_tokens(&self, tokens: &mut TokenStream) {
70        let content_type = self
71            .content_type
72            .as_ref()
73            .map(|content_type| quote!(.content_type(Some(#content_type))));
74        let explode = self
75            .explode
76            .as_ref()
77            .map(|value| quote!(.explode(Some(#value))));
78        let allow_reserved = self
79            .allow_reserved
80            .as_ref()
81            .map(|allow_reserved| quote!(.allow_reserved(Some(#allow_reserved))));
82
83        tokens.extend(quote! {
84            utoipa::openapi::encoding::EncodingBuilder::new()
85                #content_type
86                #explode
87                #allow_reserved
88        })
89    }
90}