utoipa_gen/path/response/
link.rs1use proc_macro2::TokenStream;
2use quote::{quote, ToTokens};
3use syn::parse::Parse;
4use syn::punctuated::Punctuated;
5use syn::token::Comma;
6use syn::{Ident, Token};
7
8use crate::openapi::Server;
9use crate::{parse_utils, AnyValue};
10
11#[cfg_attr(feature = "debug", derive(Debug))]
13pub struct LinkTuple(pub parse_utils::LitStrOrExpr, pub Link);
14
15impl Parse for LinkTuple {
16 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
17 let inner;
18 syn::parenthesized!(inner in input);
19
20 let name = inner.parse::<parse_utils::LitStrOrExpr>()?;
21 inner.parse::<Token![=]>()?;
22 let value = inner.parse::<Link>()?;
23
24 Ok(LinkTuple(name, value))
25 }
26}
27
28#[derive(Default)]
38#[cfg_attr(feature = "debug", derive(Debug))]
39pub struct Link {
40 operation_ref: Option<parse_utils::LitStrOrExpr>,
41 operation_id: Option<parse_utils::LitStrOrExpr>,
42 parameters: Punctuated<LinkParameter, Comma>,
43 request_body: Option<AnyValue>,
44 description: Option<parse_utils::LitStrOrExpr>,
45 server: Option<Server>,
46}
47
48impl Parse for Link {
49 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
50 let inner;
51 syn::parenthesized!(inner in input);
52 let mut link = Link::default();
53
54 while !inner.is_empty() {
55 let ident = inner.parse::<Ident>()?;
56 let attribute = &*ident.to_string();
57
58 match attribute {
59 "operation_ref" => link.operation_ref = Some(parse_utils::parse_next_literal_str_or_expr(&inner)?),
60 "operation_id" => link.operation_id = Some(parse_utils::parse_next_literal_str_or_expr(&inner)?),
61 "parameters" => {
62 link.parameters = parse_utils::parse_comma_separated_within_parenthesis(&inner)?;
63 },
64 "request_body" => link.request_body = Some(parse_utils::parse_next(&inner, || { AnyValue::parse_any(&inner)})?),
65 "description" => link.description = Some(parse_utils::parse_next_literal_str_or_expr(&inner)?),
66 "server" => link.server = Some(inner.call(Server::parse)?),
67 _ => return Err(syn::Error::new(ident.span(), format!("unexpected attribute: {attribute}, expected any of: operation_ref, operation_id, parameters, request_body, description, server")))
68 }
69
70 if !inner.is_empty() {
71 inner.parse::<Token![,]>()?;
72 }
73 }
74
75 Ok(link)
76 }
77}
78
79impl ToTokens for Link {
80 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
81 let operation_ref = self
82 .operation_ref
83 .as_ref()
84 .map(|operation_ref| quote! { .operation_ref(#operation_ref)});
85
86 let operation_id = self
87 .operation_id
88 .as_ref()
89 .map(|operation_id| quote! { .operation_id(#operation_id)});
90
91 let parameters =
92 self.parameters
93 .iter()
94 .fold(TokenStream::new(), |mut params, parameter| {
95 let name = ¶meter.name;
96 let value = ¶meter.value;
97 params.extend(quote! { .parameter(#name, #value) });
98
99 params
100 });
101
102 let request_body = self
103 .request_body
104 .as_ref()
105 .map(|request_body| quote! { .request_body(Some(#request_body)) });
106
107 let description = self
108 .description
109 .as_ref()
110 .map(|description| quote! { .description(#description) });
111
112 let server = self
113 .server
114 .as_ref()
115 .map(|server| quote! { .server(Some(#server)) });
116
117 tokens.extend(quote! {
118 utoipa::openapi::link::Link::builder()
119 #operation_ref
120 #operation_id
121 #parameters
122 #request_body
123 #description
124 #server
125 .build()
126 })
127 }
128}
129
130#[cfg_attr(feature = "debug", derive(Debug))]
132pub struct LinkParameter {
133 name: parse_utils::LitStrOrExpr,
134 value: parse_utils::LitStrOrExpr,
135}
136
137impl Parse for LinkParameter {
138 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
139 let inner;
140 syn::parenthesized!(inner in input);
141 let name = inner.parse::<parse_utils::LitStrOrExpr>()?;
142
143 inner.parse::<Token![=]>()?;
144
145 let value = inner.parse::<parse_utils::LitStrOrExpr>()?;
146
147 Ok(LinkParameter { name, value })
148 }
149}