macros: Refactor ResponseField
This commit is contained in:
parent
a59a648d04
commit
2dbaf19ded
@ -64,22 +64,22 @@ impl Response {
|
|||||||
fn has_body_fields(&self) -> bool {
|
fn has_body_fields(&self) -> bool {
|
||||||
self.fields
|
self.fields
|
||||||
.iter()
|
.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.
|
/// Whether or not this request has a single newtype body field.
|
||||||
fn has_newtype_body(&self) -> bool {
|
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.
|
/// Whether or not this request has a single raw body field.
|
||||||
fn has_raw_body(&self) -> bool {
|
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.
|
/// Whether or not this request has any data in the URL path.
|
||||||
fn has_header_fields(&self) -> bool {
|
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 {
|
fn expand_all(&self) -> TokenStream {
|
||||||
@ -127,10 +127,9 @@ impl Response {
|
|||||||
"This macro doesn't support generic types"
|
"This macro doesn't support generic types"
|
||||||
);
|
);
|
||||||
|
|
||||||
let newtype_body_fields = self
|
let newtype_body_fields = self.fields.iter().filter(|f| {
|
||||||
.fields
|
matches!(&f.kind, ResponseFieldKind::NewtypeBody | ResponseFieldKind::RawBody)
|
||||||
.iter()
|
});
|
||||||
.filter(|f| matches!(f, ResponseField::NewtypeBody(_) | ResponseField::RawBody(_)));
|
|
||||||
|
|
||||||
let has_newtype_body_field = match newtype_body_fields.count() {
|
let has_newtype_body_field = match newtype_body_fields.count() {
|
||||||
0 => false,
|
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 {
|
if has_newtype_body_field && has_body_fields {
|
||||||
return Err(syn::Error::new_spanned(
|
return Err(syn::Error::new_spanned(
|
||||||
&self.ident,
|
&self.ident,
|
||||||
@ -155,65 +155,60 @@ impl Response {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The types of fields that a response can have.
|
/// A field of the response struct.
|
||||||
enum ResponseField {
|
struct ResponseField {
|
||||||
|
inner: Field,
|
||||||
|
kind: ResponseFieldKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The kind of a response field.
|
||||||
|
enum ResponseFieldKind {
|
||||||
/// JSON data in the body of the response.
|
/// JSON data in the body of the response.
|
||||||
Body(Field),
|
Body,
|
||||||
|
|
||||||
/// Data in an HTTP header.
|
/// Data in an HTTP header.
|
||||||
Header(Field, Ident),
|
Header(Ident),
|
||||||
|
|
||||||
/// A specific data type in the body of the response.
|
/// A specific data type in the body of the response.
|
||||||
NewtypeBody(Field),
|
NewtypeBody,
|
||||||
|
|
||||||
/// Arbitrary bytes in the body of the response.
|
/// Arbitrary bytes in the body of the response.
|
||||||
RawBody(Field),
|
RawBody,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResponseField {
|
impl ResponseField {
|
||||||
/// Creates a new `ResponseField`.
|
/// Creates a new `ResponseField`.
|
||||||
fn new(field: Field, kind_attr: Option<ResponseMeta>) -> Self {
|
fn new(inner: Field, kind_attr: Option<ResponseMeta>) -> Self {
|
||||||
if let Some(attr) = kind_attr {
|
let kind = match kind_attr {
|
||||||
match attr {
|
Some(ResponseMeta::NewtypeBody) => ResponseFieldKind::NewtypeBody,
|
||||||
ResponseMeta::NewtypeBody => ResponseField::NewtypeBody(field),
|
Some(ResponseMeta::RawBody) => ResponseFieldKind::RawBody,
|
||||||
ResponseMeta::RawBody => ResponseField::RawBody(field),
|
Some(ResponseMeta::Header(header)) => ResponseFieldKind::Header(header),
|
||||||
ResponseMeta::Header(header) => ResponseField::Header(field, header),
|
None => ResponseFieldKind::Body,
|
||||||
}
|
};
|
||||||
} else {
|
|
||||||
ResponseField::Body(field)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the inner `Field` value.
|
Self { inner, kind }
|
||||||
fn field(&self) -> &Field {
|
|
||||||
match self {
|
|
||||||
ResponseField::Body(field)
|
|
||||||
| ResponseField::Header(field, _)
|
|
||||||
| ResponseField::NewtypeBody(field)
|
|
||||||
| ResponseField::RawBody(field) => field,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the contained field if this response field is a body kind.
|
/// Return the contained field if this response field is a body kind.
|
||||||
fn as_body_field(&self) -> Option<&Field> {
|
fn as_body_field(&self) -> Option<&Field> {
|
||||||
match self {
|
match &self.kind {
|
||||||
ResponseField::Body(field) | ResponseField::NewtypeBody(field) => Some(field),
|
ResponseFieldKind::Body | ResponseFieldKind::NewtypeBody => Some(&self.inner),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the contained field if this response field is a raw body kind.
|
/// Return the contained field if this response field is a raw body kind.
|
||||||
fn as_raw_body_field(&self) -> Option<&Field> {
|
fn as_raw_body_field(&self) -> Option<&Field> {
|
||||||
match self {
|
match &self.kind {
|
||||||
ResponseField::RawBody(field) => Some(field),
|
ResponseFieldKind::RawBody => Some(&self.inner),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the contained field and HTTP header ident if this response field is a header kind.
|
/// Return the contained field and HTTP header ident if this response field is a header kind.
|
||||||
fn as_header_field(&self) -> Option<(&Field, &Ident)> {
|
fn as_header_field(&self) -> Option<(&Field, &Ident)> {
|
||||||
match self {
|
match &self.kind {
|
||||||
ResponseField::Header(field, ident) => Some((field, ident)),
|
ResponseFieldKind::Header(ident) => Some((&self.inner, ident)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -257,7 +252,7 @@ impl Parse for ResponseField {
|
|||||||
|
|
||||||
impl ToTokens for ResponseField {
|
impl ToTokens for ResponseField {
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
self.field().to_tokens(tokens);
|
self.inner.to_tokens(tokens);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ use proc_macro2::TokenStream;
|
|||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::Type;
|
use syn::Type;
|
||||||
|
|
||||||
use super::{Response, ResponseField};
|
use super::{Response, ResponseFieldKind};
|
||||||
|
|
||||||
impl Response {
|
impl Response {
|
||||||
pub fn expand_incoming(&self, error_ty: &Type, ruma_common: &TokenStream) -> TokenStream {
|
pub fn expand_incoming(&self, error_ty: &Type, ruma_common: &TokenStream) -> TokenStream {
|
||||||
@ -38,20 +38,20 @@ impl Response {
|
|||||||
let mut raw_body = None;
|
let mut raw_body = None;
|
||||||
|
|
||||||
for response_field in &self.fields {
|
for response_field in &self.fields {
|
||||||
let field = response_field.field();
|
let field = &response_field.inner;
|
||||||
let field_name =
|
let field_name =
|
||||||
field.ident.as_ref().expect("expected field to have an identifier");
|
field.ident.as_ref().expect("expected field to have an identifier");
|
||||||
let cfg_attrs =
|
let cfg_attrs =
|
||||||
field.attrs.iter().filter(|a| a.path.is_ident("cfg")).collect::<Vec<_>>();
|
field.attrs.iter().filter(|a| a.path.is_ident("cfg")).collect::<Vec<_>>();
|
||||||
|
|
||||||
fields.push(match response_field {
|
fields.push(match &response_field.kind {
|
||||||
ResponseField::Body(_) | ResponseField::NewtypeBody(_) => {
|
ResponseFieldKind::Body | ResponseFieldKind::NewtypeBody => {
|
||||||
quote! {
|
quote! {
|
||||||
#( #cfg_attrs )*
|
#( #cfg_attrs )*
|
||||||
#field_name: response_body.#field_name
|
#field_name: response_body.#field_name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ResponseField::Header(_, header_name) => {
|
ResponseFieldKind::Header(header_name) => {
|
||||||
let optional_header = match &field.ty {
|
let optional_header = match &field.ty {
|
||||||
syn::Type::Path(syn::TypePath {
|
syn::Type::Path(syn::TypePath {
|
||||||
path: syn::Path { segments, .. },
|
path: syn::Path { segments, .. },
|
||||||
@ -81,7 +81,7 @@ impl Response {
|
|||||||
// This field must be instantiated last to avoid `use of move value` error.
|
// 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
|
// We are guaranteed only one new body field because of a check in
|
||||||
// `parse_response`.
|
// `parse_response`.
|
||||||
ResponseField::RawBody(_) => {
|
ResponseFieldKind::RawBody => {
|
||||||
raw_body = Some(quote! {
|
raw_body = Some(quote! {
|
||||||
#( #cfg_attrs )*
|
#( #cfg_attrs )*
|
||||||
#field_name: {
|
#field_name: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user