Skip to main content

tui_lipan/layout/
tag.rs

1//! Tag system for element/node type matching during reconciliation.
2
3use crate::core::element::{Element, ElementKind};
4use crate::core::node::{Node, NodeKind};
5
6// ---------------------------------------------------------------------------
7// Helper macros that expand the categorised variant list into Tag code.
8// ---------------------------------------------------------------------------
9
10/// Generate the `Tag` enum, `tag_of_element()`, and `tag_of_node()`.
11macro_rules! impl_tags {
12    (
13        @direct [ $($v:ident,)* ]
14        @direct_gated [ $($gv:ident => $gf:literal,)* ]
15        @direct_no_hash [ $($dnh:ident,)* ]
16        @direct_no_hash_gated [ $($dnhg:ident => $dnhgf:literal,)* ]
17        @props_dims [ $($pd:ident,)* ]
18        @const_auto_hash [ $($cah:ident,)* ]
19        @const_auto_hash_gated [ $($cahg:ident => $cahgf:literal,)* ]
20        @const_flex [ $($cf:ident,)* ]
21        @const_flex_no_hash [ $($cfnh:ident,)* ]
22        @no_dims [ $($nd:ident,)* ]
23        @element_only_const_auto [ $($eo:ident,)* ]
24    ) => {
25        /// Tag for identifying element/node types during reconciliation.
26        #[allow(missing_docs)]
27        #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
28        pub enum Tag {
29            // All non-gated variants (every category)
30            $( $v, )*
31            $( $dnh, )*
32            $( $pd, )*
33            $( $cah, )*
34            $( $cf, )*
35            $( $cfnh, )*
36            $( $nd, )*
37            $( $eo, )*
38            // Gated variants
39            $( #[cfg(feature = $gf)] $gv, )*
40            $( #[cfg(feature = $dnhgf)] $dnhg, )*
41            $( #[cfg(feature = $cahgf)] $cahg, )*
42        }
43
44        pub(crate) fn tag_of_element(el: &Element) -> Tag {
45            match &el.kind {
46                $( ElementKind::$v(_) => Tag::$v, )*
47                $( ElementKind::$dnh(_) => Tag::$dnh, )*
48                $( ElementKind::$pd(_) => Tag::$pd, )*
49                $( ElementKind::$cah(_) => Tag::$cah, )*
50                $( ElementKind::$cf(_) => Tag::$cf, )*
51                $( ElementKind::$cfnh(_) => Tag::$cfnh, )*
52                $( ElementKind::$nd(_) => Tag::$nd, )*
53                $( ElementKind::$eo(_) => Tag::$eo, )*
54                $( #[cfg(feature = $gf)] ElementKind::$gv(_) => Tag::$gv, )*
55                $( #[cfg(feature = $dnhgf)] ElementKind::$dnhg(_) => Tag::$dnhg, )*
56                $( #[cfg(feature = $cahgf)] ElementKind::$cahg(_) => Tag::$cahg, )*
57            }
58        }
59
60        pub(crate) fn tag_of_node(node: &Node) -> Tag {
61            match &node.kind {
62                // All NodeKind variants (excludes @element_only_const_auto)
63                $( NodeKind::$v(_) => Tag::$v, )*
64                $( NodeKind::$dnh(_) => Tag::$dnh, )*
65                $( NodeKind::$pd(_) => Tag::$pd, )*
66                $( NodeKind::$cah(_) => Tag::$cah, )*
67                $( NodeKind::$cf(_) => Tag::$cf, )*
68                $( NodeKind::$cfnh(_) => Tag::$cfnh, )*
69                $( NodeKind::$nd(_) => Tag::$nd, )*
70                // Note: $eo (element_only) variants are NOT in NodeKind
71                $( #[cfg(feature = $gf)] NodeKind::$gv(_) => Tag::$gv, )*
72                $( #[cfg(feature = $dnhgf)] NodeKind::$dnhg(_) => Tag::$dnhg, )*
73                $( #[cfg(feature = $cahgf)] NodeKind::$cahg(_) => Tag::$cahg, )*
74            }
75        }
76    };
77}
78
79for_all_widget_variants!(impl_tags);
80
81pub(crate) fn unwrap_transparent_element(el: &Element) -> &Element {
82    match &el.kind {
83        ElementKind::ThemeProvider(tp) => unwrap_transparent_element(&tp.child),
84        ElementKind::ContextProvider(cp) => unwrap_transparent_element(&cp.child),
85        _ => el,
86    }
87}
88
89pub(crate) fn reuse_key_of_element(el: &Element) -> Option<crate::core::element::Key> {
90    unwrap_transparent_element(el).key.clone()
91}
92
93/// Check if a node can be reused for an element.
94pub(crate) fn can_reuse(node: &Node, el: &Element) -> bool {
95    let el = unwrap_transparent_element(el);
96    node.key == el.key && tag_of_node(node) == tag_of_element(el)
97}