Skip to content

Commit

Permalink
Parse and emit attributes connected to the request/response defs in r…
Browse files Browse the repository at this point in the history
…uma_api macro
  • Loading branch information
DevinR528 committed Aug 13, 2020
1 parent b68deab commit a6c1b8f
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 5 deletions.
8 changes: 7 additions & 1 deletion ruma-api-macros/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -428,18 +428,21 @@ impl Parse for RawMetadata {
}

pub struct RawRequest {
pub attributes: Vec<Attribute>,
pub request_kw: kw::request,
pub fields: Vec<Field>,
}

impl Parse for RawRequest {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
let attributes = input.call(Attribute::parse_outer)?;
let request_kw = input.parse::<kw::request>()?;
input.parse::<Token![:]>()?;
let fields;
braced!(fields in input);

Ok(Self {
attributes,
request_kw,
fields: fields
.parse_terminated::<Field, Token![,]>(Field::parse_named)?
Expand All @@ -450,18 +453,21 @@ impl Parse for RawRequest {
}

pub struct RawResponse {
pub attributes: Vec<Attribute>,
pub response_kw: kw::response,
pub fields: Vec<Field>,
}

impl Parse for RawResponse {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
let attributes = input.call(Attribute::parse_outer)?;
let response_kw = input.parse::<kw::response>()?;
input.parse::<Token![:]>()?;
let fields;
braced!(fields in input);

Ok(Self {
attributes,
response_kw,
fields: fields
.parse_terminated::<Field, Token![,]>(Field::parse_named)?
Expand Down
16 changes: 14 additions & 2 deletions ruma-api-macros/src/api/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand All @@ -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<Attribute>,

/// The fields of the request.
fields: Vec<RequestField>,

Expand Down Expand Up @@ -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 {
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 {
Expand Down Expand Up @@ -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
Expand Down
10 changes: 8 additions & 2 deletions ruma-api-macros/src/api/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand All @@ -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<Attribute>,

/// The fields of the response.
fields: Vec<ResponseField>,

Expand Down Expand Up @@ -234,14 +237,16 @@ 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() })
}
}

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 {
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions ruma-api/tests/ruma_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
29 changes: 29 additions & 0 deletions ruma-api/tests/ui/04-attributes.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 5 additions & 0 deletions ruma-api/tests/ui/04-attributes.stderr
Original file line number Diff line number Diff line change
@@ -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]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

0 comments on commit a6c1b8f

Please sign in to comment.