diff --git a/src/builder.rs b/src/builder.rs index 2bfbb2a..2ef1e18 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -12,6 +12,7 @@ use syn::{ }; + struct TypeModule { attrs: Vec, vis: Visibility, @@ -30,7 +31,7 @@ struct TypeAlias { docs: Attribute, ident: Ident, ty: Type, - has_gen: bool, + generics: Option, } struct TypeGeneric { @@ -79,17 +80,16 @@ impl Parse for TypeModule { fn parse(input: ParseStream) -> syn::Result { let code = format_code(input.to_string()); - let mut attrs: Vec = input.call(Attribute::parse_outer)?; let vis: Visibility = input.parse()?; let struct_token: Token![struct] = input.parse()?; let name: Ident = input.parse()?; let generics: Generics = input.parse()?; - + let source = new!(Source => string[name], code); let mut type_decls: Vec = Vec::new(); - + let fields: Fields = parse_fields(input, |fields| type_decls = parse_type_decls(fields, &generics, &source) )?; @@ -97,19 +97,21 @@ impl Parse for TypeModule { let struct_doc = doc_struct(source.name.as_str(), source.code.as_str()); attrs.push(parse_quote!(#[doc = #struct_doc])); + let ident = ident!("core"); + let semi_colon = input.peek(Token![;]).then(|| input.parse().ok()).flatten(); + let struct_decl = new!({ - clone[attrs, generics], + clone[attrs, generics, ident], vis(parse_quote!(pub)), - ident(ident!("core")), - semi_colon(input.peek(Token![;]).then(|| input.parse().ok()).flatten()), + semi_colon, struct_token, fields, }: TypeStructure); let generic_decl = new!({ clone[attrs], + type_struct_ident(ident), ident(ident!("protocol")), - type_struct_ident(ident!("core")), assoc_decls(type_decls.to_vec()), generics, }: TypeGeneric); @@ -120,7 +122,6 @@ impl Parse for TypeModule { ident(name), inner(new!({ type_decls, generic_decl, struct_decl }: TypeModuleInner)) }: Self)) - } } @@ -149,11 +150,7 @@ impl ToTokens for TypeModule { impl ToTokens for TypeModuleInner { fn to_tokens(&self, tokens: &mut TokenStream2) { - let type_decls: Vec = self - .type_decls - .iter() - .filter_map(|t| t.has_gen.then(|| t.clone())) - .collect(); + let type_decls: &Vec = &self.type_decls; let type_decls = quote!(#(#type_decls)*); @@ -161,6 +158,7 @@ impl ToTokens for TypeModuleInner { let generic_decl = &self.generic_decl; let inner_decls = quote!( + pub mod fields { #type_decls } #type_decls #struct_decl @@ -178,10 +176,10 @@ impl ToTokens for TypeAlias { docs, ident, ty, - .. + generics } = self; - tokens.append_all(quote!(#docs pub type #ident = #ty;)); + tokens.append_all(quote!( #[allow(type_alias_bounds)] #docs pub type #ident #generics = #ty;)); } } @@ -214,7 +212,6 @@ impl ToTokens for TypeGeneric { tokens.append_all(quote!( pub trait #trait_ident { type __Core: #trait_ident #bind_generic; - #(#assoc_decls)* } @@ -248,10 +245,11 @@ impl ToTokens for TypeStructure { } impl TypeAlias { - pub fn new<'a>(source_code: &'a str, ident: &'a Ident, ty: &'a Type, has_gen: bool) -> Self { + pub fn new<'a>(source_code: &'a str, ident: &'a Ident, ty: &'a Type, generics: Option) -> Self { let type_doc = doc_type(ident, ty, source_code); + new!({ - clone[ident, ty, has_gen], + clone[ident, ty, generics], docs(parse_quote!(#[doc = #type_doc])), } => Self) } @@ -281,10 +279,20 @@ fn parse_type_decls(fields: &mut Fields, generics: &Generics, source: &Source) - for (index, field) in fields.iter_mut().enumerate() { let field_type_generics = FieldTypeGenerics::get_idents(&field.ty); - let has_gen = param_generics.intersection(&field_type_generics.0).count() == 0; + // FIXME: Umm, fix this shit please + let matches: Vec<_> = param_generics.intersection(&field_type_generics.0).collect(); + let hs: HashSet<_> = matches.clone().into_iter().collect(); + let gens: Vec<_> = generics.type_params().filter_map(|p| hs.contains(&p.ident).then_some(p)).collect(); + let field_ident = publicify_and_docify(field, source.name.as_str(), index); - let type_decl = TypeAlias::new(source.code.as_str(), &field_ident, &field.ty, has_gen); + let type_decl = TypeAlias::new(source.code.as_str(), &field_ident, &field.ty, { + if matches.is_empty() { + None + } else { + Some(parse_quote!(<#(#gens),*>)) + } + }); type_decls.push(type_decl); } diff --git a/src/tools.rs b/src/tools.rs index fb384c0..b57f70e 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -28,7 +28,7 @@ use syn::{self, parse_quote, Field, Ident, Type, Generics}; /// let struct_decl = new!({ /// clone[attrs, generics], /// vis(parse_quote!(pub)), -/// ident(format_ident!("ty", span = proc_macro2::Span::call_site())), +/// ident(format_ident!("core", span = proc_macro2::Span::call_site())), /// struct_token, /// fields, /// semi_colon, @@ -53,23 +53,39 @@ macro_rules! new { // Grammer - ($name:ident [$($stored:tt)*] $(.)? into $(.)? [$($field:ident),*] $(, $($tail:tt)*)?) => { new!($name [$(, $stored)* $($field: $field.into()),*] $($($tail)*)? ) }; - ($name:ident [$($stored:tt)*] $(.)? string $(.)? [$($field:ident),*] $(, $($tail:tt)*)?) => { new!($name [$(, $stored)* $($field: $field.to_string()),*] $($($tail)*)? ) }; - ($name:ident [$($stored:tt)*] $(.)? str $(.)? [$($field:ident),*] $(, $($tail:tt)*)?) => { new!($name [$(, $stored)* $($field: $field.as_str()),*] $($($tail)*)? ) }; + ($name:ident [$($stored:tt)*] $(.)? into $(.)? [$($field:ident),*] $(, $($tail:tt)*)?) + => { new!($name [$(, $stored)* $($field: $field.into()),*] $($($tail)*)? ) }; + ($name:ident [$($stored:tt)*] $(.)? string $(.)? [$($field:ident),*] $(, $($tail:tt)*)?) + => { new!($name [$(, $stored)* $($field: $field.to_string()),*] $($($tail)*)? ) }; - ($name:ident [$($stored:tt)*] $(.)? clone $(.)? [$($field:ident),*] $(, $($tail:tt)*)?) => { new!($name [$(, $stored)* $($field: $field.clone()),*] $($($tail)*)? ) }; - ($name:ident [$($stored:tt)*] $field:ident: $field2:ident $(, $($tail:tt)*)?) => { new!($name [$($stored)*, $field: $field2] $($($tail)*)? ) }; + ($name:ident [$($stored:tt)*] $(.)? str $(.)? [$($field:ident),*] $(, $($tail:tt)*)?) + => { new!($name [$(, $stored)* $($field: $field.as_str()),*] $($($tail)*)? ) }; - ($name:ident [$($stored:tt)*] $field:ident ($($sym:tt)*) $(, $($tail:tt)*)?) => { new!($name [$field: $($sym)*, $($stored)*] $($($tail)*)? ) }; + ($name:ident [$($stored:tt)*] $(.)? clone $(.)? [$($field:ident),*] $(, $($tail:tt)*)?) + => { new!($name [$(, $stored)* $($field: $field.clone()),*] $($($tail)*)? ) }; - ($name:ident [$($stored:tt)*] $field:ident $(, $($tail:tt)*)?) => { new!($name [$field, $($stored)*] $($($tail)*)? ) }; - ($name:ident [$($stored:tt)*] .. $(, $($tail:tt)*)?) => { new!([.., $($stored)*] $($($tail)*)? ) }; - ($name:ident [$($stored:tt)*] ) => { $name { $($stored)* } }; + ($name:ident [$($stored:tt)*] $(.)? clone $(.)? [$($field:ident as $alias:ident),*] $(, $($tail:tt)*)?) + => { new!($name [$(, $stored)* $($alias: $field.clone()),*] $($($tail)*)? ) }; + + ($name:ident [$($stored:tt)*] $field:ident: $field2:ident $(, $($tail:tt)*)?) + => { new!($name [$($stored)*, $field: $field2] $($($tail)*)? ) }; + + ($name:ident [$($stored:tt)*] $field:ident ($($sym:tt)*) $(, $($tail:tt)*)?) + => { new!($name [$field: $($sym)*, $($stored)*] $($($tail)*)? ) }; + + ($name:ident [$($stored:tt)*] $field:ident $(, $($tail:tt)*)?) + => { new!($name [$field, $($stored)*] $($($tail)*)? ) }; + + ($name:ident [$($stored:tt)*] .. $(, $($tail:tt)*)?) + => { new!([.., $($stored)*] $($($tail)*)? ) }; + + ($name:ident [$($stored:tt)*] ) + => { $name { $($stored)* } }; } macro_rules! ident { - ($name:tt) => {format_ident!($name, span = proc_macro2::Span::call_site())}; + ($name:tt) => { format_ident!($name, span = proc_macro2::Span::call_site()) }; } pub(crate) use new; diff --git a/tests/typed-test.rs b/tests/typed-test.rs index e5c5dc4..76fc890 100644 --- a/tests/typed-test.rs +++ b/tests/typed-test.rs @@ -4,11 +4,12 @@ extern crate typer; use typer::type_it; #[type_it] -struct Container { +struct Container { a: i32, b: Vec, c: Vec, - d: T, + d: C, + e: T } #[type_it] @@ -18,11 +19,11 @@ struct Tuple(i32, i32); struct Tuple2(i32, T); fn main() { - let a: Container::a = 10; + let a: Container::fields::a = 10; let b: Container::b = vec![a]; let c: as Container::protocol>::c = vec![10]; let d: as Container::protocol>::d = 10; - let container: Container::core = Container::core { a, b, c, d }; + let container: Container::core = Container::core { a, b, c, d, e: 10 }; assert!(container.a == a); }