1use proc_macro::TokenStream;
2use darling::FromDeriveInput;
3use quote::quote;
4
5#[proc_macro_derive(Command)]
6pub fn derive_command(input: TokenStream) -> TokenStream {
7 let input = syn::parse_macro_input!(input as syn::DeriveInput);
8 let input_name = &input.ident;
9
10 let token = quote! {
11 impl ::nitinol::Command for #input_name {}
12 };
13
14 token.into()
15}
16
17#[derive(FromDeriveInput)]
18#[darling(attributes(persist))]
19struct PersistAttribute {
20 #[darling(default)]
21 key: String,
22 enc: String,
23 dec: String
24}
25
26#[proc_macro_derive(Event, attributes(persist))]
27pub fn derive_event(input: TokenStream) -> TokenStream {
28 let input = syn::parse_macro_input!(input as syn::DeriveInput);
29 let attr = match PersistAttribute::from_derive_input(&input) {
30 Ok(v) => v,
31 Err(e) => return e.write_errors().into()
32 };
33 let input_name = &input.ident;
34
35 let event_type = if attr.key.is_empty() {
36 to_kebab_case(&input_name.to_string())
37 } else {
38 attr.key
39 };
40
41 let enc = syn::parse_str::<syn::Expr>(&attr.enc).unwrap();
42 let dec = syn::parse_str::<syn::Expr>(&attr.dec).unwrap();
43
44 let token = quote! {
45 impl ::nitinol::Event for #input_name {
46 const EVENT_TYPE: &'static str = #event_type;
47 fn as_bytes(&self) -> Result<Vec<u8>, ::nitinol::errors::SerializeError> {
48 Ok(#enc(self)?)
49 }
50 fn from_bytes(bytes: &[u8]) -> Result<Self, ::nitinol::errors::DeserializeError> {
51 Ok(#dec(bytes)?)
52 }
53 }
54 };
55
56 token.into()
57}
58
59fn to_kebab_case(input: &str) -> String {
60 input.chars().fold(String::new(), |mut acc, c| {
61 if c.is_uppercase() {
62 if !acc.is_empty() {
63 acc.push('-');
64 }
65 acc.push(c.to_ascii_lowercase());
66 } else {
67 acc.push(c);
68 }
69 acc
70 })
71}