1use crate::util;
2use proc_macro2::{Span, TokenStream};
3use quote::ToTokens;
4use std::collections::HashSet;
5use syn::parse::{Error, Parse, ParseStream, Result};
6use syn::punctuated::Punctuated;
7use syn::spanned::Spanned;
8use syn::visit::{self, Visit};
9use syn::*;
10
11pub(crate) fn gen_ui_node(args: proc_macro::TokenStream, input: proc_macro::TokenStream) -> proc_macro::TokenStream {
12 let mut input = match syn::parse::<ItemImpl>(input.clone()) {
13 Ok(i) => i,
14 Err(e) => {
15 let mut r = proc_macro::TokenStream::from(e.to_compile_error());
18 r.extend(input);
19 return r;
20 }
21 };
22 let args = parse_macro_input!(args as Args);
23
24 let crate_ = util::crate_core();
25
26 let mut ui_node_path = None;
27
28 let ui_node = ident!("UiNode");
29
30 if let Some((_, path, _)) = input.trait_ {
32 let seg = path.segments.last().unwrap();
34 if seg.ident == ui_node {
35 ui_node_path = Some(path);
36 }
37 else {
39 abort!(
40 path.span(),
41 "expected inherent impl or `UiNode` trait impl, found `{}`",
42 quote! {#path}
43 )
44 }
45 }
46
47 let mut node_items = vec![];
48 let mut node_items_missing_del_level = vec![];
49 let mut other_items = vec![];
50 let mut node_item_names = HashSet::new();
51
52 let mut errors = util::Errors::default();
53
54 let missing_delegate_level =
58 take_missing_delegate_level(&mut input.attrs, &mut errors, &HashSet::new()).unwrap_or(util::LintLevel::Deny);
59 let missing_delegate_ident = ident!("missing_delegate");
60 let mut forbidden_lints = HashSet::new();
61 if let util::LintLevel::Forbid = missing_delegate_level {
62 forbidden_lints.insert(&missing_delegate_ident);
63 }
64 let forbidden_lints = forbidden_lints;
65
66 for mut item in input.items {
67 let mut is_node = false;
68
69 if let ImplItem::Fn(m) = &mut item {
70 if ui_node_path.is_some() {
72 is_node = true;
74 node_item_names.insert(m.sig.ident.clone());
75 }
76 else if let Some(index) = m.attrs.iter().position(|a| a.path().get_ident() == Some(&ui_node)) {
78 m.attrs.remove(index);
80 is_node = true;
82 node_item_names.insert(m.sig.ident.clone());
83 }
84
85 if is_node {
86 let item_level = take_missing_delegate_level(&mut m.attrs, &mut errors, &forbidden_lints).unwrap_or(missing_delegate_level);
87 node_items_missing_del_level.push(item_level);
88 }
89 }
90
91 if is_node {
92 node_items.push(item);
93 } else {
94 other_items.push(item);
95 }
96 }
97
98 let mut validate_manual_delegate = true;
99
100 if let Some(layout) = &node_item_names.get(&ident!("layout")) {
102 if !node_item_names.contains(&ident!("measure")) {
103 errors.push(
104 "`layout` is manual impl, but `measure` is auto impl, both must be auto or manual",
105 layout.span(),
106 );
107 }
108 } else if let Some(measure) = &node_item_names.get(&ident!("measure")) {
109 if !node_item_names.contains(&ident!("measure")) {
110 errors.push(
111 "`measure` is manual impl, but `layout` is auto impl, both must be auto or manual",
112 measure.span(),
113 );
114 }
115 }
116
117 let (new_node, args) = match args {
118 Args::NewNode(args) => {
119 let new_node = expand_new_node(args, &mut errors);
120 let args = syn::parse2::<Args>(new_node.delegate.to_token_stream()).unwrap();
121 (Some(new_node), args)
122 }
123 a => (None, a),
124 };
125
126 let auto_subs = if new_node.as_ref().map(|n| !n.auto_subs.is_empty()).unwrap_or(false) {
127 quote!(self.auto_subs();)
128 } else {
129 quote!()
130 };
131 let validate_auto_subs = !auto_subs.is_empty();
132
133 let default_ui_items = match args {
135 Args::NoDelegate => {
136 validate_manual_delegate = false;
137 no_delegate_absents(crate_.clone(), node_item_names, auto_subs)
138 }
139 Args::Delegate { delegate } => delegate_absents(crate_.clone(), node_item_names, delegate, auto_subs),
140 Args::DelegateList { delegate_list } => delegate_list_absents(crate_.clone(), node_item_names, delegate_list, auto_subs),
141 Args::NewNode(_) => {
142 unreachable!()
143 }
144 };
145
146 if validate_manual_delegate {
147 let validate = [
148 ident!("init"),
149 ident!("deinit"),
150 ident!("info"),
151 ident!("event"),
152 ident!("update"),
153 ident!("layout"),
155 ident!("render"),
156 ident!("render_update"),
157 ];
158
159 for (manual_impl, level) in node_items.iter().zip(node_items_missing_del_level.into_iter()) {
162 let mut validator = DelegateValidator::new(manual_impl);
163
164 if level == util::LintLevel::Allow || !validate.contains(validator.ident) {
165 continue;
166 }
167
168 validator.visit_impl_item(manual_impl);
169
170 if !validator.delegates {
171 let ident = validator.ident;
172 errors.push(
173 format_args!(
174 "auto impl delegates call to `{ident}`, but this manual impl does not\n\
175 `#[{missing_delegate_level}(zng::missing_delegate)]` is on",
176 ),
177 {
178 match manual_impl {
179 ImplItem::Fn(mtd) => mtd.block.span(),
180 _ => non_user_error!("expected a method"),
181 }
182 },
183 );
184 }
185 }
186 }
187 if validate_auto_subs {
188 if let Some(init_mtd) = node_items
189 .iter()
190 .map(|it| match it {
191 ImplItem::Fn(mtd) => mtd,
192 _ => non_user_error!("expected a method"),
193 })
194 .find(|it| it.sig.ident == "init")
195 {
196 let mut validator = AutoSubsValidator::new();
197
198 validator.visit_impl_item_fn(init_mtd);
199
200 if !validator.ok {
201 errors.push(
202 "auto impl generates `auto_subs`, but custom init does not call it\n\
203 add `self.auto_subs();` to custom init or remove `#[var]` and `#[event]` attributes",
204 init_mtd.block.span(),
205 );
206 }
207 }
208 }
209
210 if ui_node_path.is_none() && node_items.is_empty() && !other_items.is_empty() {
212 abort_call_site!("no `UiNode` method found, missing `UiNode for` in impl or `#[UiNode]` in methods")
213 }
214
215 let generics = input.generics;
216 let (impl_generics, _, where_clause) = generics.split_for_impl();
217 let self_ty = input.self_ty;
218
219 let in_node_impl = ui_node_path.is_some();
220
221 let ui_node_path = ui_node_path
224 .map(|p| p.to_token_stream())
225 .unwrap_or_else(|| quote! { #crate_::widget::node::UiNode });
226
227 let (impl_generics, self_ty, decl) = if let Some(new_node) = new_node {
229 let gens = new_node.impl_generics;
230 let custom_gen = &generics.params;
231 let sep = if custom_gen.trailing_punct() || custom_gen.is_empty() {
232 TokenStream::new()
233 } else {
234 quote!( , )
235 };
236
237 let mut node_custom_gen = TokenStream::new();
238 let mut node_sep = TokenStream::new();
239 let node_ident = new_node.ident;
240 let mut self_ty_error = true;
241 if let syn::Type::Path(p) = &*self_ty {
242 if p.path.segments.len() == 1 {
243 let seg = &p.path.segments[0];
244 if seg.ident == node_ident {
245 self_ty_error = false;
246 if let PathArguments::AngleBracketed(a) = &seg.arguments {
247 node_custom_gen = a.args.to_token_stream();
248 if !a.args.trailing_punct() && !a.args.is_empty() {
249 node_sep = quote!( , );
250 }
251 }
252 }
253 }
254 }
255 if self_ty_error {
256 errors.push(format!("expected `{node_ident}`"), self_ty.span());
257 }
258 let node_gen = new_node.node_generics;
259
260 let impl_generics = quote! { <#custom_gen #sep #gens> };
261 let self_ty = quote! { #node_ident<#node_custom_gen #node_sep #node_gen> };
262
263 let mut decl = new_node.decl;
264
265 if !new_node.auto_subs.is_empty() {
266 let init = new_node.auto_subs;
267
268 decl.extend(quote! {
269 impl #impl_generics #self_ty #where_clause {
270 fn auto_subs(&mut self) {
272 #init
273 }
274 }
275 });
276 }
277
278 (impl_generics, self_ty, decl)
279 } else {
280 (impl_generics.to_token_stream(), self_ty.to_token_stream(), quote!())
281 };
282
283 let result = if in_node_impl {
284 quote! {
285 #errors
286
287 #decl
288
289 impl #impl_generics #ui_node_path for #self_ty #where_clause {
290 #(#node_items)*
291 #(#default_ui_items)*
292 #(#other_items)*
293 }
294 }
295 } else {
296 let input_attrs = input.attrs;
297 quote! {
298 #errors
299
300 #decl
301
302 #(#input_attrs)*
303 impl #impl_generics #self_ty #where_clause {
304 #(#other_items)*
305 }
306
307 impl #impl_generics #ui_node_path for #self_ty #where_clause {
308 #(#node_items)*
309 #(#default_ui_items)*
310 }
311 }
312 };
313
314 result.into()
320}
321
322macro_rules! make_absents {
323 ($user_mtds:ident $([fn $ident:ident $($tt:tt)*])+) => {{
324 let mut absents = vec![];
325 let user_mtds = $user_mtds;
326 $(
327 if !user_mtds.contains(&ident!(stringify!($ident))) {
328 absents.push(parse_quote! {
329
330 #[allow(clippy::borrow_deref_ref)]
331 fn $ident $($tt)*
332 });
333 }
334 )+
335 absents
336 }};
337}
338
339fn no_delegate_absents(crate_: TokenStream, user_mtds: HashSet<Ident>, auto_init: TokenStream) -> Vec<ImplItem> {
340 make_absents! { user_mtds
341 [fn info(&mut self, info: &mut #crate_::widget::info::WidgetInfoBuilder) { }]
342
343 [fn init(&mut self) { #auto_init }]
344
345 [fn deinit(&mut self) { }]
346
347 [fn update(&mut self, updates: &#crate_::update::WidgetUpdates) { }]
348
349 [fn event(&mut self, update: &#crate_::update::EventUpdate) { }]
350
351 [fn measure(&mut self, wm: &mut #crate_::widget::info::WidgetMeasure) -> #crate_::layout::unit::PxSize {
352 #crate_::layout::context::LAYOUT.constraints().fill_size()
353 }]
354
355 [fn layout(&mut self, wl: &mut #crate_::widget::info::WidgetLayout) -> #crate_::layout::unit::PxSize {
356 #crate_::layout::context::LAYOUT.constraints().fill_size()
357 }]
358 [fn render(&mut self, frame: &mut #crate_::render::FrameBuilder) { }]
359
360 [fn render_update(&mut self, update: &mut #crate_::render::FrameUpdate) { }]
361 }
362}
363
364fn delegate_absents(crate_: TokenStream, user_mtds: HashSet<Ident>, borrow: Expr, auto_init: TokenStream) -> Vec<ImplItem> {
365 let child = ident_spanned!(borrow.span()=> "child");
366
367 let deref = quote_spanned! {borrow.span()=>
368 &mut *#child
369 };
370
371 make_absents! { user_mtds
372 [fn info(&mut self, info: &mut #crate_::widget::info::WidgetInfoBuilder) {
373 let mut #child = {#borrow};
374 #crate_::widget::node::UiNode::info(#deref, info);
375 }]
376
377 [fn init(&mut self) {
378 #auto_init
379 let mut #child = {#borrow};
380 #crate_::widget::node::UiNode::init(#deref);
381 }]
382
383 [fn deinit(&mut self) {
384 let mut #child = {#borrow};
385 #crate_::widget::node::UiNode::deinit(#deref);
386 }]
387
388 [fn update(&mut self, updates: &#crate_::update::WidgetUpdates) {
389 let mut #child = {#borrow};
390 #crate_::widget::node::UiNode::update(#deref, updates);
391 }]
392
393 [fn event(&mut self, update: &#crate_::update::EventUpdate) {
394 let mut #child = {#borrow};
395 #crate_::widget::node::UiNode::event(#deref, update);
396 }]
397
398 [fn measure(&mut self, wm: &mut #crate_::widget::info::WidgetMeasure) -> #crate_::layout::unit::PxSize {
399 let mut #child = {#borrow};
400 #crate_::widget::node::UiNode::measure(#deref, wm)
401 }]
402
403 [fn layout(&mut self, wl: &mut #crate_::widget::info::WidgetLayout) -> #crate_::layout::unit::PxSize {
404 let mut #child = {#borrow};
405 #crate_::widget::node::UiNode::layout(#deref, wl)
406 }]
407
408 [fn render(&mut self, frame: &mut #crate_::render::FrameBuilder) {
409 let mut #child = {#borrow};
410 #crate_::widget::node::UiNode::render(#deref, frame);
411 }]
412
413 [fn render_update(&mut self, update: &mut #crate_::render::FrameUpdate) {
414 let mut #child = {#borrow};
415 #crate_::widget::node::UiNode::render_update(#deref, update);
416 }]
417 }
418}
419
420fn delegate_list_absents(crate_: TokenStream, user_mtds: HashSet<Ident>, borrow: Expr, auto_init: TokenStream) -> Vec<ImplItem> {
421 let children = ident_spanned!(borrow.span()=> "children");
422 let deref = quote_spanned! {borrow.span()=>
423 &mut *#children
424 };
425 make_absents! { user_mtds
426 [fn info(&mut self, info: &mut #crate_::widget::info::WidgetInfoBuilder) {
427 let #children = {#borrow};
428 #crate_::widget::node::ui_node_list_default::info_all(#deref, info);
429 }]
430
431 [fn init(&mut self) {
432 #auto_init
433 let #children = {#borrow};
434 #crate_::widget::node::ui_node_list_default::init_all(#deref);
435 }]
436
437 [fn deinit(&mut self) {
438 let #children = {#borrow};
439 #crate_::widget::node::ui_node_list_default::deinit_all(#deref);
440 }]
441
442 [fn update(&mut self, updates: &#crate_::update::WidgetUpdates) {
443 let #children = {#borrow};
444 #crate_::widget::node::ui_node_list_default::update_all(#deref, updates);
445 }]
446
447 [fn event(&mut self, update: &#crate_::update::EventUpdate) {
448 let #children = {#borrow};
449 #crate_::widget::node::ui_node_list_default::event_all(#deref, update);
450 }]
451
452 [fn measure(&mut self, wm: &mut #crate_::widget::info::WidgetMeasure) -> #crate_::layout::unit::PxSize {
453 let #children = {#borrow};
454 #crate_::widget::node::ui_node_list_default::measure_all(#deref, wm)
455 }]
456
457 [fn layout(&mut self, wl: &mut #crate_::widget::info::WidgetLayout) -> #crate_::layout::unit::PxSize {
458 let #children = {#borrow};
459 #crate_::widget::node::ui_node_list_default::layout_all(#deref, wl)
460 }]
461
462 [fn render(&mut self, frame: &mut #crate_::render::FrameBuilder) {
463 let #children = {#borrow};
464 #crate_::widget::node::ui_node_list_default::render_all(#deref, frame);
465 }]
466
467 [fn render_update(&mut self, update: &mut #crate_::render::FrameUpdate) {
468 let #children = {#borrow};
469 #crate_::widget::node::ui_node_list_default::render_update_all(#deref, update);
470 }]
471 }
472}
473
474enum Args {
476 NoDelegate,
478 Delegate { delegate: Expr },
481 DelegateList { delegate_list: Expr },
484 NewNode(ArgsNewNode),
486}
487
488impl Parse for Args {
489 fn parse(args: ParseStream) -> Result<Self> {
490 if args.peek(Token![struct]) {
491 args.parse().map(Args::NewNode)
492 } else if args.peek(Ident) {
493 let arg0 = args.parse::<Ident>()?;
494
495 let args = if arg0 == ident!("child") {
496 Args::Delegate {
497 delegate: parse_quote_spanned!(arg0.span()=> &mut self.child),
498 }
499 } else if arg0 == ident!("children") {
500 Args::DelegateList {
501 delegate_list: parse_quote_spanned!(arg0.span()=> &mut self.children),
502 }
503 } else if arg0 == ident!("none") {
504 Args::NoDelegate
505 } else {
506 let delegate = ident!("delegate");
507
508 if arg0 == delegate {
509 let delegate = parse_delegate(args, &arg0)?;
510 Args::Delegate { delegate }
511 } else {
512 let delegate_list = ident!("delegate_list");
513
514 if arg0 == delegate_list {
515 let delegate_list = parse_delegate(args, &arg0)?;
516 Args::DelegateList { delegate_list }
517 } else {
518 return Err(Error::new(
519 arg0.span(),
520 "expected `child`, `children`, `delegate`, or, `delegate_list`",
521 ));
522 }
523 }
524 };
525
526 Ok(args)
527 } else {
528 Err(Error::new(
529 Span::call_site(),
530 "missing macro argument, expected `none`, `child`, `children`, `delegate`, `delegate_list`, or `struct`",
531 ))
532 }
533 }
534}
535
536fn parse_delegate(args: ParseStream, ident: &Ident) -> Result<Expr> {
537 let colon = args
538 .parse::<Token![=]>()
539 .map_err(|_| Error::new(ident.span(), format!("expected `{ident} = <expr>`")))?;
540 let expr: Expr = args
541 .parse()
542 .map_err(|_| Error::new(colon.span(), format!("expected `{ident} = <expr>`")))?;
543
544 Ok(expr)
545}
546
547struct DelegateValidator<'a> {
548 pub ident: &'a Ident,
549 pub list_variant: Ident,
550 pub list_specific_variant: Ident,
551 args_count: u8,
552 pub delegates: bool,
553
554 todo_paths: Vec<Path>,
555}
556impl<'a> DelegateValidator<'a> {
557 fn new(manual_impl: &'a ImplItem) -> Self {
558 if let ImplItem::Fn(m) = manual_impl {
559 DelegateValidator {
560 ident: &m.sig.ident,
561 list_variant: ident!("{}_all", m.sig.ident),
562 list_specific_variant: ident!("item_{}", m.sig.ident),
563 args_count: (m.sig.inputs.len() - 1) as u8,
564 delegates: false,
565
566 todo_paths: vec![parse_quote!(todo), parse_quote!(std::todo)],
567 }
568 } else {
569 panic!("")
570 }
571 }
572}
573impl<'ast> Visit<'ast> for DelegateValidator<'_> {
574 fn visit_expr_method_call(&mut self, i: &'ast ExprMethodCall) {
575 if (&i.method == self.ident && i.args.len() as u8 == self.args_count)
576 || i.method == self.list_variant
577 || i.method == self.list_specific_variant
578 {
579 self.delegates = true;
580 }
581 visit::visit_expr_method_call(self, i)
582 }
583
584 fn visit_expr_call(&mut self, i: &'ast ExprCall) {
585 if let Expr::Path(p) = &*i.func {
586 let len = p.path.segments.len();
587 if len >= 2 {
588 let q = &p.path.segments[len - 2].ident;
589 if q == "UiNode" {
590 let method = &p.path.segments[len - 1].ident;
591 if (method == self.ident && i.args.len() as u8 == self.args_count + 1)
592 || method == &self.list_variant
593 || method == &self.list_specific_variant
594 {
595 self.delegates = true;
596 }
597 }
598 }
599 }
600 visit::visit_expr_call(self, i)
601 }
602
603 fn visit_macro(&mut self, i: &'ast Macro) {
604 for p in &self.todo_paths {
605 if &i.path == p {
606 self.delegates = true;
607 break;
608 }
609 }
610 visit::visit_macro(self, i)
611 }
612}
613
614struct AutoSubsValidator {
615 ident: Ident,
616 pub ok: bool,
617}
618impl AutoSubsValidator {
619 fn new() -> Self {
620 Self {
621 ident: ident!("auto_subs"),
622 ok: false,
623 }
624 }
625}
626impl<'ast> Visit<'ast> for AutoSubsValidator {
627 fn visit_expr_method_call(&mut self, i: &'ast ExprMethodCall) {
628 if i.method == self.ident && i.args.is_empty() {
629 self.ok = true;
630 }
631 visit::visit_expr_method_call(self, i)
632 }
633}
634
635fn take_missing_delegate_level(
637 attrs: &mut Vec<Attribute>,
638 errors: &mut util::Errors,
639 forbidden: &HashSet<&Ident>,
640) -> Option<util::LintLevel> {
641 let mut r = None;
642 for (lint_ident, level, _) in util::take_zng_lints(attrs, errors, forbidden) {
643 if lint_ident == "missing_delegate" {
644 r = Some(level);
645 }
646 }
647 r
648}
649
650struct ArgsNewNode {
651 ident: Ident,
652 explicit_generics: Option<Generics>,
653 fields: Punctuated<ArgsNewNodeField, Token![,]>,
654}
655impl Parse for ArgsNewNode {
656 fn parse(input: ParseStream) -> Result<Self> {
657 let _: Token![struct] = input.parse()?;
658 let ident: Ident = input.parse()?;
659 let explicit_generics = if input.peek(Token![<]) { Some(input.parse()?) } else { None };
660 let inner;
661 braced!(inner in input);
662 let fields = Punctuated::parse_terminated(&inner)?;
663 Ok(ArgsNewNode {
664 ident,
665 explicit_generics,
666 fields,
667 })
668 }
669}
670
671struct ArgsNewNodeField {
672 attrs: Vec<Attribute>,
673 kind: ArgsNewNodeFieldKind,
674 ident: Ident,
675 ty: Type,
676}
677impl Parse for ArgsNewNodeField {
678 fn parse(input: ParseStream) -> Result<Self> {
679 let mut attrs = Attribute::parse_outer(input)?;
680 let ident = input.parse()?;
681 let kind = ArgsNewNodeFieldKind::from_attrs(&mut attrs);
682 let _: Token![:] = input.parse()?;
683 let ty = input.parse()?;
684 Ok(ArgsNewNodeField { attrs, kind, ident, ty })
685 }
686}
687
688enum ArgsNewNodeFieldKind {
689 Var,
690 Event,
691 Custom,
692}
693impl ArgsNewNodeFieldKind {
694 fn from_attrs(attrs: &mut Vec<Attribute>) -> Self {
695 let mut r = ArgsNewNodeFieldKind::Custom;
696 let mut rmv = None;
697
698 for (i, attr) in attrs.iter().enumerate() {
699 if let Some(id) = attr.path().get_ident() {
700 if id == "var" {
701 r = ArgsNewNodeFieldKind::Var;
702 rmv = Some(i);
703 break;
704 } else if id == "event" {
705 r = ArgsNewNodeFieldKind::Event;
706 rmv = Some(i);
707 break;
708 }
709 }
710 }
711
712 if let Some(i) = rmv {
713 attrs.remove(i);
714 }
715
716 r
717 }
718}
719
720fn expand_new_node(args: ArgsNewNode, errors: &mut util::Errors) -> ExpandedNewNode {
721 let mut delegate = ident!("none");
722 let mut impl_generics = TokenStream::new();
723 let mut node_generics = TokenStream::new();
724 let mut node_fields = TokenStream::new();
725 let mut auto_subs = TokenStream::new();
726
727 let crate_ = crate::util::crate_core();
728
729 if let Some(g) = args.explicit_generics {
730 for p in g.params.into_iter() {
731 if let GenericParam::Type(t) = p {
732 t.to_tokens(&mut impl_generics);
733 impl_generics.extend(quote!( , ));
734
735 let cfg = util::Attributes::new(t.attrs).cfg;
736 let ident = t.ident;
737 node_generics.extend(quote! {
738 #cfg #ident ,
739 });
740 } else {
741 errors.push("only type params are supported", p.span());
742 }
743 }
744 }
745
746 for ArgsNewNodeField {
747 attrs, kind, ident, ty, ..
748 } in args.fields
749 {
750 let attrs = util::Attributes::new(attrs);
751 let cfg = attrs.cfg;
752 let mut member_attrs = attrs.docs;
753 member_attrs.extend(attrs.lints);
754 member_attrs.extend(attrs.others);
755
756 if ident == ident!("child") || ident == ident!("children") || ident == ident!("children_iter") {
757 delegate = ident.clone();
758 }
759
760 match ty {
761 Type::ImplTrait(t) => {
762 let t_ident = ident!("T_{ident}");
763 node_fields.extend(quote! {
764 #cfg
765 #(#member_attrs)*
766 #ident: #t_ident,
767 });
768
769 let bounds = t.bounds;
770 impl_generics.extend(quote! {
771 #cfg
772 #t_ident: #bounds,
773 });
774
775 node_generics.extend(quote! {
776 #cfg
777 #t_ident,
778 });
779 }
780 t => {
781 node_fields.extend(quote! {
782 #cfg
783 #(#member_attrs)*
784 #ident: #t,
785 });
786 }
787 }
788
789 match kind {
790 ArgsNewNodeFieldKind::Var => {
791 auto_subs.extend(quote! {
792 #cfg
793 #crate_::widget::WIDGET.sub_var(&self.#ident);
794 });
795 }
796 ArgsNewNodeFieldKind::Event => {
797 auto_subs.extend(quote! {
798 #cfg
799 #crate_::widget::WIDGET.sub_event(&self.#ident);
800 });
801 }
802 ArgsNewNodeFieldKind::Custom => {}
803 }
804 }
805
806 let ident = args.ident;
807 let decl = quote! {
808 struct #ident<#impl_generics> {
809 #node_fields
810 }
811 };
812
813 ExpandedNewNode {
814 delegate,
815 ident,
816 decl,
817 impl_generics,
818 node_generics,
819 auto_subs,
820 }
821}
822
823struct ExpandedNewNode {
824 delegate: Ident,
825 ident: Ident,
826 decl: TokenStream,
827 impl_generics: TokenStream,
828 node_generics: TokenStream,
829 auto_subs: TokenStream,
830}