From 2dbaf19ded08c7570d94ad5f16310c677d3fb301 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Mon, 26 Sep 2022 16:03:05 +0200 Subject: [PATCH] macros: Refactor ResponseField --- crates/ruma-macros/src/api/response.rs | 77 +++++++++---------- .../ruma-macros/src/api/response/incoming.rs | 12 +-- 2 files changed, 42 insertions(+), 47 deletions(-) diff --git a/crates/ruma-macros/src/api/response.rs b/crates/ruma-macros/src/api/response.rs index 734f8783..01eeb5fb 100644 --- a/crates/ruma-macros/src/api/response.rs +++ b/crates/ruma-macros/src/api/response.rs @@ -64,22 +64,22 @@ impl Response { fn has_body_fields(&self) -> bool { self.fields .iter() - .any(|f| matches!(f, ResponseField::Body(_) | &ResponseField::NewtypeBody(_))) + .any(|f| matches!(&f.kind, ResponseFieldKind::Body | &ResponseFieldKind::NewtypeBody)) } /// Whether or not this request has a single newtype body field. fn has_newtype_body(&self) -> bool { - self.fields.iter().any(|f| matches!(f, ResponseField::NewtypeBody(_))) + self.fields.iter().any(|f| matches!(&f.kind, ResponseFieldKind::NewtypeBody)) } /// Whether or not this request has a single raw body field. fn has_raw_body(&self) -> bool { - self.fields.iter().any(|f| matches!(f, ResponseField::RawBody(_))) + self.fields.iter().any(|f| matches!(&f.kind, ResponseFieldKind::RawBody)) } /// Whether or not this request has any data in the URL path. fn has_header_fields(&self) -> bool { - self.fields.iter().any(|f| matches!(f, &ResponseField::Header(..))) + self.fields.iter().any(|f| matches!(&f.kind, &ResponseFieldKind::Header(_))) } fn expand_all(&self) -> TokenStream { @@ -127,10 +127,9 @@ impl Response { "This macro doesn't support generic types" ); - let newtype_body_fields = self - .fields - .iter() - .filter(|f| matches!(f, ResponseField::NewtypeBody(_) | ResponseField::RawBody(_))); + let newtype_body_fields = self.fields.iter().filter(|f| { + matches!(&f.kind, ResponseFieldKind::NewtypeBody | ResponseFieldKind::RawBody) + }); let has_newtype_body_field = match newtype_body_fields.count() { 0 => false, @@ -143,7 +142,8 @@ impl Response { } }; - let has_body_fields = self.fields.iter().any(|f| matches!(f, ResponseField::Body(_))); + let has_body_fields = + self.fields.iter().any(|f| matches!(&f.kind, ResponseFieldKind::Body)); if has_newtype_body_field && has_body_fields { return Err(syn::Error::new_spanned( &self.ident, @@ -155,65 +155,60 @@ impl Response { } } -/// The types of fields that a response can have. -enum ResponseField { +/// A field of the response struct. +struct ResponseField { + inner: Field, + kind: ResponseFieldKind, +} + +/// The kind of a response field. +enum ResponseFieldKind { /// JSON data in the body of the response. - Body(Field), + Body, /// Data in an HTTP header. - Header(Field, Ident), + Header(Ident), /// A specific data type in the body of the response. - NewtypeBody(Field), + NewtypeBody, /// Arbitrary bytes in the body of the response. - RawBody(Field), + RawBody, } impl ResponseField { /// Creates a new `ResponseField`. - fn new(field: Field, kind_attr: Option) -> Self { - if let Some(attr) = kind_attr { - match attr { - ResponseMeta::NewtypeBody => ResponseField::NewtypeBody(field), - ResponseMeta::RawBody => ResponseField::RawBody(field), - ResponseMeta::Header(header) => ResponseField::Header(field, header), - } - } else { - ResponseField::Body(field) - } - } + fn new(inner: Field, kind_attr: Option) -> Self { + let kind = match kind_attr { + Some(ResponseMeta::NewtypeBody) => ResponseFieldKind::NewtypeBody, + Some(ResponseMeta::RawBody) => ResponseFieldKind::RawBody, + Some(ResponseMeta::Header(header)) => ResponseFieldKind::Header(header), + None => ResponseFieldKind::Body, + }; - /// Gets the inner `Field` value. - fn field(&self) -> &Field { - match self { - ResponseField::Body(field) - | ResponseField::Header(field, _) - | ResponseField::NewtypeBody(field) - | ResponseField::RawBody(field) => field, - } + Self { inner, kind } } /// Return the contained field if this response field is a body kind. fn as_body_field(&self) -> Option<&Field> { - match self { - ResponseField::Body(field) | ResponseField::NewtypeBody(field) => Some(field), + match &self.kind { + ResponseFieldKind::Body | ResponseFieldKind::NewtypeBody => Some(&self.inner), _ => None, } } /// Return the contained field if this response field is a raw body kind. fn as_raw_body_field(&self) -> Option<&Field> { - match self { - ResponseField::RawBody(field) => Some(field), + match &self.kind { + ResponseFieldKind::RawBody => Some(&self.inner), _ => None, } } /// Return the contained field and HTTP header ident if this response field is a header kind. fn as_header_field(&self) -> Option<(&Field, &Ident)> { - match self { - ResponseField::Header(field, ident) => Some((field, ident)), + match &self.kind { + ResponseFieldKind::Header(ident) => Some((&self.inner, ident)), _ => None, } } @@ -257,7 +252,7 @@ impl Parse for ResponseField { impl ToTokens for ResponseField { fn to_tokens(&self, tokens: &mut TokenStream) { - self.field().to_tokens(tokens); + self.inner.to_tokens(tokens); } } diff --git a/crates/ruma-macros/src/api/response/incoming.rs b/crates/ruma-macros/src/api/response/incoming.rs index 2c21ee62..4641ea6b 100644 --- a/crates/ruma-macros/src/api/response/incoming.rs +++ b/crates/ruma-macros/src/api/response/incoming.rs @@ -2,7 +2,7 @@ use proc_macro2::TokenStream; use quote::quote; use syn::Type; -use super::{Response, ResponseField}; +use super::{Response, ResponseFieldKind}; impl Response { pub fn expand_incoming(&self, error_ty: &Type, ruma_common: &TokenStream) -> TokenStream { @@ -38,20 +38,20 @@ impl Response { let mut raw_body = None; for response_field in &self.fields { - let field = response_field.field(); + let field = &response_field.inner; let field_name = field.ident.as_ref().expect("expected field to have an identifier"); let cfg_attrs = field.attrs.iter().filter(|a| a.path.is_ident("cfg")).collect::>(); - fields.push(match response_field { - ResponseField::Body(_) | ResponseField::NewtypeBody(_) => { + fields.push(match &response_field.kind { + ResponseFieldKind::Body | ResponseFieldKind::NewtypeBody => { quote! { #( #cfg_attrs )* #field_name: response_body.#field_name } } - ResponseField::Header(_, header_name) => { + ResponseFieldKind::Header(header_name) => { let optional_header = match &field.ty { syn::Type::Path(syn::TypePath { path: syn::Path { segments, .. }, @@ -81,7 +81,7 @@ impl Response { // This field must be instantiated last to avoid `use of move value` error. // We are guaranteed only one new body field because of a check in // `parse_response`. - ResponseField::RawBody(_) => { + ResponseFieldKind::RawBody => { raw_body = Some(quote! { #( #cfg_attrs )* #field_name: {