Parse and emit attributes connected to the request/response defs in ruma_api macro
This commit is contained in:
parent
b68deabb86
commit
a6c1b8f0bd
@ -8,7 +8,7 @@ use syn::{
|
|||||||
braced,
|
braced,
|
||||||
parse::{Parse, ParseStream},
|
parse::{Parse, ParseStream},
|
||||||
spanned::Spanned,
|
spanned::Spanned,
|
||||||
Field, FieldValue, Token, Type,
|
Attribute, Field, FieldValue, Token, Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) mod attribute;
|
pub(crate) mod attribute;
|
||||||
@ -428,18 +428,21 @@ impl Parse for RawMetadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct RawRequest {
|
pub struct RawRequest {
|
||||||
|
pub attributes: Vec<Attribute>,
|
||||||
pub request_kw: kw::request,
|
pub request_kw: kw::request,
|
||||||
pub fields: Vec<Field>,
|
pub fields: Vec<Field>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for RawRequest {
|
impl Parse for RawRequest {
|
||||||
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
|
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
|
||||||
|
let attributes = input.call(Attribute::parse_outer)?;
|
||||||
let request_kw = input.parse::<kw::request>()?;
|
let request_kw = input.parse::<kw::request>()?;
|
||||||
input.parse::<Token![:]>()?;
|
input.parse::<Token![:]>()?;
|
||||||
let fields;
|
let fields;
|
||||||
braced!(fields in input);
|
braced!(fields in input);
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
attributes,
|
||||||
request_kw,
|
request_kw,
|
||||||
fields: fields
|
fields: fields
|
||||||
.parse_terminated::<Field, Token![,]>(Field::parse_named)?
|
.parse_terminated::<Field, Token![,]>(Field::parse_named)?
|
||||||
@ -450,18 +453,21 @@ impl Parse for RawRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct RawResponse {
|
pub struct RawResponse {
|
||||||
|
pub attributes: Vec<Attribute>,
|
||||||
pub response_kw: kw::response,
|
pub response_kw: kw::response,
|
||||||
pub fields: Vec<Field>,
|
pub fields: Vec<Field>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for RawResponse {
|
impl Parse for RawResponse {
|
||||||
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
|
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
|
||||||
|
let attributes = input.call(Attribute::parse_outer)?;
|
||||||
let response_kw = input.parse::<kw::response>()?;
|
let response_kw = input.parse::<kw::response>()?;
|
||||||
input.parse::<Token![:]>()?;
|
input.parse::<Token![:]>()?;
|
||||||
let fields;
|
let fields;
|
||||||
braced!(fields in input);
|
braced!(fields in input);
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
attributes,
|
||||||
response_kw,
|
response_kw,
|
||||||
fields: fields
|
fields: fields
|
||||||
.parse_terminated::<Field, Token![,]>(Field::parse_named)?
|
.parse_terminated::<Field, Token![,]>(Field::parse_named)?
|
||||||
|
@ -4,7 +4,7 @@ use std::{collections::BTreeSet, convert::TryFrom, mem};
|
|||||||
|
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::{quote, quote_spanned, ToTokens};
|
use quote::{quote, quote_spanned, ToTokens};
|
||||||
use syn::{spanned::Spanned, Field, Ident, Lifetime};
|
use syn::{spanned::Spanned, Attribute, Field, Ident, Lifetime};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
api::{
|
api::{
|
||||||
@ -24,6 +24,9 @@ pub struct RequestLifetimes {
|
|||||||
|
|
||||||
/// The result of processing the `request` section of the macro.
|
/// The result of processing the `request` section of the macro.
|
||||||
pub struct Request {
|
pub struct Request {
|
||||||
|
/// The attributes that will be applied to the struct definition.
|
||||||
|
attributes: Vec<Attribute>,
|
||||||
|
|
||||||
/// The fields of the request.
|
/// The fields of the request.
|
||||||
fields: Vec<RequestField>,
|
fields: Vec<RequestField>,
|
||||||
|
|
||||||
@ -382,13 +385,21 @@ impl TryFrom<RawRequest> 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 {
|
impl ToTokens for Request {
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
let import_path = &self.ruma_api_import;
|
let import_path = &self.ruma_api_import;
|
||||||
|
|
||||||
|
let struct_attributes = &self.attributes;
|
||||||
|
|
||||||
let request_def = if self.fields.is_empty() {
|
let request_def = if self.fields.is_empty() {
|
||||||
quote!(;)
|
quote!(;)
|
||||||
} else {
|
} else {
|
||||||
@ -484,6 +495,7 @@ impl ToTokens for Request {
|
|||||||
let request = quote! {
|
let request = quote! {
|
||||||
#[derive(Debug, Clone, #import_path::Outgoing)]
|
#[derive(Debug, Clone, #import_path::Outgoing)]
|
||||||
#[incoming_no_deserialize]
|
#[incoming_no_deserialize]
|
||||||
|
#( #struct_attributes )*
|
||||||
pub struct Request #request_generics #request_def
|
pub struct Request #request_generics #request_def
|
||||||
|
|
||||||
#request_body_struct
|
#request_body_struct
|
||||||
|
@ -4,7 +4,7 @@ use std::{convert::TryFrom, mem};
|
|||||||
|
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::{quote, quote_spanned, ToTokens};
|
use quote::{quote, quote_spanned, ToTokens};
|
||||||
use syn::{spanned::Spanned, Field, Ident};
|
use syn::{spanned::Spanned, Attribute, Field, Ident};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
api::{
|
api::{
|
||||||
@ -16,6 +16,9 @@ use crate::{
|
|||||||
|
|
||||||
/// The result of processing the `response` section of the macro.
|
/// The result of processing the `response` section of the macro.
|
||||||
pub struct Response {
|
pub struct Response {
|
||||||
|
/// The attributes that will be applied to the struct definition.
|
||||||
|
attributes: Vec<Attribute>,
|
||||||
|
|
||||||
/// The fields of the response.
|
/// The fields of the response.
|
||||||
fields: Vec<ResponseField>,
|
fields: Vec<ResponseField>,
|
||||||
|
|
||||||
@ -234,7 +237,7 @@ impl TryFrom<RawResponse> 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) {
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
let import_path = &self.ruma_api_import;
|
let import_path = &self.ruma_api_import;
|
||||||
|
|
||||||
|
let struct_attributes = &self.attributes;
|
||||||
|
|
||||||
let response_def = if self.fields.is_empty() {
|
let response_def = if self.fields.is_empty() {
|
||||||
quote!(;)
|
quote!(;)
|
||||||
} else {
|
} else {
|
||||||
@ -279,6 +284,7 @@ impl ToTokens for Response {
|
|||||||
let response = quote! {
|
let response = quote! {
|
||||||
#[derive(Debug, Clone, #import_path::Outgoing)]
|
#[derive(Debug, Clone, #import_path::Outgoing)]
|
||||||
#[incoming_no_deserialize]
|
#[incoming_no_deserialize]
|
||||||
|
#( #struct_attributes )*
|
||||||
pub struct Response #response_def
|
pub struct Response #response_def
|
||||||
|
|
||||||
#response_body_struct
|
#response_body_struct
|
||||||
|
@ -4,4 +4,5 @@ fn ui() {
|
|||||||
t.pass("tests/ui/01-api-sanity-check.rs");
|
t.pass("tests/ui/01-api-sanity-check.rs");
|
||||||
t.compile_fail("tests/ui/02-invalid-path.rs");
|
t.compile_fail("tests/ui/02-invalid-path.rs");
|
||||||
t.pass("tests/ui/03-move-value.rs");
|
t.pass("tests/ui/03-move-value.rs");
|
||||||
|
t.compile_fail("tests/ui/04-attributes.rs");
|
||||||
}
|
}
|
||||||
|
29
ruma-api/tests/ui/04-attributes.rs
Normal file
29
ruma-api/tests/ui/04-attributes.rs
Normal file
@ -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() {}
|
5
ruma-api/tests/ui/04-attributes.stderr
Normal file
5
ruma-api/tests/ui/04-attributes.stderr
Normal file
@ -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]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
Loading…
x
Reference in New Issue
Block a user