From 709eb44ccb8d08ad7f26cdac2932eadc7ccd48e7 Mon Sep 17 00:00:00 2001 From: Melody Horn / boringcactus Date: Fri, 18 Jun 2021 10:12:16 -0600 Subject: make model metadata available in AppConfig --- tosin-macros/src/lib.rs | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) (limited to 'tosin-macros/src/lib.rs') diff --git a/tosin-macros/src/lib.rs b/tosin-macros/src/lib.rs index 7efbac6..408378f 100644 --- a/tosin-macros/src/lib.rs +++ b/tosin-macros/src/lib.rs @@ -2,6 +2,8 @@ extern crate proc_macro; +use std::fs; + use proc_macro::TokenStream; use quote::quote; @@ -19,9 +21,9 @@ fn impl_model(ast: &syn::DeriveInput) -> TokenStream { let name = &ast.ident; let gen = quote! { impl #name { - fn hello_macro() { - println!("Hello, Macro! My name is {}!", stringify!(#name)); - } + pub const META: tosin::db::models::ModelMeta = tosin::db::models::ModelMeta { + name: stringify!(#name), + }; } }; gen.into() @@ -55,3 +57,36 @@ pub fn gather_migrations(_input: TokenStream) -> TokenStream { gen.into() } + +#[proc_macro] +pub fn gather_models(_input: TokenStream) -> TokenStream { + let call_site = proc_macro::Span::call_site(); + let call_site_file = call_site.source_file(); + let call_site_path = call_site_file.path(); + if !call_site_file.is_real() { + panic!("call site does not have a real path"); + } + + let call_site_ast = syn::parse_file(&fs::read_to_string(call_site_path).unwrap()).unwrap(); + let models = call_site_ast.items.iter() + .filter_map(|item| if let syn::Item::Struct(item) = item { Some(item) } else { None }) + .filter(|item| item.attrs.iter().any(|attr| { + let attr = if let Ok(syn::Meta::List(attr)) = attr.parse_meta() { attr } else { return false; }; + if attr.path.get_ident().map_or(false, |hopefully_derive| hopefully_derive == "derive") { + let mut derived = attr.nested.iter() + .filter_map(|derived| if let syn::NestedMeta::Meta(derived) = derived { Some(derived) } else { None }); + derived.any(|derived| derived.path().get_ident().map_or(false, |hopefully_model| hopefully_model == "Model")) + } else { + false + } + })) + .map(|item| &item.ident); + + let gen = quote! { + pub const ALL: &[tosin::db::models::ModelMeta] = &[ + #(#models::META),* + ]; + }; + + gen.into() +} -- cgit v1.2.3