From a6c1b8f0bdcf8bc984a0a57f9deb9f55a2d0d62d Mon Sep 17 00:00:00 2001 From: Devin Ragotzy Date: Thu, 13 Aug 2020 18:01:19 -0400 Subject: [PATCH] Parse and emit attributes connected to the request/response defs in ruma_api macro --- ruma-api-macros/src/api.rs | 8 ++++++- ruma-api-macros/src/api/request.rs | 16 ++++++++++++-- ruma-api-macros/src/api/response.rs | 10 +++++++-- ruma-api/tests/ruma_api.rs | 1 + ruma-api/tests/ui/04-attributes.rs | 29 ++++++++++++++++++++++++++ ruma-api/tests/ui/04-attributes.stderr | 5 +++++ 6 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 ruma-api/tests/ui/04-attributes.rs create mode 100644 ruma-api/tests/ui/04-attributes.stderr diff --git a/ruma-api-macros/src/api.rs b/ruma-api-macros/src/api.rs index e40101cc..ef8890d4 100644 --- a/ruma-api-macros/src/api.rs +++ b/ruma-api-macros/src/api.rs @@ -8,7 +8,7 @@ use syn::{ braced, parse::{Parse, ParseStream}, spanned::Spanned, - Field, FieldValue, Token, Type, + Attribute, Field, FieldValue, Token, Type, }; pub(crate) mod attribute; @@ -428,18 +428,21 @@ impl Parse for RawMetadata { } pub struct RawRequest { + pub attributes: Vec, pub request_kw: kw::request, pub fields: Vec, } impl Parse for RawRequest { fn parse(input: ParseStream<'_>) -> syn::Result { + let attributes = input.call(Attribute::parse_outer)?; let request_kw = input.parse::()?; input.parse::()?; let fields; braced!(fields in input); Ok(Self { + attributes, request_kw, fields: fields .parse_terminated::(Field::parse_named)? @@ -450,18 +453,21 @@ impl Parse for RawRequest { } pub struct RawResponse { + pub attributes: Vec, pub response_kw: kw::response, pub fields: Vec, } impl Parse for RawResponse { fn parse(input: ParseStream<'_>) -> syn::Result { + let attributes = input.call(Attribute::parse_outer)?; let response_kw = input.parse::()?; input.parse::()?; let fields; braced!(fields in input); Ok(Self { + attributes, response_kw, fields: fields .parse_terminated::(Field::parse_named)? diff --git a/ruma-api-macros/src/api/request.rs b/ruma-api-macros/src/api/request.rs index e41f25c3..913d58bd 100644 --- a/ruma-api-macros/src/api/request.rs +++ b/ruma-api-macros/src/api/request.rs @@ -4,7 +4,7 @@ use std::{collections::BTreeSet, convert::TryFrom, mem}; use proc_macro2::TokenStream; use quote::{quote, quote_spanned, ToTokens}; -use syn::{spanned::Spanned, Field, Ident, Lifetime}; +use syn::{spanned::Spanned, Attribute, Field, Ident, Lifetime}; use crate::{ api::{ @@ -24,6 +24,9 @@ pub struct RequestLifetimes { /// The result of processing the `request` section of the macro. pub struct Request { + /// The attributes that will be applied to the struct definition. + attributes: Vec, + /// The fields of the request. fields: Vec, @@ -382,13 +385,21 @@ impl TryFrom for Request { )); } - Ok(Self { fields, lifetimes, ruma_api_import: util::import_ruma_api() }) + Ok(Self { + attributes: raw.attributes, + fields, + lifetimes, + ruma_api_import: util::import_ruma_api(), + }) } } impl ToTokens for Request { fn to_tokens(&self, tokens: &mut TokenStream) { let import_path = &self.ruma_api_import; + + let struct_attributes = &self.attributes; + let request_def = if self.fields.is_empty() { quote!(;) } else { @@ -484,6 +495,7 @@ impl ToTokens for Request { let request = quote! { #[derive(Debug, Clone, #import_path::Outgoing)] #[incoming_no_deserialize] + #( #struct_attributes )* pub struct Request #request_generics #request_def #request_body_struct diff --git a/ruma-api-macros/src/api/response.rs b/ruma-api-macros/src/api/response.rs index cd077d89..913b8d9c 100644 --- a/ruma-api-macros/src/api/response.rs +++ b/ruma-api-macros/src/api/response.rs @@ -4,7 +4,7 @@ use std::{convert::TryFrom, mem}; use proc_macro2::TokenStream; use quote::{quote, quote_spanned, ToTokens}; -use syn::{spanned::Spanned, Field, Ident}; +use syn::{spanned::Spanned, Attribute, Field, Ident}; use crate::{ api::{ @@ -16,6 +16,9 @@ use crate::{ /// The result of processing the `response` section of the macro. pub struct Response { + /// The attributes that will be applied to the struct definition. + attributes: Vec, + /// The fields of the response. fields: Vec, @@ -234,7 +237,7 @@ impl TryFrom for Response { )); } - Ok(Self { fields, ruma_api_import: util::import_ruma_api() }) + Ok(Self { attributes: raw.attributes, fields, ruma_api_import: util::import_ruma_api() }) } } @@ -242,6 +245,8 @@ impl ToTokens for Response { fn to_tokens(&self, tokens: &mut TokenStream) { let import_path = &self.ruma_api_import; + let struct_attributes = &self.attributes; + let response_def = if self.fields.is_empty() { quote!(;) } else { @@ -279,6 +284,7 @@ impl ToTokens for Response { let response = quote! { #[derive(Debug, Clone, #import_path::Outgoing)] #[incoming_no_deserialize] + #( #struct_attributes )* pub struct Response #response_def #response_body_struct diff --git a/ruma-api/tests/ruma_api.rs b/ruma-api/tests/ruma_api.rs index bd6e1702..fd9605cf 100644 --- a/ruma-api/tests/ruma_api.rs +++ b/ruma-api/tests/ruma_api.rs @@ -4,4 +4,5 @@ fn ui() { t.pass("tests/ui/01-api-sanity-check.rs"); t.compile_fail("tests/ui/02-invalid-path.rs"); t.pass("tests/ui/03-move-value.rs"); + t.compile_fail("tests/ui/04-attributes.rs"); } diff --git a/ruma-api/tests/ui/04-attributes.rs b/ruma-api/tests/ui/04-attributes.rs new file mode 100644 index 00000000..54613dcf --- /dev/null +++ b/ruma-api/tests/ui/04-attributes.rs @@ -0,0 +1,29 @@ +use ruma_api::ruma_api; + +ruma_api! { + metadata: { + description: "Does something.", + method: POST, // An `http::Method` constant. No imports required. + name: "some_endpoint", + path: "/_matrix/some/endpoint/:baz", + rate_limited: false, + requires_authentication: false, + } + + #[not_a_real_attribute_should_fail] + request: { + pub foo: String, + #[ruma_api(header = CONTENT_TYPE)] + pub content_type: String, + #[ruma_api(query)] + pub bar: String, + #[ruma_api(path)] + pub baz: String, + } + + response: { + pub value: String, + } +} + +fn main() {} diff --git a/ruma-api/tests/ui/04-attributes.stderr b/ruma-api/tests/ui/04-attributes.stderr new file mode 100644 index 00000000..e2bb1a28 --- /dev/null +++ b/ruma-api/tests/ui/04-attributes.stderr @@ -0,0 +1,5 @@ +error: cannot find attribute `not_a_real_attribute_should_fail` in this scope + --> $DIR/04-attributes.rs:13:7 + | +13 | #[not_a_real_attribute_should_fail] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^