lib.rs 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. use proc_macro::TokenStream;
  2. use syn::{parse_macro_input, DeriveInput};
  3. use quote::{quote,format_ident};
  4. use convert_case::{Case, Casing};
  5. #[proc_macro_derive(Entity, attributes(microrm))]
  6. pub fn derive_model(tokens: TokenStream) -> TokenStream {
  7. let input = parse_macro_input!(tokens as DeriveInput);
  8. let struct_name = &input.ident;
  9. let enum_name = format_ident!("{}Columns", &input.ident);
  10. let table_name = format!("{}", struct_name).to_case(Case::Snake);
  11. if let syn::Data::Struct(st) = input.data {
  12. if let syn::Fields::Named(fields) = st.fields {
  13. let mut variants = syn::punctuated::Punctuated::<syn::Ident, syn::token::Comma>::new();
  14. let mut field_names = syn::punctuated::Punctuated::<proc_macro2::TokenStream, syn::token::Comma>::new();
  15. let mut value_references = syn::punctuated::Punctuated::<proc_macro2::TokenStream, syn::token::Comma>::new();
  16. for name in fields.named.iter() {
  17. let converted_case = format!("{}", name.ident.as_ref().unwrap().clone()).to_case(Case::UpperCamel);
  18. let converted_case = format_ident!("{}", converted_case);
  19. variants.push(converted_case.clone());
  20. let field_name = name.ident.as_ref().unwrap().clone();
  21. let field_name_str = format!("{}", field_name);
  22. field_names.push(quote!{ Self::Column::#converted_case => #field_name_str }.into());
  23. value_references.push(quote!{ &self. #field_name });
  24. }
  25. let ret = quote!{
  26. #[derive(Clone,Copy,strum::IntoStaticStr,strum::EnumCount)]
  27. enum #enum_name {
  28. #variants
  29. }
  30. impl crate::model::Entity for #struct_name {
  31. fn table_name() -> &'static str { #table_name }
  32. type Column = #enum_name;
  33. fn column_count() -> usize {
  34. <Self::Column as strum::EnumCount>::COUNT
  35. }
  36. fn index(c: Self::Column) -> usize {
  37. c as usize
  38. }
  39. fn name(c: Self::Column) -> &'static str {
  40. match c {
  41. #field_names
  42. }
  43. }
  44. fn values(&self) -> Vec<&dyn rusqlite::ToSql> {
  45. vec![ #value_references ]
  46. }
  47. }
  48. }.into();
  49. ret
  50. }
  51. else { panic!("Can only use derive(Model) on non-unit structs with named fields!") }
  52. }
  53. else { panic!("Can only use derive(Model) on structs!") }
  54. }