1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use quote::{quote, ToTokens};
5use syn::{parse_macro_input, parse_quote, Data, DeriveInput, Fields};
6
7#[allow(clippy::too_many_lines)]
8#[proc_macro_derive(UserControl, attributes(parent, state, child, childSelf))]
9pub fn user_control_derive(input: TokenStream) -> TokenStream {
10 let input = parse_macro_input!(input as DeriveInput);
11 let name = &input.ident;
12 let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl();
13
14 let mut parent = parse_quote!(());
15 let mut state = parse_quote!(());
16 let mut child_field = None;
17
18 for attr in &input.attrs {
19 if attr.path().is_ident("parent") {
20 attr.parse_nested_meta(|meta| {
21 parent = meta.path.to_token_stream();
22 Ok(())
23 })
24 .expect("Error parsing parent type attribute");
25 } else if attr.path().is_ident("state") {
26 attr.parse_nested_meta(|meta| {
27 state = meta.path.to_token_stream();
28 Ok(())
29 })
30 .expect("Error parsing state type attribute");
31 }
32 }
33
34 let expanded = match &input.data {
35 Data::Enum(data_enum) => {
36 let variants = data_enum.variants.iter().map(|variant| {
37 let variant_name = &variant.ident;
38 match &variant.fields {
39 Fields::Unnamed(fields) => {
40 if fields.unnamed.len() != 1{
41 panic!("Multiple element in enum case");
42 }
43 let field_type = fields.unnamed.first().expect("").ty.to_token_stream();
44 (quote! {
45 #name::#variant_name(el) => UserControl::surface(el.into(), parent, state),
46 },quote! {
47 #name::#variant_name(el) => UserControl::event(el.into(), canvas, event, parent, state),
48 },quote! {
49 #name::#variant_name(el) => UserControl::update(el.into(), canvas, elapsed, parent, state),
50 },quote! {
51 #name::#variant_name(el) => UserControl::draw(el.into(), canvas, parent, state),
52 },quote! {
53 impl #impl_generics From<#field_type> for #name #type_generics #where_clause {
54 fn from(value: #field_type) -> Self {
55 #name::#variant_name(value)
56 }
57 }
58 })
59 }
60 _ => panic!("Wrong enum format"),
61 }
62 }).collect::<Vec<(proc_macro2::TokenStream,proc_macro2::TokenStream,proc_macro2::TokenStream,proc_macro2::TokenStream,proc_macro2::TokenStream)>>();
63 let surfaces = variants.iter().map(|(s, _, _, _, _)| s);
64 let events = variants.iter().map(|(_, s, _, _, _)| s);
65 let updates = variants.iter().map(|(_, _, s, _, _)| s);
66 let draws = variants.iter().map(|(_, _, _, s, _)| s);
67 let froms = variants.iter().map(|(_, _, _, _, s)| s);
68
69 quote! {
70 impl #impl_generics UserControl<#parent, #state> for #name #type_generics #where_clause {
71 fn surface(this: Ref<Self>, parent: Ref<#parent>, state: Ref<#state>) -> FRect {
72 match this.as_ref() {
73 #(#surfaces)*
74 }
75 }
76
77 fn event(
78 mut this: MutRef<Self>,
79 canvas: &Canvas<Window>,
80 event: Event,
81 parent: MutRef<#parent>,
82 state: MutRef<#state>,
83 ) -> Result<()> {
84 match this.as_mut() {
85 #(#events)*
86 }
87 }
88
89 fn update(
90 mut this: MutRef<Self>,
91 canvas: &Canvas<Window>,
92 elapsed: Duration,
93 parent: MutRef<#parent>,
94 state: MutRef<#state>,
95 ) -> Result<()> {
96 match this.as_mut() {
97 #(#updates)*
98 }
99 }
100
101 fn draw(this: Ref<Self>, canvas: &mut Canvas<Window>, parent: Ref<#parent>, state: Ref<#state>) -> Result<()> {
102 match this.as_ref() {
103 #(#draws)*
104 }
105 }
106 }
107
108 #(#froms)*
109 }
110 }
111 Data::Struct(data_struct) => {
112 for field in &data_struct.fields {
113 for attr in &field.attrs {
114 if attr.path().is_ident("child") || attr.path().is_ident("childSelf") {
115 if child_field.is_some()
116 || (attr.path().is_ident("child") && attr.path().is_ident("childSelf"))
117 {
118 panic!("the struct can't have multiple child.");
119 }
120 child_field = Some((
121 field.ident.clone().expect("Expected named field"),
122 attr.path().is_ident("childSelf"),
123 ));
124 }
125 }
126 }
127 let (child_field, child_self) =
128 child_field.expect("Expected a field with the 'child' attribute");
129
130 let (name_parent, used_parent) = if child_self {
131 (
132 quote! {_}.to_token_stream(),
133 quote! {this}.to_token_stream(),
134 )
135 } else {
136 (
137 quote! {parent}.to_token_stream(),
138 quote! {parent}.to_token_stream(),
139 )
140 };
141 quote! {
142 impl #impl_generics UserControl<#parent, #state> for #name #type_generics #where_clause {
143 fn surface(this: Ref<Self>, #name_parent: Ref<#parent>, state: Ref<#state>) -> FRect {
144 UserControl::surface((&this.#child_field).into(), #used_parent, state)
145 }
146
147 fn event( mut this: MutRef<Self>, canvas: &Canvas<Window>, event: Event, #name_parent: MutRef<#parent>, state: MutRef<#state>, ) -> Result<()> {
148 UserControl::event((&mut this.#child_field).into(), canvas, event, #used_parent, state)
149 }
150
151 fn update( mut this: MutRef<Self>, canvas: &Canvas<Window>, elapsed: Duration, #name_parent: MutRef<#parent>, state: MutRef<#state>, ) -> Result<()> {
152 UserControl::update((&mut this.#child_field).into(), canvas, elapsed, #used_parent, state)
153 }
154
155 fn draw(this: Ref<Self>, canvas: &mut Canvas<Window>, #name_parent: Ref<#parent>, state: Ref<#state>) -> Result<()> {
156 UserControl::draw((&this.#child_field).into(), canvas, #used_parent, state)
157 }
158 }
159 }
160 }
161 _ => panic!(
162 "\nHow to use the derive macro:\n\n\
163 #[parent(PARENT)]\n\
164 #[state(STATE)]\n\
165 enum A{{\n\
166 Child1(UserControl),\n\
167 Child2(UserControl),\n\
168 ...\n\
169 }}\n\n\
170 #[parent(PARENT)]\n\
171 #[state(STATE)]\n\
172 struct A{{\n\
173 #[child] or #[childSelf] for self as parent\n\
174 Child: UserControl\n\
175 }}"
176 ),
177 };
178 TokenStream::from(expanded)
179}