utoipa_gen/path/media_type/
encoding.rs1use 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#[derive(Default)]
10#[cfg_attr(feature = "debug", derive(Debug))]
11pub struct Encoding {
12 pub(super) content_type: Option<parse_utils::LitStrOrExpr>,
13 pub(super) explode: Option<bool>,
16 pub(super) allow_reserved: Option<bool>,
17 }
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 "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 _ => {
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}