Revert "api: Remove error_ty from Request and Response derive attributes"

This reverts commit 1989e0350d61ca769b258ce5f2f48360dc4b3f3c.
This commit is contained in:
Jonas Platte 2022-10-24 14:03:10 +02:00
parent 54183bd748
commit 1be2def65a
No known key found for this signature in database
GPG Key ID: AAA7A61F696C3E0C
9 changed files with 142 additions and 51 deletions

View File

@ -74,8 +74,8 @@ impl Api {
|err_ty| quote! { #err_ty }, |err_ty| quote! { #err_ty },
); );
let request = self.request.map(|req| req.expand(metadata, &ruma_common)); let request = self.request.map(|req| req.expand(metadata, &error_ty, &ruma_common));
let response = self.response.map(|res| res.expand(metadata, &ruma_common)); let response = self.response.map(|res| res.expand(metadata, &error_ty, &ruma_common));
let metadata_doc = format!("Metadata for the `{}` API endpoint.", name.value()); let metadata_doc = format!("Metadata for the `{}` API endpoint.", name.value());
@ -93,11 +93,11 @@ impl Api {
history: #history, history: #history,
}; };
#[allow(unused)]
type EndpointError = #error_ty;
#request #request
#response #response
#[cfg(not(any(feature = "client", feature = "server")))]
type _SilenceUnusedError = #error_ty;
} }
} }

View File

@ -67,7 +67,12 @@ impl Request {
lifetimes lifetimes
} }
pub(super) fn expand(&self, metadata: &Metadata, ruma_common: &TokenStream) -> TokenStream { pub(super) fn expand(
&self,
metadata: &Metadata,
error_ty: &TokenStream,
ruma_common: &TokenStream,
) -> TokenStream {
let ruma_macros = quote! { #ruma_common::exports::ruma_macros }; let ruma_macros = quote! { #ruma_common::exports::ruma_macros };
let docs = format!( let docs = format!(
@ -93,6 +98,7 @@ impl Request {
)] )]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[incoming_derive(!Deserialize, #ruma_macros::_FakeDeriveRumaApi)] #[incoming_derive(!Deserialize, #ruma_macros::_FakeDeriveRumaApi)]
#[ruma_api(error_ty = #error_ty)]
#( #struct_attributes )* #( #struct_attributes )*
pub struct #request_ident < #(#lifetimes),* > { pub struct #request_ident < #(#lifetimes),* > {
#fields #fields

View File

@ -19,7 +19,12 @@ pub(crate) struct Response {
} }
impl Response { impl Response {
pub(super) fn expand(&self, metadata: &Metadata, ruma_common: &TokenStream) -> TokenStream { pub(super) fn expand(
&self,
metadata: &Metadata,
error_ty: &TokenStream,
ruma_common: &TokenStream,
) -> TokenStream {
let ruma_macros = quote! { #ruma_common::exports::ruma_macros }; let ruma_macros = quote! { #ruma_common::exports::ruma_macros };
let docs = let docs =
@ -39,6 +44,7 @@ impl Response {
)] )]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[incoming_derive(!Deserialize, #ruma_macros::_FakeDeriveRumaApi)] #[incoming_derive(!Deserialize, #ruma_macros::_FakeDeriveRumaApi)]
#[ruma_api(error_ty = #error_ty)]
#( #struct_attributes )* #( #struct_attributes )*
pub struct #response_ident { pub struct #response_ident {
#fields #fields

View File

@ -2,7 +2,7 @@
use syn::{ use syn::{
parse::{Parse, ParseStream}, parse::{Parse, ParseStream},
Ident, Token, Ident, Token, Type,
}; };
mod kw { mod kw {
@ -12,6 +12,8 @@ mod kw {
syn::custom_keyword!(query); syn::custom_keyword!(query);
syn::custom_keyword!(query_map); syn::custom_keyword!(query_map);
syn::custom_keyword!(header); syn::custom_keyword!(header);
syn::custom_keyword!(error_ty);
syn::custom_keyword!(manual_body_serde);
} }
pub enum RequestMeta { pub enum RequestMeta {
@ -51,6 +53,23 @@ impl Parse for RequestMeta {
} }
} }
pub enum DeriveRequestMeta {
ErrorTy(Type),
}
impl Parse for DeriveRequestMeta {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(kw::error_ty) {
let _: kw::error_ty = input.parse()?;
let _: Token![=] = input.parse()?;
input.parse().map(Self::ErrorTy)
} else {
Err(lookahead.error())
}
}
}
pub enum ResponseMeta { pub enum ResponseMeta {
NewtypeBody, NewtypeBody,
RawBody, RawBody,
@ -75,3 +94,25 @@ impl Parse for ResponseMeta {
} }
} }
} }
#[allow(clippy::large_enum_variant)]
pub enum DeriveResponseMeta {
ManualBodySerde,
ErrorTy(Type),
}
impl Parse for DeriveResponseMeta {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(kw::manual_body_serde) {
let _: kw::manual_body_serde = input.parse()?;
Ok(Self::ManualBodySerde)
} else if lookahead.peek(kw::error_ty) {
let _: kw::error_ty = input.parse()?;
let _: Token![=] = input.parse()?;
input.parse().map(Self::ErrorTy)
} else {
Err(lookahead.error())
}
}
}

View File

@ -4,10 +4,14 @@ use proc_macro2::TokenStream;
use quote::{quote, ToTokens}; use quote::{quote, ToTokens};
use syn::{ use syn::{
parse::{Parse, ParseStream}, parse::{Parse, ParseStream},
DeriveInput, Field, Generics, Ident, Lifetime, punctuated::Punctuated,
DeriveInput, Field, Generics, Ident, Lifetime, Token, Type,
}; };
use super::{attribute::RequestMeta, util::collect_lifetime_idents}; use super::{
attribute::{DeriveRequestMeta, RequestMeta},
util::collect_lifetime_idents,
};
use crate::util::import_ruma_common; use crate::util::import_ruma_common;
mod incoming; mod incoming;
@ -40,7 +44,29 @@ pub fn expand_derive_request(input: DeriveInput) -> syn::Result<TokenStream> {
}) })
.collect::<syn::Result<_>>()?; .collect::<syn::Result<_>>()?;
let request = Request { ident: input.ident, generics: input.generics, fields, lifetimes }; let mut error_ty = None;
for attr in input.attrs {
if !attr.path.is_ident("ruma_api") {
continue;
}
let metas =
attr.parse_args_with(Punctuated::<DeriveRequestMeta, Token![,]>::parse_terminated)?;
for meta in metas {
match meta {
DeriveRequestMeta::ErrorTy(t) => error_ty = Some(t),
}
}
}
let request = Request {
ident: input.ident,
generics: input.generics,
fields,
lifetimes,
error_ty: error_ty.expect("missing error_ty attribute"),
};
let ruma_common = import_ruma_common(); let ruma_common = import_ruma_common();
let test = request.check(&ruma_common)?; let test = request.check(&ruma_common)?;
@ -65,6 +91,8 @@ struct Request {
generics: Generics, generics: Generics,
lifetimes: RequestLifetimes, lifetimes: RequestLifetimes,
fields: Vec<RequestField>, fields: Vec<RequestField>,
error_ty: Type,
} }
impl Request { impl Request {

View File

@ -10,6 +10,8 @@ impl Request {
let serde = quote! { #ruma_common::exports::serde }; let serde = quote! { #ruma_common::exports::serde };
let serde_json = quote! { #ruma_common::exports::serde_json }; let serde_json = quote! { #ruma_common::exports::serde_json };
let error_ty = &self.error_ty;
let incoming_request_type = if self.has_lifetimes() { let incoming_request_type = if self.has_lifetimes() {
quote! { IncomingRequest } quote! { IncomingRequest }
} else { } else {
@ -178,7 +180,7 @@ impl Request {
#[automatically_derived] #[automatically_derived]
#[cfg(feature = "server")] #[cfg(feature = "server")]
impl #ruma_common::api::IncomingRequest for #incoming_request_type { impl #ruma_common::api::IncomingRequest for #incoming_request_type {
type EndpointError = self::EndpointError; type EndpointError = #error_ty;
type OutgoingResponse = Response; type OutgoingResponse = Response;
const METADATA: #ruma_common::api::Metadata = METADATA; const METADATA: #ruma_common::api::Metadata = METADATA;

View File

@ -9,6 +9,8 @@ impl Request {
let bytes = quote! { #ruma_common::exports::bytes }; let bytes = quote! { #ruma_common::exports::bytes };
let http = quote! { #ruma_common::exports::http }; let http = quote! { #ruma_common::exports::http };
let error_ty = &self.error_ty;
let path_fields = let path_fields =
self.path_fields().map(|f| f.ident.as_ref().expect("path fields have a name")); self.path_fields().map(|f| f.ident.as_ref().expect("path fields have a name"));
@ -122,7 +124,7 @@ impl Request {
#[automatically_derived] #[automatically_derived]
#[cfg(feature = "client")] #[cfg(feature = "client")]
impl #impl_generics #ruma_common::api::OutgoingRequest for Request #ty_generics #where_clause { impl #impl_generics #ruma_common::api::OutgoingRequest for Request #ty_generics #where_clause {
type EndpointError = self::EndpointError; type EndpointError = #error_ty;
type IncomingResponse = Response; type IncomingResponse = Response;
const METADATA: #ruma_common::api::Metadata = METADATA; const METADATA: #ruma_common::api::Metadata = METADATA;

View File

@ -4,20 +4,17 @@ use proc_macro2::TokenStream;
use quote::{quote, ToTokens}; use quote::{quote, ToTokens};
use syn::{ use syn::{
parse::{Parse, ParseStream}, parse::{Parse, ParseStream},
punctuated::Punctuated,
visit::Visit, visit::Visit,
DeriveInput, Field, Generics, Ident, Lifetime, Type, DeriveInput, Field, Generics, Ident, Lifetime, Token, Type,
}; };
use super::attribute::ResponseMeta; use super::attribute::{DeriveResponseMeta, ResponseMeta};
use crate::util::import_ruma_common; use crate::util::import_ruma_common;
mod incoming; mod incoming;
mod outgoing; mod outgoing;
mod kw {
syn::custom_keyword!(manual_body_serde);
}
pub fn expand_derive_response(input: DeriveInput) -> syn::Result<TokenStream> { pub fn expand_derive_response(input: DeriveInput) -> syn::Result<TokenStream> {
let fields = match input.data { let fields = match input.data {
syn::Data::Struct(s) => s.fields, syn::Data::Struct(s) => s.fields,
@ -26,18 +23,29 @@ pub fn expand_derive_response(input: DeriveInput) -> syn::Result<TokenStream> {
let fields = fields.into_iter().map(ResponseField::try_from).collect::<syn::Result<_>>()?; let fields = fields.into_iter().map(ResponseField::try_from).collect::<syn::Result<_>>()?;
let mut manual_body_serde = false; let mut manual_body_serde = false;
let mut error_ty = None;
for attr in input.attrs { for attr in input.attrs {
if !attr.path.is_ident("ruma_api") { if !attr.path.is_ident("ruma_api") {
continue; continue;
} }
let _ = attr.parse_args::<kw::manual_body_serde>()?; let metas =
attr.parse_args_with(Punctuated::<DeriveResponseMeta, Token![,]>::parse_terminated)?;
manual_body_serde = true; for meta in metas {
match meta {
DeriveResponseMeta::ManualBodySerde => manual_body_serde = true,
DeriveResponseMeta::ErrorTy(t) => error_ty = Some(t),
}
}
} }
let response = let response = Response {
Response { ident: input.ident, generics: input.generics, fields, manual_body_serde }; ident: input.ident,
generics: input.generics,
fields,
manual_body_serde,
error_ty: error_ty.unwrap(),
};
response.check()?; response.check()?;
Ok(response.expand_all()) Ok(response.expand_all())
@ -48,6 +56,7 @@ struct Response {
generics: Generics, generics: Generics,
fields: Vec<ResponseField>, fields: Vec<ResponseField>,
manual_body_serde: bool, manual_body_serde: bool,
error_ty: Type,
} }
impl Response { impl Response {
@ -100,7 +109,7 @@ impl Response {
}); });
let outgoing_response_impl = self.expand_outgoing(&ruma_common); let outgoing_response_impl = self.expand_outgoing(&ruma_common);
let incoming_response_impl = self.expand_incoming(&ruma_common); let incoming_response_impl = self.expand_incoming(&self.error_ty, &ruma_common);
quote! { quote! {
#response_body_struct #response_body_struct

View File

@ -1,10 +1,11 @@
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::quote; use quote::quote;
use syn::Type;
use super::{Response, ResponseFieldKind}; use super::{Response, ResponseFieldKind};
impl Response { impl Response {
pub fn expand_incoming(&self, ruma_common: &TokenStream) -> TokenStream { pub fn expand_incoming(&self, error_ty: &Type, ruma_common: &TokenStream) -> TokenStream {
let http = quote! { #ruma_common::exports::http }; let http = quote! { #ruma_common::exports::http };
let serde_json = quote! { #ruma_common::exports::serde_json }; let serde_json = quote! { #ruma_common::exports::serde_json };
@ -103,7 +104,18 @@ impl Response {
} }
}; };
let method_body = quote! { quote! {
#[automatically_derived]
#[cfg(feature = "client")]
impl #ruma_common::api::IncomingResponse for Response {
type EndpointError = #error_ty;
fn try_from_http_response<T: ::std::convert::AsRef<[::std::primitive::u8]>>(
response: #http::Response<T>,
) -> ::std::result::Result<
Self,
#ruma_common::api::error::FromHttpResponseError<#error_ty>,
> {
if response.status().as_u16() < 400 { if response.status().as_u16() < 400 {
#extract_response_headers #extract_response_headers
#typed_response_body_decl #typed_response_body_decl
@ -112,7 +124,7 @@ impl Response {
#response_init_fields #response_init_fields
}) })
} else { } else {
match <EndpointError as #ruma_common::api::EndpointError>::try_from_http_response( match <#error_ty as #ruma_common::api::EndpointError>::try_from_http_response(
response response
) { ) {
::std::result::Result::Ok(err) => { ::std::result::Result::Ok(err) => {
@ -123,21 +135,6 @@ impl Response {
} }
} }
} }
};
quote! {
#[automatically_derived]
#[cfg(feature = "client")]
impl #ruma_common::api::IncomingResponse for Response {
type EndpointError = EndpointError;
fn try_from_http_response<T: ::std::convert::AsRef<[::std::primitive::u8]>>(
response: #http::Response<T>,
) -> ::std::result::Result<
Self,
#ruma_common::api::error::FromHttpResponseError<EndpointError>,
> {
#method_body
} }
} }
} }