utoipa_gen/path/response/
link.rs
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use syn::parse::Parse;
use syn::punctuated::Punctuated;
use syn::token::Comma;
use syn::{Ident, Token};
use crate::openapi::Server;
use crate::{parse_utils, AnyValue};
#[cfg_attr(feature = "debug", derive(Debug))]
pub struct LinkTuple(pub parse_utils::LitStrOrExpr, pub Link);
impl Parse for LinkTuple {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let inner;
syn::parenthesized!(inner in input);
let name = inner.parse::<parse_utils::LitStrOrExpr>()?;
inner.parse::<Token![=]>()?;
let value = inner.parse::<Link>()?;
Ok(LinkTuple(name, value))
}
}
#[derive(Default)]
#[cfg_attr(feature = "debug", derive(Debug))]
pub struct Link {
operation_ref: Option<parse_utils::LitStrOrExpr>,
operation_id: Option<parse_utils::LitStrOrExpr>,
parameters: Punctuated<LinkParameter, Comma>,
request_body: Option<AnyValue>,
description: Option<parse_utils::LitStrOrExpr>,
server: Option<Server>,
}
impl Parse for Link {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let inner;
syn::parenthesized!(inner in input);
let mut link = Link::default();
while !inner.is_empty() {
let ident = inner.parse::<Ident>()?;
let attribute = &*ident.to_string();
match attribute {
"operation_ref" => link.operation_ref = Some(parse_utils::parse_next_literal_str_or_expr(&inner)?),
"operation_id" => link.operation_id = Some(parse_utils::parse_next_literal_str_or_expr(&inner)?),
"parameters" => {
link.parameters = parse_utils::parse_comma_separated_within_parenthesis(&inner)?;
},
"request_body" => link.request_body = Some(parse_utils::parse_next(&inner, || { AnyValue::parse_any(&inner)})?),
"description" => link.description = Some(parse_utils::parse_next_literal_str_or_expr(&inner)?),
"server" => link.server = Some(inner.call(Server::parse)?),
_ => return Err(syn::Error::new(ident.span(), format!("unexpected attribute: {attribute}, expected any of: operation_ref, operation_id, parameters, request_body, description, server")))
}
if !inner.is_empty() {
inner.parse::<Token![,]>()?;
}
}
Ok(link)
}
}
impl ToTokens for Link {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
let operation_ref = self
.operation_ref
.as_ref()
.map(|operation_ref| quote! { .operation_ref(#operation_ref)});
let operation_id = self
.operation_id
.as_ref()
.map(|operation_id| quote! { .operation_id(#operation_id)});
let parameters =
self.parameters
.iter()
.fold(TokenStream::new(), |mut params, parameter| {
let name = ¶meter.name;
let value = ¶meter.value;
params.extend(quote! { .parameter(#name, #value) });
params
});
let request_body = self
.request_body
.as_ref()
.map(|request_body| quote! { .request_body(Some(#request_body)) });
let description = self
.description
.as_ref()
.map(|description| quote! { .description(#description) });
let server = self
.server
.as_ref()
.map(|server| quote! { .server(Some(#server)) });
tokens.extend(quote! {
utoipa::openapi::link::Link::builder()
#operation_ref
#operation_id
#parameters
#request_body
#description
#server
.build()
})
}
}
#[cfg_attr(feature = "debug", derive(Debug))]
pub struct LinkParameter {
name: parse_utils::LitStrOrExpr,
value: parse_utils::LitStrOrExpr,
}
impl Parse for LinkParameter {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let inner;
syn::parenthesized!(inner in input);
let name = inner.parse::<parse_utils::LitStrOrExpr>()?;
inner.parse::<Token![=]>()?;
let value = inner.parse::<parse_utils::LitStrOrExpr>()?;
Ok(LinkParameter { name, value })
}
}