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
use std::collections::HashSet;

use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::parse::Parse;
use syn::{parse_macro_input, Ident, Token};

struct InputConsumerMacro {
	name: Ident,
	types: Vec<Ident>,
}

impl Parse for InputConsumerMacro {
	fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
		let mut types: Vec<Ident> = Vec::new();
		let name: Ident = input.parse()?;
		input.parse::<Token![;]>()?;
		while !input.is_empty() {
			let ty: Ident = input.parse()?;
			types.push(ty);
			if !input.is_empty() {
				input.parse::<Token![,]>()?;
			}
		}
		Ok(InputConsumerMacro { name, types })
	}
}

#[proc_macro]
pub fn derive_input_consumer(input: TokenStream) -> TokenStream {
	let mut subtypes_str: HashSet<&str> = HashSet::from([
		"AnyButtonConsumer",
		"ButtonConsumer",
		"HotkeyConsumer",
		"CursorPositionConsumer",
		"CursorMotionConsumer",
		"ScrollConsumer",
		"ResizeConsumer",
		"FocusConsumer",
		"CursorInWindowConsumer",
		"CloseConsumer",
	]);
	let InputConsumerMacro { name, types } = parse_macro_input!(input as InputConsumerMacro);

	for ty in types {
		subtypes_str.remove(ty.to_string().as_str());
	}

	let mut subtypes: Vec<Ident> = Vec::new();
	for t in subtypes_str {
		subtypes.push(format_ident!("{}", t));
	}

	let iter = subtypes.iter();

	let expanded = quote! {
			impl InputConsumer for #name {}
			impl<'a> From<&'a mut #name> for &'a mut dyn InputConsumer {
				fn from(val: &'a mut #name) -> Self {
					val as &'a mut dyn InputConsumer
				}
			}
			use input::*;
			#(impl #iter for #name {fn accepts(&self) -> bool {false}})*
		};
	TokenStream::from(expanded)
}

// #[proc_macro]
// pub fn better_derive_input_consumer(input: TokenStream) -> TokenStream {
// 	let InputConsumerMacro {
// 		name,
// 		types
// 	} = parse_macro_input!(input as InputConsumerMacro);
// 	if types.contains(&format_ident!("AnyButtonConsumer")) {

// 	}
// 	todo!()
// }

#[test]
fn test() {
	assert_eq!(
		syn::parse_str::<Ident>("Hello").unwrap().to_string(),
		"Hello"
	);
}