macros: Simplify Incoming derive implementation
This commit is contained in:
parent
a6a530dcc8
commit
5a791b3c6e
@ -4,32 +4,49 @@ use syn::{
|
|||||||
parse::{Parse, ParseStream},
|
parse::{Parse, ParseStream},
|
||||||
parse_quote,
|
parse_quote,
|
||||||
punctuated::Punctuated,
|
punctuated::Punctuated,
|
||||||
AngleBracketedGenericArguments, Attribute, Data, DeriveInput, Field, Fields, GenericArgument,
|
AngleBracketedGenericArguments, Attribute, Data, DeriveInput, GenericArgument, GenericParam,
|
||||||
GenericParam, Generics, Ident, ImplGenerics, ParenthesizedGenericArguments, Path,
|
Generics, Ident, ParenthesizedGenericArguments, Path, PathArguments, Token, Type, TypePath,
|
||||||
PathArguments, Token, Type, TypeGenerics, TypePath, TypeReference, TypeSlice, Variant,
|
TypeReference, TypeSlice,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::util::import_ruma_common;
|
use crate::util::import_ruma_common;
|
||||||
|
|
||||||
enum StructKind {
|
pub fn expand_derive_incoming(mut ty_def: DeriveInput) -> syn::Result<TokenStream> {
|
||||||
Struct,
|
|
||||||
Tuple,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum DataKind {
|
|
||||||
Struct(Vec<Field>, StructKind),
|
|
||||||
Enum(Vec<Variant>),
|
|
||||||
Unit,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn expand_derive_incoming(input: DeriveInput) -> syn::Result<TokenStream> {
|
|
||||||
let ruma_common = import_ruma_common();
|
let ruma_common = import_ruma_common();
|
||||||
|
|
||||||
|
let mut found_lifetime = false;
|
||||||
|
match &mut ty_def.data {
|
||||||
|
Data::Union(_) => panic!("#[derive(Incoming)] does not support Union types"),
|
||||||
|
Data::Enum(e) => {
|
||||||
|
for var in &mut e.variants {
|
||||||
|
for field in &mut var.fields {
|
||||||
|
if strip_lifetimes(&mut field.ty) {
|
||||||
|
found_lifetime = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Data::Struct(s) => {
|
||||||
|
for field in &mut s.fields {
|
||||||
|
if !matches!(field.vis, syn::Visibility::Public(_)) {
|
||||||
|
return Err(syn::Error::new_spanned(field, "All fields must be marked `pub`"));
|
||||||
|
}
|
||||||
|
if strip_lifetimes(&mut field.ty) {
|
||||||
|
found_lifetime = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found_lifetime {
|
||||||
|
return Ok(TokenStream::new());
|
||||||
|
}
|
||||||
|
|
||||||
let mut derives = vec![quote! { Debug }];
|
let mut derives = vec![quote! { Debug }];
|
||||||
let mut derive_deserialize = true;
|
let mut derive_deserialize = true;
|
||||||
|
|
||||||
derives.extend(
|
derives.extend(
|
||||||
input
|
ty_def
|
||||||
.attrs
|
.attrs
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|attr| attr.path.is_ident("incoming_derive"))
|
.filter(|attr| attr.path.is_ident("incoming_derive"))
|
||||||
@ -52,86 +69,17 @@ pub fn expand_derive_incoming(input: DeriveInput) -> syn::Result<TokenStream> {
|
|||||||
quote! { #ruma_common::serde::_FakeDeriveSerde }
|
quote! { #ruma_common::serde::_FakeDeriveSerde }
|
||||||
});
|
});
|
||||||
|
|
||||||
let input_attrs =
|
ty_def.attrs.retain(filter_input_attrs);
|
||||||
input.attrs.iter().filter(|attr| filter_input_attrs(attr)).collect::<Vec<_>>();
|
clean_generics(&mut ty_def.generics);
|
||||||
|
|
||||||
let data = match input.data.clone() {
|
let doc = format!("'Incoming' variant of [{}].", &ty_def.ident);
|
||||||
Data::Union(_) => panic!("#[derive(Incoming)] does not support Union types"),
|
ty_def.ident = format_ident!("Incoming{}", ty_def.ident, span = Span::call_site());
|
||||||
Data::Enum(e) => DataKind::Enum(e.variants.into_iter().collect()),
|
|
||||||
Data::Struct(s) => match s.fields {
|
|
||||||
Fields::Named(fs) => {
|
|
||||||
DataKind::Struct(fs.named.into_iter().collect(), StructKind::Struct)
|
|
||||||
}
|
|
||||||
Fields::Unnamed(fs) => {
|
|
||||||
DataKind::Struct(fs.unnamed.into_iter().collect(), StructKind::Tuple)
|
|
||||||
}
|
|
||||||
Fields::Unit => DataKind::Unit,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
match data {
|
|
||||||
DataKind::Unit => Ok(TokenStream::new()),
|
|
||||||
DataKind::Enum(mut vars) => {
|
|
||||||
let mut found_lifetime = false;
|
|
||||||
for var in &mut vars {
|
|
||||||
for field in &mut var.fields {
|
|
||||||
if strip_lifetimes(&mut field.ty) {
|
|
||||||
found_lifetime = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !found_lifetime {
|
|
||||||
return Ok(TokenStream::new());
|
|
||||||
}
|
|
||||||
|
|
||||||
let vis = input.vis;
|
|
||||||
let doc = format!("'Incoming' variant of [{ty}](enum.{ty}.html).", ty = &input.ident);
|
|
||||||
let incoming_ident = format_ident!("Incoming{}", input.ident, span = Span::call_site());
|
|
||||||
let mut gen_copy = input.generics.clone();
|
|
||||||
let (_, ty_gen) = split_for_impl_lifetime_less(&mut gen_copy);
|
|
||||||
|
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
#[doc = #doc]
|
#[doc = #doc]
|
||||||
#[derive( #( #derives ),* )]
|
#[derive( #( #derives ),* )]
|
||||||
#( #input_attrs )*
|
#ty_def
|
||||||
#vis enum #incoming_ident #ty_gen { #( #vars, )* }
|
|
||||||
})
|
})
|
||||||
}
|
|
||||||
DataKind::Struct(mut fields, struct_kind) => {
|
|
||||||
let mut found_lifetime = false;
|
|
||||||
for field in &mut fields {
|
|
||||||
if !matches!(field.vis, syn::Visibility::Public(_)) {
|
|
||||||
return Err(syn::Error::new_spanned(field, "All fields must be marked `pub`"));
|
|
||||||
}
|
|
||||||
if strip_lifetimes(&mut field.ty) {
|
|
||||||
found_lifetime = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !found_lifetime {
|
|
||||||
return Ok(TokenStream::new());
|
|
||||||
}
|
|
||||||
|
|
||||||
let vis = input.vis;
|
|
||||||
let doc = format!("'Incoming' variant of [{ty}](struct.{ty}.html).", ty = &input.ident);
|
|
||||||
let incoming_ident = format_ident!("Incoming{}", input.ident, span = Span::call_site());
|
|
||||||
let mut gen_copy = input.generics.clone();
|
|
||||||
let (_, ty_gen) = split_for_impl_lifetime_less(&mut gen_copy);
|
|
||||||
|
|
||||||
let struct_def = match struct_kind {
|
|
||||||
StructKind::Struct => quote! { { #(#fields,)* } },
|
|
||||||
StructKind::Tuple => quote! { ( #(#fields,)* ); },
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(quote! {
|
|
||||||
#[doc = #doc]
|
|
||||||
#[derive( #( #derives ),* )]
|
|
||||||
#( #input_attrs )*
|
|
||||||
#vis struct #incoming_ident #ty_gen #struct_def
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Keep any `cfg`, `cfg_attr`, `serde` or `non_exhaustive` attributes found and pass them to the
|
/// Keep any `cfg`, `cfg_attr`, `serde` or `non_exhaustive` attributes found and pass them to the
|
||||||
@ -144,16 +92,13 @@ fn filter_input_attrs(attr: &Attribute) -> bool {
|
|||||||
|| attr.path.is_ident("allow")
|
|| attr.path.is_ident("allow")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn split_for_impl_lifetime_less(generics: &mut Generics) -> (ImplGenerics<'_>, TypeGenerics<'_>) {
|
fn clean_generics(generics: &mut Generics) {
|
||||||
generics.params = generics
|
generics.params = generics
|
||||||
.params
|
.params
|
||||||
.clone()
|
.clone()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|param| !matches!(param, GenericParam::Lifetime(_)))
|
.filter(|param| !matches!(param, GenericParam::Lifetime(_)))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let (impl_gen, ty_gen, _) = generics.split_for_impl();
|
|
||||||
(impl_gen, ty_gen)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn strip_lifetimes(field_type: &mut Type) -> bool {
|
fn strip_lifetimes(field_type: &mut Type) -> bool {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user