paperclip_macros/
lib.rs

1//! Convenience macros for [paperclip](https://github.com/paperclip-rs/paperclip).
2//!
3//! You shouldn't need to depend on this, because the stuff here is
4//! already exposed by the corresponding crates.
5
6#![recursion_limit = "512"]
7
8extern crate proc_macro;
9#[macro_use]
10extern crate proc_macro_error2;
11
12#[cfg(feature = "actix")]
13#[macro_use]
14mod actix;
15#[cfg(feature = "v2")]
16mod core;
17
18use proc_macro::TokenStream;
19use quote::quote;
20use syn::{
21    parse::{Parse, ParseStream},
22    punctuated::Punctuated,
23    spanned::Spanned,
24    token::Comma,
25    DeriveInput, NestedMeta,
26};
27
28/// Converts your struct to support deserializing from an OpenAPI v2
29/// [Schema](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#schemaObject)
30/// object ([example](https://paperclip-rs.github.io/paperclip/paperclip/v2/)). This adds the necessary fields (in addition to your own fields) and implements the
31/// `Schema` trait for parsing and codegen.
32#[cfg(feature = "v2")]
33#[proc_macro_attribute]
34pub fn api_v2_schema_struct(_attr: TokenStream, input: TokenStream) -> TokenStream {
35    self::core::emit_v2_schema_struct(input)
36}
37
38/// Marker attribute for indicating that a function is an OpenAPI v2 compatible operation.
39#[cfg(feature = "actix")]
40#[proc_macro_error]
41#[proc_macro_attribute]
42pub fn api_v2_operation(attr: TokenStream, input: TokenStream) -> TokenStream {
43    self::actix::emit_v2_operation(attr, input)
44}
45
46/// Derive attribute for indicating that a type is an OpenAPI v2 compatible definition.
47#[cfg(feature = "actix")]
48#[proc_macro_error]
49#[proc_macro_derive(Apiv2Schema, attributes(openapi))]
50pub fn api_v2_schema(input: TokenStream) -> TokenStream {
51    self::actix::emit_v2_definition(input)
52}
53
54/// Marker attribute for indicating that an object forbids public access to operation (for example AccessToken).
55#[cfg(feature = "actix")]
56#[proc_macro_error]
57#[proc_macro_derive(Apiv2Security, attributes(openapi))]
58pub fn api_v2_security(input: TokenStream) -> TokenStream {
59    self::actix::emit_v2_security(input)
60}
61
62/// Derive attribute for indicating that a type is an OpenAPI v2 compatible header parameter.
63#[cfg(feature = "actix")]
64#[proc_macro_error]
65#[proc_macro_derive(Apiv2Header, attributes(openapi))]
66pub fn api_v2_header(input: TokenStream) -> TokenStream {
67    self::actix::emit_v2_header(input)
68}
69
70/// Marker attribute for indicating that the marked object can represent non-2xx (error)
71/// status codes with optional descriptions.
72#[cfg(feature = "actix")]
73#[proc_macro_error]
74#[proc_macro_attribute]
75pub fn api_v2_errors(attrs: TokenStream, input: TokenStream) -> TokenStream {
76    self::actix::emit_v2_errors(attrs, input)
77}
78
79/// Marker attribute for indicating that the marked object can filter error responses from the
80/// the `#[api_v2_errors]` macro.
81#[cfg(feature = "actix")]
82#[proc_macro_error]
83#[proc_macro_attribute]
84pub fn api_v2_errors_overlay(attrs: TokenStream, input: TokenStream) -> TokenStream {
85    self::actix::emit_v2_errors_overlay(attrs, input)
86}
87
88/// Generate an error at the call site and return empty token stream.
89#[allow(dead_code)]
90fn span_error_with_msg<T: Spanned>(it: &T, msg: &str) -> TokenStream {
91    emit_error!(it.span().unwrap(), msg);
92    (quote! {}).into()
93}
94
95/// Parses this token stream expecting a struct/enum and fails with an error otherwise.
96#[allow(dead_code)]
97fn expect_struct_or_enum(ts: TokenStream) -> Result<DeriveInput, TokenStream> {
98    syn::parse(ts).map_err(|e| {
99        emit_error!(
100            e.span().unwrap(),
101            "expected struct or enum for deriving schema."
102        );
103        quote!().into()
104    })
105}
106
107/// Helper struct for parsing proc-macro input attributes.
108#[derive(Default)]
109struct MacroAttribute(#[allow(dead_code)] Punctuated<NestedMeta, Comma>);
110
111impl Parse for MacroAttribute {
112    fn parse(input: ParseStream) -> syn::Result<Self> {
113        Ok(MacroAttribute(input.call(Punctuated::parse_terminated)?))
114    }
115}
116
117#[cfg(feature = "actix")]
118fn parse_input_attrs(ts: TokenStream) -> MacroAttribute {
119    syn::parse(ts)
120        .map_err(|e| {
121            emit_warning!(
122                e.span().unwrap(),
123                "cannot parse proc-macro input attributes."
124            );
125        })
126        .ok()
127        .unwrap_or_default()
128}
129
130#[cfg(feature = "actix")]
131rest_methods! {
132    Get,    get,
133    Post,   post,
134    Put,    put,
135    Delete, delete,
136    Patch,  patch,
137    Head,   head,
138}