Skip to content

Commit

Permalink
Added generics to static type fields
Browse files Browse the repository at this point in the history
  • Loading branch information
viktorlott committed Jan 16, 2023
1 parent f590a44 commit 97018b0
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 36 deletions.
50 changes: 29 additions & 21 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use syn::{
};



struct TypeModule {
attrs: Vec<Attribute>,
vis: Visibility,
Expand All @@ -30,7 +31,7 @@ struct TypeAlias {
docs: Attribute,
ident: Ident,
ty: Type,
has_gen: bool,
generics: Option<Generics>,
}

struct TypeGeneric {
Expand Down Expand Up @@ -79,37 +80,38 @@ impl Parse for TypeModule {
fn parse(input: ParseStream) -> syn::Result<Self> {
let code = format_code(input.to_string());


let mut attrs: Vec<Attribute> = 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<TypeAlias> = Vec::new();

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]));

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);
Expand All @@ -120,7 +122,6 @@ impl Parse for TypeModule {
ident(name),
inner(new!({ type_decls, generic_decl, struct_decl }: TypeModuleInner))
}: Self))

}
}

Expand Down Expand Up @@ -149,18 +150,15 @@ impl ToTokens for TypeModule {

impl ToTokens for TypeModuleInner {
fn to_tokens(&self, tokens: &mut TokenStream2) {
let type_decls: Vec<TypeAlias> = self
.type_decls
.iter()
.filter_map(|t| t.has_gen.then(|| t.clone()))
.collect();
let type_decls: &Vec<TypeAlias> = &self.type_decls;

let type_decls = quote!(#(#type_decls)*);

let struct_decl = &self.struct_decl;
let generic_decl = &self.generic_decl;

let inner_decls = quote!(
pub mod fields { #type_decls }
#type_decls

#struct_decl
Expand All @@ -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;));
}
}

Expand Down Expand Up @@ -214,7 +212,6 @@ impl ToTokens for TypeGeneric {
tokens.append_all(quote!(
pub trait #trait_ident {
type __Core: #trait_ident #bind_generic;

#(#assoc_decls)*
}

Expand Down Expand Up @@ -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<Generics>) -> 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)
}
Expand Down Expand Up @@ -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);
}
Expand Down
38 changes: 27 additions & 11 deletions src/tools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand Down
9 changes: 5 additions & 4 deletions tests/typed-test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ extern crate typer;
use typer::type_it;

#[type_it]
struct Container<T> {
struct Container<C: Clone, T = i64> {
a: i32,
b: Vec<i32>,
c: Vec<T>,
d: T,
d: C,
e: T
}

#[type_it]
Expand All @@ -18,11 +19,11 @@ struct Tuple(i32, i32);
struct Tuple2<T>(i32, T);

fn main() {
let a: Container::a = 10;
let a: Container::fields::a = 10;
let b: Container::b = vec![a];
let c: <Container::core<i64> as Container::protocol>::c = vec![10];
let d: <Container::core<i64> as Container::protocol>::d = 10;
let container: Container::core<i64> = Container::core { a, b, c, d };
let container: Container::core<i64> = Container::core { a, b, c, d, e: 10 };

assert!(container.a == a);
}

0 comments on commit 97018b0

Please sign in to comment.