diff options
author | Martin Fischer <martin@push-f.com> | 2021-11-25 08:49:47 +0100 |
---|---|---|
committer | Martin Fischer <martin@push-f.com> | 2021-11-25 09:34:50 +0100 |
commit | 06a384000b0a6c7b657e4f8a9145b3d4357f3d70 (patch) | |
tree | dd28fbfc23d7067d07285f9528d097bcf3ca8899 /src/lib.rs | |
parent | 0acd72140f5e1b854d6a30d27de11785b0be8a63 (diff) |
refactor: factor out parse_attrs module
Diffstat (limited to 'src/lib.rs')
-rw-r--r-- | src/lib.rs | 94 |
1 files changed, 13 insertions, 81 deletions
@@ -3,13 +3,10 @@ use std::collections::HashMap; use proc_macro::TokenStream; -use proc_macro2::Group; use quote::format_ident; use quote::quote; use quote::quote_spanned; use quote::ToTokens; -use syn::parenthesized; -use syn::parse::Parse; use syn::parse_macro_input; use syn::spanned::Spanned; use syn::token::Brace; @@ -18,20 +15,16 @@ use syn::token::Lt; use syn::token::Trait; use syn::AngleBracketedGenericArguments; use syn::Block; -use syn::Error; use syn::Expr; use syn::GenericArgument; use syn::GenericParam; -use syn::Ident; use syn::ImplItemMethod; use syn::ItemTrait; -use syn::LitInt; use syn::Path; use syn::PathArguments; use syn::PathSegment; use syn::Signature; use syn::Stmt; -use syn::Token; use syn::TraitBound; use syn::TraitItem; use syn::TraitItemMethod; @@ -44,6 +37,7 @@ use syn_utils::TypeOrPath; use crate::parse_assoc_type::parse_assoc_type; use crate::parse_assoc_type::AssocTypeError; +use crate::parse_attrs::TraitAttrs; use crate::syn_utils::iter_path; use crate::syn_utils::trait_bounds; use crate::trait_sig::convert_trait_signature; @@ -54,6 +48,7 @@ use crate::transform::TransformError; use crate::transform::TypeConverter; mod parse_assoc_type; +mod parse_attrs; mod syn_utils; mod trait_sig; mod transform; @@ -66,30 +61,6 @@ macro_rules! abort { }}; } -struct Collection { - id: Ident, - count: usize, -} - -impl Parse for Collection { - fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { - let inner; - parenthesized!(inner in input); - - let id: Ident = inner.parse()?; - let _: Token![,] = inner.parse()?; - let count_lit: LitInt = inner.parse()?; - let count: usize = count_lit.base10_parse()?; - if count < 1 { - return Err(Error::new( - count_lit.span(), - "number of type parameters must be >= 1", - )); - } - Ok(Self { id, count }) - } -} - #[proc_macro_attribute] pub fn dynamize(_attr: TokenStream, input: TokenStream) -> TokenStream { let mut original_trait = parse_macro_input!(input as ItemTrait); @@ -108,57 +79,15 @@ pub fn dynamize(_attr: TokenStream, input: TokenStream) -> TokenStream { } } - let mut type_converter = TypeConverter::default(); - - let mut blanket_impl_attrs = Vec::new(); - let mut dyn_trait_attrs = Vec::new(); + let method_attrs = match TraitAttrs::parse(&mut original_trait.attrs) { + Ok(attrs) => attrs, + Err(err) => return err.to_compile_error().into(), + }; - // FUTURE: use Vec::drain_filter once it's stable - let mut i = 0; - while i < original_trait.attrs.len() { - if original_trait.attrs[i].path.is_ident("blanket_impl_attr") { - let attr = original_trait.attrs.remove(i); - let group: Group = match syn::parse2(attr.tokens) { - Ok(g) => g, - Err(err) => { - return abort!( - err.span(), - "expected parenthesis: #[blanket_impl_attr(...)]" - ) - } - }; - let tokens = group.stream(); - blanket_impl_attrs.push(quote! {#[#tokens]}); - } else if original_trait.attrs[i].path.is_ident("dyn_trait_attr") { - let attr = original_trait.attrs.remove(i); - let group: Group = match syn::parse2(attr.tokens) { - Ok(g) => g, - Err(err) => { - return abort!(err.span(), "expected parenthesis: #[dyn_trait_attr(...)]") - } - }; - let tokens = group.stream(); - dyn_trait_attrs.push(quote! {#[#tokens]}); - } else if original_trait.attrs[i].path.is_ident("collection") { - let attr = original_trait.attrs.remove(i); - let tokens = attr.tokens.into(); - let coll = parse_macro_input!(tokens as Collection); - - if type_converter - .collections - .insert(coll.id.clone(), coll.count) - .is_some() - { - return abort!( - coll.id.span(), - "collection `{}` is defined multiple times for this trait", - coll.id - ); - } - } else { - i += 1; - } - } + let mut type_converter = TypeConverter { + collections: method_attrs.collections, + ..TypeConverter::default() + }; for item in &original_trait.items { if let TraitItem::Type(assoc_type) = item { @@ -393,6 +322,9 @@ pub fn dynamize(_attr: TokenStream, input: TokenStream) -> TokenStream { let dyn_trait_name = &dyn_trait.ident; let (impl_generics, ty_generics, where_clause) = dyn_trait.generics.split_for_impl(); + let dyn_trait_attrs = method_attrs.dyn_trait_attrs; + let blanket_impl_attrs = method_attrs.blanket_impl_attrs; + let expanded = quote! { #original_trait |