diff --git a/README.md b/README.md index cd33537..50c96d0 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -`Typed` is a procedural macro that is used for disassembling `structs`, `enums` and `fns` into their inner `type` components that are then accompanied with documentation and examples. The `Typed` structures will be wrapped into a module and reassigned with a name (default `ty`), this also goes for the `static` and `generic` fields. +`Typed` is a procedural macro that is used for disassembling `structs`, `enums` and `fns` into their inner `type` components that are then accompanied with documentation and examples. The `Typed` structures will be wrapped into a module and reassigned with a name (default `core`), this also goes for the `static` and `generic` fields. #### *Project is still under development* @@ -28,7 +28,7 @@ pub mod #name { // Docs (/w examples) describing the original `item`. #[doc = #docs] // The original `ìtem`. - #struct_original // Access through `#name::ty` + #struct_original // Access through `#name::core` } ``` @@ -48,9 +48,9 @@ struct Area(i32); ```rust let current: Container::current = 10; let buffer: Container::buffer = vec![current]; -let another: as Container::proto>::another = 20; -let container: Container::ty = - Container::ty { +let another: as Container::protocol>::another = 20; +let container: Container::core = + Container::core { current, buffer, another @@ -58,9 +58,9 @@ let container: Container::ty = ``` - It's also possible to use it as following: ```rust -trait Trait: Container::proto { - fn retrieve(&self) -> Container::proto::buffer; - fn extend(&mut self, val: Container::proto::another); +trait Trait: Container::protocol { + fn retrieve(&self) -> Container::protocol::buffer; + fn extend(&mut self, val: Container::protocol::another); } ``` @@ -81,7 +81,7 @@ fn main() { another: 20, } - let y: MContainer::ty = x; + let y: MContainer::core = x; } ``` diff --git a/src/builder.rs b/src/builder.rs index 10fd5c5..2bfbb2a 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1,3 +1,4 @@ +use crate::tools::{doc_struct, doc_type, format_code, publicify_and_docify, get_generic_idents, new, ident}; use proc_macro::TokenStream; use proc_macro2::TokenStream as TokenStream2; use quote::{format_ident, quote, ToTokens, TokenStreamExt}; @@ -10,79 +11,6 @@ use syn::{ Attribute, Fields, Generics, Ident, Token, Type, Visibility, }; -use tools::{doc_struct, doc_type, format_code, publicify_and_docify}; - -#[path = "tools.rs"] -mod tools; - -/// Use `new!(..)` to construct `structs`. -/// - `clone[$ident,*]` -> `$ident.clone(),*` -/// - `string[$ident,*]` -> `$ident.to_string(),*` -/// - `into[$ident,*]` -> `$ident.into(),*` -/// - `$ident($tt)` -> `$ident: $tt` -/// -/// # Example -/// ```no_run -/// struct TypeStructure { -/// attrs: Vec, -/// vis: Visibility, -/// struct_token: Token![struct], -/// ident: Ident, -/// generics: Generics, -/// fields: Fields, -/// semi_colon: Option, -/// } -/// -/// let attrs = ...; -/// let generics ...; -/// -/// let struct_decl = new!({ -/// clone[attrs, generics], -/// vis(parse_quote!(pub)), -/// ident(format_ident!("ty", span = proc_macro2::Span::call_site())), -/// struct_token, -/// fields, -/// semi_colon, -/// }: TypeStructure); -/// ``` -/// -macro_rules! new { - // Invoke syntax - ({ $($tail:tt)* } = $name:ident ) => { new!($name @ [] @ $($tail)*) }; - ({ $($tail:tt)* }: $name:ident ) => { new!($name @ [] @ $($tail)*) }; - ({ $($tail:tt)* } => $name:ident ) => { new!($name @ [] @ $($tail)*) }; - ({ $($tail:tt)* } $name:ident ) => { new!($name @ [] @ $($tail)*) }; - - ($name:ident { $($tail:tt)* } ) => { new!($name @ [] @ $($tail)*) }; - ($name:ident => { $($tail:tt)* } ) => { new!($name @ [] @ $($tail)*) }; - ($name:ident: { $($tail:tt)* } ) => { new!($name @ [] @ $($tail)*) }; - ($name:ident = { $($tail:tt)* } ) => { new!($name @ [] @ $($tail)*) }; - - ($name:ident => $($tail:tt)* ) => { new!($name @ [] @ $($tail)*) }; - ($name:ident: $($tail:tt)* ) => { new!($name @ [] @ $($tail)*) }; - ($name:ident = $($tail:tt)* ) => { new!($name @ [] @ $($tail)*) }; - - - // 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)*] @ $(.)? 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)*] @ $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())}; -} struct TypeModule { attrs: Vec, @@ -106,10 +34,12 @@ struct TypeAlias { } struct TypeGeneric { + #[allow(dead_code)] attrs: Vec, ident: Ident, generics: Generics, assoc_decls: Vec, + type_struct_ident: Ident, } struct TypeStructure { @@ -149,6 +79,7 @@ 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()?; @@ -159,9 +90,9 @@ impl Parse for TypeModule { let mut type_decls: Vec = Vec::new(); - let fields: Fields = parse_fields(input, |fields| { + let fields: Fields = parse_fields(input, |fields| type_decls = parse_type_decls(fields, &generics, &source) - })?; + )?; let struct_doc = doc_struct(source.name.as_str(), source.code.as_str()); attrs.push(parse_quote!(#[doc = #struct_doc])); @@ -169,16 +100,16 @@ impl Parse for TypeModule { let struct_decl = new!({ clone[attrs, generics], vis(parse_quote!(pub)), - ident(ident!("ty")), + ident(ident!("core")), semi_colon(input.peek(Token![;]).then(|| input.parse().ok()).flatten()), struct_token, - fields, + fields, }: TypeStructure); - let generic_decl = new!({ clone[attrs], - ident(ident!("gen")), + ident(ident!("protocol")), + type_struct_ident(ident!("core")), assoc_decls(type_decls.to_vec()), generics, }: TypeGeneric); @@ -209,7 +140,6 @@ impl ToTokens for TypeModule { #![allow(non_camel_case_types)] #module_inner - } ); @@ -219,17 +149,19 @@ impl ToTokens for TypeModule { impl ToTokens for TypeModuleInner { fn to_tokens(&self, tokens: &mut TokenStream2) { - let type_delcs: Vec = self + let type_decls: Vec = self .type_decls .iter() .filter_map(|t| t.has_gen.then(|| t.clone())) .collect(); + let type_decls = quote!(#(#type_decls)*); + let struct_decl = &self.struct_decl; let generic_decl = &self.generic_decl; let inner_decls = quote!( - #(#type_delcs)* + #type_decls #struct_decl @@ -243,7 +175,10 @@ impl ToTokens for TypeModuleInner { impl ToTokens for TypeAlias { fn to_tokens(&self, tokens: &mut TokenStream2) { let TypeAlias { - docs, ident, ty, .. + docs, + ident, + ty, + .. } = self; tokens.append_all(quote!(#docs pub type #ident = #ty;)); @@ -252,7 +187,8 @@ impl ToTokens for TypeAlias { impl ToTokens for TypeGeneric { fn to_tokens(&self, tokens: &mut TokenStream2) { - let trait_ident = &self.ident; + let TypeGeneric { ident: trait_ident, type_struct_ident , .. } = self; + let (impl_generics, ty_generics, where_clause) = self.generics.split_for_impl(); let mut assoc_decls = Vec::::new(); @@ -277,13 +213,13 @@ impl ToTokens for TypeGeneric { tokens.append_all(quote!( pub trait #trait_ident { - type __Bind: #trait_ident #bind_generic; + type __Core: #trait_ident #bind_generic; #(#assoc_decls)* } - impl #impl_generics #trait_ident for ty #ty_generics #where_clause { - type __Bind = Self; + impl #impl_generics #trait_ident for #type_struct_ident #ty_generics #where_clause { + type __Core = Self; #(#assoc_impl_decls)* } )); @@ -292,17 +228,19 @@ impl ToTokens for TypeGeneric { impl ToTokens for TypeStructure { fn to_tokens(&self, tokens: &mut TokenStream2) { - let attrs = &self.attrs; - let visibility = &self.vis; - let struct_token = &self.struct_token; - let ident = &self.ident; - let generics = &self.generics; - let fields = &self.fields; - let semi_colon = &self.semi_colon; - + let TypeStructure { + attrs, + vis, + struct_token, + ident, + generics, + fields, + semi_colon + } = self; + let struct_decl = quote!( #(#attrs)* - #visibility #struct_token #ident #generics #fields #semi_colon + #vis #struct_token #ident #generics #fields #semi_colon ); tokens.append_all(struct_decl); @@ -339,10 +277,7 @@ where fn parse_type_decls(fields: &mut Fields, generics: &Generics, source: &Source) -> Vec { let mut type_decls: Vec = Vec::new(); - let param_generics = generics - .type_params() - .map(|tp| tp.ident.clone()) - .collect::>(); + let param_generics = get_generic_idents(generics); for (index, field) in fields.iter_mut().enumerate() { let field_type_generics = FieldTypeGenerics::get_idents(&field.ty); diff --git a/src/docs/struct.md b/src/docs/struct.md index 730cfd4..6b1562f 100644 --- a/src/docs/struct.md +++ b/src/docs/struct.md @@ -1,11 +1,11 @@ -Use `{name}::ty` as a type. +Use `{name}::core` as a type. ```no_run {source_code} ``` # Example ```no_run -fn get(input: {name}::ty) -> {name}::ty {{ - let field: {name}::ty = input; +fn get(input: {name}::core) -> {name}::core {{ + let field: {name}::core = input; input }} ``` \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 6221a7d..58ddbdf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ use proc_macro::TokenStream; +mod tools; mod builder; /// Use `type_it` as a proc-macro. @@ -20,9 +21,9 @@ mod builder; /// ```no_run /// let current: Container::current = 10; /// let buffer: Container::buffer = vec![current]; -/// let another: as Container::proto>::another = 20; -/// let container: Container::ty = -/// Container::ty { +/// let another: as Container::proto>::another = 20; +/// let container: Container::core = +/// Container::core { /// current, /// buffer, /// another @@ -30,7 +31,7 @@ mod builder; /// ``` /// - It's also possible to use it as following: /// ```no_run -/// trait Trait: Container::proto { +/// trait Trait: Container::protocol { /// fn retrieve(&self) -> Container::proto::buffer; /// fn extend(&mut self, val: Container::proto::another); /// } diff --git a/src/tools.rs b/src/tools.rs index 055033c..fb384c0 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -1,7 +1,80 @@ use ::rustfmt::{format_input, Input}; use quote::{format_ident, ToTokens}; -use std::{io::Sink}; -use syn::{self, parse_quote, Field, Ident, Type}; +use std::{io::Sink, collections::HashSet}; +use syn::{self, parse_quote, Field, Ident, Type, Generics}; + + +/// Use `new!(..)` to construct `structs`. +/// - `clone[$ident,*]` -> `$ident.clone(),*` +/// - `string[$ident,*]` -> `$ident.to_string(),*` +/// - `into[$ident,*]` -> `$ident.into(),*` +/// - `$ident($tt)` -> `$ident: $tt` +/// +/// # Example +/// ```no_run +/// struct TypeStructure { +/// attrs: Vec, +/// vis: Visibility, +/// struct_token: Token![struct], +/// ident: Ident, +/// generics: Generics, +/// fields: Fields, +/// semi_colon: Option, +/// } +/// +/// let attrs = ...; +/// let generics ...; +/// +/// let struct_decl = new!({ +/// clone[attrs, generics], +/// vis(parse_quote!(pub)), +/// ident(format_ident!("ty", span = proc_macro2::Span::call_site())), +/// struct_token, +/// fields, +/// semi_colon, +/// }: TypeStructure); +/// ``` +/// +macro_rules! new { + // Invoke syntax + ({ $($tail:tt)* } = $name:ident ) => { new!($name [] $($tail)*) }; + ({ $($tail:tt)* }: $name:ident ) => { new!($name [] $($tail)*) }; + ({ $($tail:tt)* } => $name:ident ) => { new!($name [] $($tail)*) }; + ({ $($tail:tt)* } $name:ident ) => { new!($name [] $($tail)*) }; + + ($name:ident { $($tail:tt)* } ) => { new!($name [] $($tail)*) }; + ($name:ident => { $($tail:tt)* } ) => { new!($name [] $($tail)*) }; + ($name:ident: { $($tail:tt)* } ) => { new!($name [] $($tail)*) }; + ($name:ident = { $($tail:tt)* } ) => { new!($name [] $($tail)*) }; + + ($name:ident => $($tail:tt)* ) => { new!($name [] $($tail)*) }; + ($name:ident: $($tail:tt)* ) => { new!($name [] $($tail)*) }; + ($name:ident = $($tail:tt)* ) => { new!($name [] $($tail)*) }; + + + // 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)*] $(.)? 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)*] $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())}; +} + +pub(crate) use new; +pub(crate) use ident; + pub fn doc_type(name: &Ident, ty: &Type, source_code: &str) -> String { let name = name.to_string(); @@ -56,3 +129,10 @@ pub fn publicify_and_docify(field: &mut Field, parent: &str, i: usize) -> Ident ident } + +pub fn get_generic_idents(generics: &Generics) -> HashSet { + generics + .type_params() + .map(|tp| tp.ident.clone()) + .collect::>() +} diff --git a/tests/typed-test.rs b/tests/typed-test.rs index 1076f72..e5c5dc4 100644 --- a/tests/typed-test.rs +++ b/tests/typed-test.rs @@ -8,7 +8,7 @@ struct Container { a: i32, b: Vec, c: Vec, - d: T + d: T, } #[type_it] @@ -17,14 +17,12 @@ struct Tuple(i32, i32); #[type_it] struct Tuple2(i32, T); - - fn main() { let a: Container::a = 10; let b: Container::b = vec![a]; - let c: as Container::gen>::c = vec![10]; - let d: as Container::gen>::d = 10; - let container: Container::ty = Container::ty { a, b, c, d }; + 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 }; assert!(container.a == a); }