zng_app_proc_macros/
ui_node.rs

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            // in case of major parsing error, like item not being an impl block. We give the args error
16            // but do not remove the function.
17            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 the impl block has a trait path.
31    if let Some((_, path, _)) = input.trait_ {
32        // if the trait name is UiNode
33        let seg = path.segments.last().unwrap();
34        if seg.ident == ui_node {
35            ui_node_path = Some(path);
36        }
37        // if the impl block is for a trait not named UiNode
38        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    // impl scope custom lints:
55    //
56    // we only have one lint, `zng::missing_delegate`.
57    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 we are in an UiNode impl
71            if ui_node_path.is_some() {
72                // assume the item is a method defined in the UiNode trait.
73                is_node = true;
74                node_item_names.insert(m.sig.ident.clone());
75            }
76            // if we are not in an UiNode impl but a method is annotated with `#[UiNode]`.
77            else if let Some(index) = m.attrs.iter().position(|a| a.path().get_ident() == Some(&ui_node)) {
78                // remove the marker attribute..
79                m.attrs.remove(index);
80                // ..and assume the item is a method defined in the UiNode trait.
81                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    // validate layout/measure pair
101    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    // collect default methods needed.
134    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!("measure"), // very common to avoid delegating
154            ident!("layout"),
155            ident!("render"),
156            ident!("render_update"),
157        ];
158
159        // validate that manually implemented UiNode methods call the expected method in the struct child or children.
160
161        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 we are not in a `UiNode` impl and no method was tagged `#[UiNode]`.
211    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    // we use the UiNode path provided by the user if possible
222    // to avoid an unused import warning.
223    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    // modify impl header for new_node and collect
228    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                    /// Init auto-generated event and var subscriptions.
271                    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    //let test = format!("{result}");
315    //if test.contains("FocusOnInit") {
316    //    println!("{test}");
317    //}
318
319    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
474/// Parsed macro arguments.
475enum Args {
476    /// No arguments. Impl is for a leaf in the Ui tree.
477    NoDelegate,
478    /// `child` or `delegate=expr`. Impl is for
479    /// an Ui that delegates each call to a single delegate.
480    Delegate { delegate: Expr },
481    /// `children` or `delegate_list=expr`. Impl
482    /// is for an Ui that delegates each call to multiple delegates.
483    DelegateList { delegate_list: Expr },
484    /// New node mode.
485    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
635/// Removes and returns the `zng::missing_delegate` level.
636fn 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}