diff options
Diffstat (limited to 'src/parse_attrs.rs')
-rw-r--r-- | src/parse_attrs.rs | 59 |
1 files changed, 56 insertions, 3 deletions
diff --git a/src/parse_attrs.rs b/src/parse_attrs.rs index d9725ff..06a5123 100644 --- a/src/parse_attrs.rs +++ b/src/parse_attrs.rs @@ -1,8 +1,14 @@ -use std::collections::{HashMap, HashSet}; +use std::{ + collections::{HashMap, HashSet}, + rc::Rc, +}; use proc_macro2::{Group, TokenStream}; use quote::quote; -use syn::{parenthesized, parse::Parse, Attribute, Error, Ident, LitInt, Token}; +use syn::{ + braced, parenthesized, parse::Parse, spanned::Spanned, Attribute, Error, Ident, LitInt, Token, + Type, +}; struct Collection { pub id: Ident, @@ -32,8 +38,9 @@ impl Parse for Collection { pub struct TraitAttrs { pub blanket_impl_attrs: Vec<TokenStream>, pub dyn_trait_attrs: Vec<TokenStream>, - pub collections: HashMap<Ident, usize>, pub dynamized_supertraits: HashSet<Ident>, + pub collections: HashMap<Ident, usize>, + pub type_conversions: HashMap<Type, Rc<Convert>>, } struct Dynamized { @@ -82,6 +89,21 @@ impl TraitAttrs { }; let tokens = group.stream(); parsed.dyn_trait_attrs.push(quote! {#[#tokens]}); + } else if attrs[i].path.is_ident("convert") { + let attr = attrs.remove(i); + let convert: Convert = syn::parse2(attr.tokens)?; + let span = convert.original_type.span(); + + if parsed + .type_conversions + .insert(convert.original_type.clone(), Rc::new(convert)) + .is_some() + { + return Err(Error::new( + span, + format_args!("conversion is defined multiple times for this type"), + )); + } } else if attrs[i].path.is_ident("collection") { let attr = attrs.remove(i); let coll: Collection = syn::parse2(attr.tokens)?; @@ -118,3 +140,34 @@ impl TraitAttrs { Ok(parsed) } } + +#[derive(Debug, Clone)] +pub struct Convert { + pub ident: Ident, + pub original_type: Type, + pub dest_type: Type, + pub block: TokenStream, +} + +impl Parse for Convert { + fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { + let _: Token![=] = input.parse()?; + let _: Token![|] = input.parse()?; + let param: Ident = input.parse()?; + let _: Token![:] = input.parse()?; + let original_type: Type = input.parse()?; + let _: Token![|] = input.parse()?; + let _: Token![->] = input.parse()?; + let dest_type: Type = input.parse()?; + + let inner; + braced!(inner in input); + + Ok(Self { + ident: param, + original_type, + dest_type, + block: inner.parse()?, + }) + } +} |