1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
extern crate proc_macro;
use proc_macro2::TokenStream;
use quote::quote;
use quote::*;

macro_rules! state_attribute {
  ($fn:ident, $implement:ident, $derive:ident) => {
    #[proc_macro_attribute]
    pub fn $fn(attr: proc_macro::TokenStream, item: proc_macro::TokenStream) -> proc_macro::TokenStream {
      let attr = TokenStream::from(attr);
      let ast: syn::ItemFn = syn::parse(item).unwrap();
      let mut tokens = TokenStream::new();

      ast.block.to_tokens(&mut tokens);
      let expanded = quote!{
        impl $implement for #attr {
          fn $fn(&mut self) #tokens
        }
      };
      proc_macro::TokenStream::from(expanded)
    }

    #[proc_macro_derive($implement)]
    pub fn $derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
      let ast: syn::DeriveInput = syn::parse(input).unwrap();
      let name = &ast.ident;
      let expanded = quote! {
        impl $implement for #name {
          fn $fn(&mut self) {}
        }
      };
      proc_macro::TokenStream::from(expanded)
    }
  };
}

state_attribute!(on_start, OnStart, derive_on_start);
state_attribute!(on_stop, OnStop, derive_on_stop);

#[proc_macro_attribute]
pub fn on_event(attr: proc_macro::TokenStream, item: proc_macro::TokenStream) -> proc_macro::TokenStream {
  let attr = TokenStream::from(attr);
  let ast: syn::ItemFn = syn::parse(item).unwrap();
  let mut tokens = TokenStream::new();
  ast.block.to_tokens(&mut tokens);
  let expanded = quote!{
    impl OnEvent for #attr {
      fn on_event(&mut self, window: &mut Window, events: &mut EventsLoop) #tokens
    }
  };
  proc_macro::TokenStream::from(expanded)
}

#[proc_macro_derive(OnEvent)]
pub fn derive_on_event(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
  let ast: syn::DeriveInput = syn::parse(input).unwrap();
  let name = &ast.ident;
  let expanded = quote! {
    impl OnEvent for #name {
      fn on_event(&mut self, window: &mut Window, events: &mut EventsLoop) {}
    }
  };
  proc_macro::TokenStream::from(expanded)
}

#[proc_macro_attribute]
pub fn on_update(attr: proc_macro::TokenStream, item: proc_macro::TokenStream) -> proc_macro::TokenStream {
  let attr = TokenStream::from(attr);
  let ast: syn::ItemFn = syn::parse(item).unwrap();
  let mut tokens = TokenStream::new();
  ast.block.to_tokens(&mut tokens);
  let expanded = quote!{
    impl OnUpdate for #attr {
      fn on_update(&mut self, elapsed: u128, window: &mut Window) #tokens
    }
  };
  proc_macro::TokenStream::from(expanded)
}

#[proc_macro_derive(OnUpdate)]
pub fn derive_on_update(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
  let ast: syn::DeriveInput = syn::parse(input).unwrap();
  let name = &ast.ident;
  let expanded = quote! {
    impl OnUpdate for #name {
      fn on_update(&mut self, elapsed: u128, window: &mut Window) {}
    }
  };
  proc_macro::TokenStream::from(expanded)
}