aeth_window_macros/
lib.rs1use proc_macro::TokenStream;
2use proc_macro2::Span;
3use quote::quote;
4use syn::{FnArg, Ident, ItemFn, Pat, parse_macro_input};
5
6fn collect_fn_args(item_fn: &ItemFn) -> Vec<Ident> {
7 item_fn
8 .sig
9 .inputs
10 .iter()
11 .filter_map(|input| {
12 if let FnArg::Typed(typed) = input {
13 Some(typed)
14 } else {
15 None
16 }
17 })
18 .filter_map(|typed| {
19 if let Pat::Ident(pat) = typed.pat.as_ref() {
20 Some(pat.ident.clone())
21 } else {
22 None
23 }
24 })
25 .collect()
26}
27
28fn is_mutable_method(item_fn: &ItemFn) -> Option<bool> {
29 Some(
30 item_fn
31 .sig
32 .inputs
33 .iter()
34 .filter_map(|input| {
35 if let FnArg::Receiver(receiver) = input {
36 Some(receiver)
37 } else {
38 None
39 }
40 })
41 .next()?
42 .mutability
43 .is_some(),
44 )
45}
46
47#[proc_macro_attribute]
48pub fn forward_winit_window_method(_attr: TokenStream, item: TokenStream) -> TokenStream {
49 let item_fn = parse_macro_input!(item as ItemFn);
50 let args = collect_fn_args(&item_fn);
51 let mutable =
52 is_mutable_method(&item_fn).expect("Must be a method of AccessWinitWindow trait extension");
53 let vis = item_fn.vis;
54 let sig = item_fn.sig;
55 let name = sig.ident.clone();
56 let method = Ident::new(
57 if mutable {
58 "map_winit_window_mut"
59 } else {
60 "map_winit_window"
61 },
62 Span::call_site(),
63 );
64 TokenStream::from(quote! {
65 #[doc = concat!("Invoke [`winit::window::Window::", stringify!(#name), "`].")]
66 #vis #sig {
67 self.#method(move |v| v.#name(#(#args),*))
68 }
69 })
70}
71
72#[proc_macro_attribute]
73pub fn forward_winit_active_event_loop_method(
74 _attr: TokenStream,
75 item: TokenStream,
76) -> TokenStream {
77 let item_fn = parse_macro_input!(item as ItemFn);
78 let args = collect_fn_args(&item_fn);
79 is_mutable_method(&item_fn)
80 .expect("Must be a method of AccessWinitActiveEventLoop trait extension");
81 let vis = item_fn.vis;
82 let sig = item_fn.sig;
83 let name = sig.ident.clone();
84 TokenStream::from(quote! {
85 #[doc = concat!("Invoke [`winit::event_loop::ActiveEventLoop::", stringify!(#name), "`].")]
86 #vis #sig {
87 self.run_with_active_event_loop(move |v| { v.#name(#(#args),*) })
88 .await
89 }
90 })
91}