macros: Refactor RequestField

This commit is contained in:
Jonas Platte 2022-09-26 15:48:45 +02:00
parent 82dd050277
commit a59a648d04
No known key found for this signature in database
GPG Key ID: AAA7A61F696C3E0C
3 changed files with 67 additions and 76 deletions

View File

@ -30,16 +30,16 @@ pub fn expand_derive_request(input: DeriveInput) -> syn::Result<TokenStream> {
.into_iter() .into_iter()
.map(|f| { .map(|f| {
let f = RequestField::try_from(f)?; let f = RequestField::try_from(f)?;
let ty = &f.field().ty; let ty = &f.inner.ty;
match &f { match &f.kind {
RequestField::Header(..) => collect_lifetime_idents(&mut lifetimes.header, ty), RequestFieldKind::Header(_) => collect_lifetime_idents(&mut lifetimes.header, ty),
RequestField::Body(_) => collect_lifetime_idents(&mut lifetimes.body, ty), RequestFieldKind::Body => collect_lifetime_idents(&mut lifetimes.body, ty),
RequestField::NewtypeBody(_) => collect_lifetime_idents(&mut lifetimes.body, ty), RequestFieldKind::NewtypeBody => collect_lifetime_idents(&mut lifetimes.body, ty),
RequestField::RawBody(_) => collect_lifetime_idents(&mut lifetimes.body, ty), RequestFieldKind::RawBody => collect_lifetime_idents(&mut lifetimes.body, ty),
RequestField::Path(_) => collect_lifetime_idents(&mut lifetimes.path, ty), RequestFieldKind::Path => collect_lifetime_idents(&mut lifetimes.path, ty),
RequestField::Query(_) => collect_lifetime_idents(&mut lifetimes.query, ty), RequestFieldKind::Query => collect_lifetime_idents(&mut lifetimes.query, ty),
RequestField::QueryMap(_) => collect_lifetime_idents(&mut lifetimes.query, ty), RequestFieldKind::QueryMap => collect_lifetime_idents(&mut lifetimes.query, ty),
} }
Ok(f) Ok(f)
@ -119,23 +119,23 @@ impl Request {
fn has_body_fields(&self) -> bool { fn has_body_fields(&self) -> bool {
self.fields self.fields
.iter() .iter()
.any(|f| matches!(f, RequestField::Body(_) | RequestField::NewtypeBody(_))) .any(|f| matches!(&f.kind, RequestFieldKind::Body | RequestFieldKind::NewtypeBody))
} }
fn has_newtype_body(&self) -> bool { fn has_newtype_body(&self) -> bool {
self.fields.iter().any(|f| matches!(f, RequestField::NewtypeBody(_))) self.fields.iter().any(|f| matches!(&f.kind, RequestFieldKind::NewtypeBody))
} }
fn has_header_fields(&self) -> bool { fn has_header_fields(&self) -> bool {
self.fields.iter().any(|f| matches!(f, RequestField::Header(..))) self.fields.iter().any(|f| matches!(&f.kind, RequestFieldKind::Header(_)))
} }
fn has_path_fields(&self) -> bool { fn has_path_fields(&self) -> bool {
self.fields.iter().any(|f| matches!(f, RequestField::Path(_))) self.fields.iter().any(|f| matches!(&f.kind, RequestFieldKind::Path))
} }
fn has_query_fields(&self) -> bool { fn has_query_fields(&self) -> bool {
self.fields.iter().any(|f| matches!(f, RequestField::Query(_))) self.fields.iter().any(|f| matches!(&f.kind, RequestFieldKind::Query))
} }
fn has_lifetimes(&self) -> bool { fn has_lifetimes(&self) -> bool {
@ -145,8 +145,8 @@ impl Request {
&& self.lifetimes.header.is_empty()) && self.lifetimes.header.is_empty())
} }
fn header_fields(&self) -> impl Iterator<Item = &RequestField> { fn header_fields(&self) -> impl Iterator<Item = (&Field, &Ident)> {
self.fields.iter().filter(|f| matches!(f, RequestField::Header(..))) self.fields.iter().filter_map(RequestField::as_header_field)
} }
fn path_fields_ordered(&self) -> impl Iterator<Item = &Field> { fn path_fields_ordered(&self) -> impl Iterator<Item = &Field> {
@ -259,8 +259,8 @@ impl Request {
self.check_path(&path_fields, self.r0_path.as_ref())?; self.check_path(&path_fields, self.r0_path.as_ref())?;
self.check_path(&path_fields, self.stable_path.as_ref())?; self.check_path(&path_fields, self.stable_path.as_ref())?;
let newtype_body_fields = self.fields.iter().filter(|field| { let newtype_body_fields = self.fields.iter().filter(|f| {
matches!(field, RequestField::NewtypeBody(_) | RequestField::RawBody(_)) matches!(&f.kind, RequestFieldKind::NewtypeBody | RequestFieldKind::RawBody)
}); });
let has_newtype_body_field = match newtype_body_fields.count() { let has_newtype_body_field = match newtype_body_fields.count() {
@ -275,7 +275,7 @@ impl Request {
}; };
let query_map_fields = let query_map_fields =
self.fields.iter().filter(|f| matches!(f, RequestField::QueryMap(_))); self.fields.iter().filter(|f| matches!(&f.kind, RequestFieldKind::QueryMap));
let has_query_map_field = match query_map_fields.count() { let has_query_map_field = match query_map_fields.count() {
0 => false, 0 => false,
1 => true, 1 => true,
@ -287,8 +287,9 @@ impl Request {
} }
}; };
let has_body_fields = self.fields.iter().any(|f| matches!(f, RequestField::Body(_))); let has_body_fields = self.fields.iter().any(|f| matches!(&f.kind, RequestFieldKind::Body));
let has_query_fields = self.fields.iter().any(|f| matches!(f, RequestField::Query(_))); let has_query_fields =
self.fields.iter().any(|f| matches!(&f.kind, RequestFieldKind::Query));
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(
@ -365,97 +366,97 @@ impl Request {
} }
} }
/// The types of fields that a request can have. /// A field of the request struct.
enum RequestField { struct RequestField {
inner: Field,
kind: RequestFieldKind,
}
/// The kind of a request field.
enum RequestFieldKind {
/// JSON data in the body of the request. /// JSON data in the body of the request.
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 request. /// A specific data type in the body of the request.
NewtypeBody(Field), NewtypeBody,
/// Arbitrary bytes in the body of the request. /// Arbitrary bytes in the body of the request.
RawBody(Field), RawBody,
/// Data that appears in the URL path. /// Data that appears in the URL path.
Path(Field), Path,
/// Data that appears in the query string. /// Data that appears in the query string.
Query(Field), Query,
/// Data that appears in the query string as dynamic key-value pairs. /// Data that appears in the query string as dynamic key-value pairs.
QueryMap(Field), QueryMap,
} }
impl RequestField { impl RequestField {
/// Creates a new `RequestField`. /// Creates a new `RequestField`.
fn new(field: Field, kind_attr: Option<RequestMeta>) -> Self { fn new(inner: Field, kind_attr: Option<RequestMeta>) -> Self {
if let Some(attr) = kind_attr { let kind = match kind_attr {
match attr { Some(RequestMeta::NewtypeBody) => RequestFieldKind::NewtypeBody,
RequestMeta::NewtypeBody => RequestField::NewtypeBody(field), Some(RequestMeta::RawBody) => RequestFieldKind::RawBody,
RequestMeta::RawBody => RequestField::RawBody(field), Some(RequestMeta::Path) => RequestFieldKind::Path,
RequestMeta::Path => RequestField::Path(field), Some(RequestMeta::Query) => RequestFieldKind::Query,
RequestMeta::Query => RequestField::Query(field), Some(RequestMeta::QueryMap) => RequestFieldKind::QueryMap,
RequestMeta::QueryMap => RequestField::QueryMap(field), Some(RequestMeta::Header(header)) => RequestFieldKind::Header(header),
RequestMeta::Header(header) => RequestField::Header(field, header), None => RequestFieldKind::Body,
} };
} else {
RequestField::Body(field) Self { inner, kind }
}
} }
/// Return the contained field if this request field is a body kind. /// Return the contained field if this request field is a body kind.
pub fn as_body_field(&self) -> Option<&Field> { pub fn as_body_field(&self) -> Option<&Field> {
match self { match &self.kind {
RequestField::Body(field) | RequestField::NewtypeBody(field) => Some(field), RequestFieldKind::Body | RequestFieldKind::NewtypeBody => Some(&self.inner),
_ => None, _ => None,
} }
} }
/// Return the contained field if this request field is a raw body kind. /// Return the contained field if this request field is a raw body kind.
pub fn as_raw_body_field(&self) -> Option<&Field> { pub fn as_raw_body_field(&self) -> Option<&Field> {
match self { match &self.kind {
RequestField::RawBody(field) => Some(field), RequestFieldKind::RawBody => Some(&self.inner),
_ => None, _ => None,
} }
} }
/// Return the contained field if this request field is a path kind. /// Return the contained field if this request field is a path kind.
pub fn as_path_field(&self) -> Option<&Field> { pub fn as_path_field(&self) -> Option<&Field> {
match self { match &self.kind {
RequestField::Path(field) => Some(field), RequestFieldKind::Path => Some(&self.inner),
_ => None, _ => None,
} }
} }
/// Return the contained field if this request field is a query kind. /// Return the contained field if this request field is a query kind.
pub fn as_query_field(&self) -> Option<&Field> { pub fn as_query_field(&self) -> Option<&Field> {
match self { match &self.kind {
RequestField::Query(field) => Some(field), RequestFieldKind::Query => Some(&self.inner),
_ => None, _ => None,
} }
} }
/// Return the contained field if this request field is a query map kind. /// Return the contained field if this request field is a query map kind.
pub fn as_query_map_field(&self) -> Option<&Field> { pub fn as_query_map_field(&self) -> Option<&Field> {
match self { match &self.kind {
RequestField::QueryMap(field) => Some(field), RequestFieldKind::QueryMap => Some(&self.inner),
_ => None, _ => None,
} }
} }
/// Gets the inner `Field` value. /// Return the contained field and header ident if this request field is a header kind.
pub fn field(&self) -> &Field { pub fn as_header_field(&self) -> Option<(&Field, &Ident)> {
match self { match &self.kind {
RequestField::Body(field) RequestFieldKind::Header(header_name) => Some((&self.inner, header_name)),
| RequestField::Header(field, _) _ => None,
| RequestField::NewtypeBody(field)
| RequestField::RawBody(field)
| RequestField::Path(field)
| RequestField::Query(field)
| RequestField::QueryMap(field) => field,
} }
} }
} }
@ -491,6 +492,6 @@ impl Parse for RequestField {
impl ToTokens for RequestField { impl ToTokens for RequestField {
fn to_tokens(&self, tokens: &mut TokenStream) { fn to_tokens(&self, tokens: &mut TokenStream) {
self.field().to_tokens(tokens); self.inner.to_tokens(tokens);
} }
} }

View File

@ -86,12 +86,7 @@ impl Request {
let (parse_headers, header_vars) = if self.has_header_fields() { let (parse_headers, header_vars) = if self.has_header_fields() {
let (decls, names): (TokenStream, Vec<_>) = self let (decls, names): (TokenStream, Vec<_>) = self
.header_fields() .header_fields()
.map(|request_field| { .map(|(field, header_name)| {
let (field, header_name) = match request_field {
RequestField::Header(field, header_name) => (field, header_name),
_ => panic!("expected request field to be header variant"),
};
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<_>>();

View File

@ -100,12 +100,7 @@ impl Request {
TokenStream::new() TokenStream::new()
}; };
header_kvs.extend(self.header_fields().map(|request_field| { header_kvs.extend(self.header_fields().map(|(field, header_name)| {
let (field, header_name) = match request_field {
RequestField::Header(field, header_name) => (field, header_name),
_ => unreachable!("expected request field to be header variant"),
};
let field_name = &field.ident; let field_name = &field.ident;
match &field.ty { match &field.ty {