diff --git a/crates/ruma-common/src/api.rs b/crates/ruma-common/src/api.rs index c3dbbcf6..c2d71d28 100644 --- a/crates/ruma-common/src/api.rs +++ b/crates/ruma-common/src/api.rs @@ -232,6 +232,9 @@ pub use ruma_macros::ruma_api; /// not just JSON. The field type must be `Vec`. pub use ruma_macros::request; +// TODO: Write docs +pub use ruma_macros::response; + pub mod error; mod metadata; diff --git a/crates/ruma-macros/src/api/api_response.rs b/crates/ruma-macros/src/api/api_response.rs index c62d6826..0113fa7c 100644 --- a/crates/ruma-macros/src/api/api_response.rs +++ b/crates/ruma-macros/src/api/api_response.rs @@ -35,16 +35,7 @@ impl Response { let fields = &self.fields; quote! { #[doc = #docs] - #[derive( - Clone, - Debug, - #ruma_macros::Response, - #ruma_common::serde::Incoming, - #ruma_common::serde::_FakeDeriveSerde, - )] - #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] - #[incoming_derive(!Deserialize, #ruma_macros::_FakeDeriveRumaApi)] - #[ruma_api(error = #error_ty)] + #[#ruma_macros::response(error = #error_ty)] #( #struct_attributes )* pub struct #response_ident { #fields diff --git a/crates/ruma-macros/src/api/response.rs b/crates/ruma-macros/src/api/response.rs index f96d3831..ede58849 100644 --- a/crates/ruma-macros/src/api/response.rs +++ b/crates/ruma-macros/src/api/response.rs @@ -6,7 +6,7 @@ use syn::{ parse::{Parse, ParseStream}, punctuated::Punctuated, visit::Visit, - DeriveInput, Field, Generics, Ident, Lifetime, Token, Type, + DeriveInput, Field, Generics, Ident, ItemStruct, Lifetime, Token, Type, }; use super::attribute::{DeriveResponseMeta, ResponseMeta}; @@ -15,6 +15,42 @@ use crate::util::import_ruma_common; mod incoming; mod outgoing; +pub fn expand_response(attr: ResponseAttr, item: ItemStruct) -> TokenStream { + let ruma_common = import_ruma_common(); + let ruma_macros = quote! { #ruma_common::exports::ruma_macros }; + + let error_ty = attr + .0 + .iter() + .find_map(|a| match a { + DeriveResponseMeta::Error(ty) => Some(quote! { #ty }), + _ => None, + }) + .unwrap_or_else(|| quote! { #ruma_common::api::error::MatrixError }); + + quote! { + #[derive( + Clone, + Debug, + #ruma_macros::Response, + #ruma_common::serde::Incoming, + #ruma_common::serde::_FakeDeriveSerde, + )] + #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] + #[incoming_derive(!Deserialize, #ruma_macros::_FakeDeriveRumaApi)] + #[ruma_api(error = #error_ty)] + #item + } +} + +pub struct ResponseAttr(Punctuated); + +impl Parse for ResponseAttr { + fn parse(input: ParseStream<'_>) -> syn::Result { + Punctuated::::parse_terminated(input).map(Self) + } +} + pub fn expand_derive_response(input: DeriveInput) -> syn::Result { let fields = match input.data { syn::Data::Struct(s) => s.fields, diff --git a/crates/ruma-macros/src/lib.rs b/crates/ruma-macros/src/lib.rs index 4f7c8cc7..388bc9d3 100644 --- a/crates/ruma-macros/src/lib.rs +++ b/crates/ruma-macros/src/lib.rs @@ -27,7 +27,7 @@ mod util; use self::{ api::{ request::{expand_derive_request, expand_request}, - response::expand_derive_response, + response::{expand_derive_response, expand_response}, Api, }, events::{ @@ -397,6 +397,15 @@ pub fn request(attr: TokenStream, item: TokenStream) -> TokenStream { expand_request(attr, item).into() } +/// > ⚠ If this is the only documentation you see, please navigate to the docs for +/// > `ruma_common::api::response`, where actual documentation can be found. +#[proc_macro_attribute] +pub fn response(attr: TokenStream, item: TokenStream) -> TokenStream { + let attr = parse_macro_input!(attr); + let item = parse_macro_input!(item); + expand_response(attr, item).into() +} + /// Internal helper taking care of the request-specific parts of `ruma_api!`. #[proc_macro_derive(Request, attributes(ruma_api))] pub fn derive_request(input: TokenStream) -> TokenStream {