From 9810b809179ad4f3fecd29aa1d6b9fdf353bb06e Mon Sep 17 00:00:00 2001 From: torkleyy Date: Mon, 5 Jun 2017 21:55:39 +0200 Subject: [PATCH] Add support for where clauses and properly bind type parameters Also contains other improvements: * Don't clone tys * Return Vec instead of Vec + Add a where clause to the generic example Fix example: Make AutoBundle private --- examples/derive_bundle.rs | 2 +- examples/generic_derive.rs | 11 +++++++++- shred-derive/src/lib.rs | 43 +++++++++++++++++++++++++------------- 3 files changed, 39 insertions(+), 17 deletions(-) diff --git a/examples/derive_bundle.rs b/examples/derive_bundle.rs index 69ead78..b1cb4c5 100644 --- a/examples/derive_bundle.rs +++ b/examples/derive_bundle.rs @@ -11,7 +11,7 @@ struct ResA; struct ResB; #[derive(SystemData)] -pub struct AutoBundle<'a> { +struct AutoBundle<'a> { a: Fetch<'a, ResA>, b: FetchMut<'a, ResB>, } diff --git a/examples/generic_derive.rs b/examples/generic_derive.rs index fc650e1..d8ce21d 100644 --- a/examples/generic_derive.rs +++ b/examples/generic_derive.rs @@ -8,12 +8,21 @@ use std::fmt::Debug; use shred::{Fetch, FetchMut, Resource}; +trait Hrtb<'a> {} + #[derive(SystemData)] -struct VeryCustomDerive<'a, T: Debug + Resource> { +struct VeryCustomDerive<'a, T: Debug + Resource + for<'b> Hrtb<'b>> { _b: FetchMut<'a, T>, } #[derive(SystemData)] struct SomeTuple<'a, T: Debug + Resource>(Fetch<'a, T>); +#[derive(SystemData)] +struct WithWhereClause<'a, T> + where T: Resource +{ + k: Fetch<'a, T>, +} + fn main() {} diff --git a/shred-derive/src/lib.rs b/shred-derive/src/lib.rs index 10b9170..84a665a 100644 --- a/shred-derive/src/lib.rs +++ b/shred-derive/src/lib.rs @@ -6,7 +6,8 @@ extern crate syn; extern crate quote; use proc_macro::TokenStream; -use syn::{Body, Field, Ident, Lifetime, LifetimeDef, MacroInput, TyParam, VariantData}; +use syn::{Body, Field, Ident, Lifetime, LifetimeDef, MacroInput, Ty, TyParam, VariantData, + WhereClause}; use quote::Tokens; /// Used to `#[derive]` the trait @@ -25,28 +26,31 @@ fn impl_system_data(ast: &MacroInput) -> Tokens { let name = &ast.ident; let lifetime_defs = &ast.generics.lifetimes; let ty_params = &ast.generics.ty_params; + let where_clause = &ast.generics.where_clause; let (fetch_return, tys) = gen_from_body(&ast.body, name); + let tys = &tys; // Assumes that the first lifetime is the fetch lt - let fetch_lt = lifetime_defs + let def_fetch_lt = lifetime_defs .iter() .next() .expect("There has to be at least one lifetime"); + let ref impl_fetch_lt = def_fetch_lt.lifetime; let def_lt_tokens = gen_def_lt_tokens(lifetime_defs); let impl_lt_tokens = gen_impl_lt_tokens(lifetime_defs); let def_ty_params = gen_def_ty_params(ty_params); let impl_ty_params = gen_impl_ty_params(ty_params); + let where_clause = gen_where_clause(where_clause, impl_fetch_lt, tys); // Reads and writes are taken from the same types, // but need to be cloned before. - let reads = tys.clone(); - let writes = tys.clone(); quote! { impl< #def_lt_tokens , #def_ty_params > - ::shred::SystemData< #fetch_lt > + ::shred::SystemData< #impl_fetch_lt > for #name< #impl_lt_tokens , #impl_ty_params > + where #where_clause { - fn fetch(res: & #fetch_lt ::shred::Resources, id: usize) -> Self { + fn fetch(res: & #impl_fetch_lt ::shred::Resources, id: usize) -> Self { #fetch_return } @@ -54,7 +58,7 @@ fn impl_system_data(ast: &MacroInput) -> Tokens { let mut r = Vec::new(); #( { - let mut reads = <#reads as ::shred::SystemData> :: reads(id); + let mut reads = <#tys as ::shred::SystemData> :: reads(id); r.append(&mut reads); } )* @@ -65,7 +69,7 @@ fn impl_system_data(ast: &MacroInput) -> Tokens { let mut r = Vec::new(); #( { - let mut writes = <#writes as ::shred::SystemData> :: writes(id); + let mut writes = <#tys as ::shred::SystemData> :: writes(id); r.append(&mut writes); } )* @@ -75,12 +79,8 @@ fn impl_system_data(ast: &MacroInput) -> Tokens { } } -fn collect_field_types(fields: &Vec) -> Vec { - fields - .iter() - .map(|x| x.ty.clone()) - .map(|x| quote! { #x }) - .collect() +fn collect_field_types(fields: &Vec) -> Vec { + fields.iter().map(|x| x.ty.clone()).collect() } fn gen_identifiers(fields: &Vec) -> Vec { @@ -131,7 +131,20 @@ fn gen_impl_ty_params(ty_params: &Vec) -> Tokens { quote! { #( #ty_params ),* } } -fn gen_from_body(ast: &Body, name: &Ident) -> (Tokens, Vec) { +fn gen_where_clause(clause: &WhereClause, fetch_lt: &Lifetime, tys: &Vec) -> Tokens { + let user_predicates = clause.predicates.iter().map(|x| quote! { #x }); + let system_data_predicates = tys.iter() + .map(|ty| { + quote! { #ty : ::shred::SystemData< #fetch_lt > } + }); + + let mut tokens = Tokens::new(); + tokens.append_separated(user_predicates.chain(system_data_predicates), ","); + + tokens +} + +fn gen_from_body(ast: &Body, name: &Ident) -> (Tokens, Vec) { enum BodyType { Struct, Tuple,