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 { |     Ok(quote! { | ||||||
|         DataKind::Unit => Ok(TokenStream::new()), |         #[doc = #doc] | ||||||
|         DataKind::Enum(mut vars) => { |         #[derive( #( #derives ),* )] | ||||||
|             let mut found_lifetime = false; |         #ty_def | ||||||
|             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! { |  | ||||||
|                 #[doc = #doc] |  | ||||||
|                 #[derive( #( #derives ),* )] |  | ||||||
|                 #( #input_attrs )* |  | ||||||
|                 #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