summaryrefslogtreecommitdiff
path: root/src/generate/summon_checker.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/generate/summon_checker.rs')
-rw-r--r--src/generate/summon_checker.rs62
1 files changed, 62 insertions, 0 deletions
diff --git a/src/generate/summon_checker.rs b/src/generate/summon_checker.rs
new file mode 100644
index 0000000..743c199
--- /dev/null
+++ b/src/generate/summon_checker.rs
@@ -0,0 +1,62 @@
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::Error;
+
+use crate::info_structures::{ArgType, BuilderType, StructInfo};
+
+pub fn generate_checker_summoner(info: &StructInfo) -> Result<TokenStream, Error> {
+ let mut code: Vec<TokenStream> = Vec::new();
+ let mut params: Vec<TokenStream> = Vec::new();
+ let mut value_consumers: Vec<TokenStream> = Vec::new();
+ let mut template_consumers: Vec<TokenStream> = Vec::new();
+ for field in &info.fields {
+ let field_name = &field.name;
+
+ let arg_type = field.make_constructor_arg_type(&info, BuilderType::Sync)?;
+ if let ArgType::Plain(plain_type) = arg_type {
+ // No fancy builder function, we can just move the value directly into the struct.
+ params.push(quote! { #field_name: #plain_type });
+ } else if let ArgType::TraitBound(bound_type) = arg_type {
+ // Trait bounds are much trickier. We need a special syntax to accept them in the
+ // contructor, and generic parameters need to be added to the builder struct to make
+ // it work.
+ let builder_name = field.builder_name();
+ params.push(quote! { #builder_name : impl #bound_type });
+ let mut builder_args = Vec::new();
+ for (_, borrow) in field.borrows.iter().enumerate() {
+ let borrowed_name = &info.fields[borrow.index].name;
+ if borrow.mutable {
+ builder_args.push(quote! { &mut #borrowed_name });
+ } else {
+ builder_args.push(quote! { &#borrowed_name });
+ }
+ }
+ code.push(quote! { let #field_name = #builder_name (#(#builder_args),*); });
+ }
+ if field.is_mutably_borrowed() {
+ code.push(quote! { let mut #field_name = #field_name; });
+ } else {
+ code.push(quote! { let #field_name = #field_name; });
+ value_consumers.push(quote! { #field_name: &#field_name });
+ }
+ }
+ for (_ty, ident) in info.generic_consumers() {
+ template_consumers.push(quote! { #ident: ::core::marker::PhantomData });
+ }
+ let generic_params = info.generic_params();
+ let where_clause = &info.generics.where_clause;
+ let borrowed_generic_params_inferred = info.borrowed_generic_params_inferred();
+ Ok(quote! {
+ fn check_if_okay_according_to_checkers<#generic_params>(
+ #(#params,)*
+ )
+ #where_clause
+ {
+ #(#code;)*
+ BorrowedFields::#borrowed_generic_params_inferred {
+ #(#value_consumers,)*
+ #(#template_consumers,)*
+ };
+ }
+ })
+}