cranpose_foundation/
modifier_helpers.rs

1//! Helper macros to reduce boilerplate when implementing modifier nodes.
2//!
3//! These helpers follow the Jetpack Compose pattern where setting capability
4//! bits + implementing the specialized trait is enough for the node to participate
5//! in the corresponding pipeline stage.
6
7/// Implements the as_draw_node methods for a type that implements DrawModifierNode.
8///
9/// # Example
10///
11/// ```text
12/// impl ModifierNode for MyNode {
13///     impl_draw_node!();
14/// }
15/// ```
16#[macro_export]
17macro_rules! impl_draw_node {
18    () => {
19        fn as_draw_node(&self) -> Option<&dyn $crate::DrawModifierNode> {
20            Some(self)
21        }
22
23        fn as_draw_node_mut(&mut self) -> Option<&mut dyn $crate::DrawModifierNode> {
24            Some(self)
25        }
26    };
27}
28
29/// Implements the as_pointer_input_node methods for a type that implements PointerInputNode.
30///
31/// # Example
32///
33/// ```text
34/// impl ModifierNode for MyNode {
35///     impl_pointer_input_node!();
36/// }
37/// ```
38#[macro_export]
39macro_rules! impl_pointer_input_node {
40    () => {
41        fn as_pointer_input_node(&self) -> Option<&dyn $crate::PointerInputNode> {
42            Some(self)
43        }
44
45        fn as_pointer_input_node_mut(&mut self) -> Option<&mut dyn $crate::PointerInputNode> {
46            Some(self)
47        }
48    };
49}
50
51/// Implements the as_semantics_node methods for a type that implements SemanticsNode.
52///
53/// # Example
54///
55/// ```text
56/// impl ModifierNode for MyNode {
57///     impl_semantics_node!();
58/// }
59/// ```
60#[macro_export]
61macro_rules! impl_semantics_node {
62    () => {
63        fn as_semantics_node(&self) -> Option<&dyn $crate::SemanticsNode> {
64            Some(self)
65        }
66
67        fn as_semantics_node_mut(&mut self) -> Option<&mut dyn $crate::SemanticsNode> {
68            Some(self)
69        }
70    };
71}
72
73/// Implements the as_focus_node methods for a type that implements FocusNode.
74///
75/// # Example
76///
77/// ```text
78/// impl ModifierNode for MyNode {
79///     impl_focus_node!();
80/// }
81/// ```
82#[macro_export]
83macro_rules! impl_focus_node {
84    () => {
85        fn as_focus_node(&self) -> Option<&dyn $crate::FocusNode> {
86            Some(self)
87        }
88
89        fn as_focus_node_mut(&mut self) -> Option<&mut dyn $crate::FocusNode> {
90            Some(self)
91        }
92    };
93}
94
95/// Comprehensive macro that implements all capability-based methods for a modifier node.
96///
97/// This macro reduces boilerplate by automatically implementing the as_* methods
98/// for all specialized traits that the type implements. Use this as the primary
99/// way to declare which traits your node implements.
100///
101/// # Example
102///
103/// ```text
104/// impl ModifierNode for MyDrawNode {
105///     impl_modifier_node!(draw);
106/// }
107///
108/// impl ModifierNode for MyPointerNode {
109///     impl_modifier_node!(pointer_input);
110/// }
111///
112/// impl ModifierNode for MyComplexNode {
113///     impl_modifier_node!(draw, pointer_input, semantics);
114/// }
115/// ```
116#[macro_export]
117macro_rules! impl_modifier_node {
118    (draw) => {
119        $crate::impl_draw_node!();
120    };
121    (pointer_input) => {
122        $crate::impl_pointer_input_node!();
123    };
124    (semantics) => {
125        $crate::impl_semantics_node!();
126    };
127    (focus) => {
128        $crate::impl_focus_node!();
129    };
130    (draw, $($rest:tt)*) => {
131        $crate::impl_draw_node!();
132        $crate::impl_modifier_node!($($rest)*);
133    };
134    (pointer_input, $($rest:tt)*) => {
135        $crate::impl_pointer_input_node!();
136        $crate::impl_modifier_node!($($rest)*);
137    };
138    (semantics, $($rest:tt)*) => {
139        $crate::impl_semantics_node!();
140        $crate::impl_modifier_node!($($rest)*);
141    };
142    (focus, $($rest:tt)*) => {
143        $crate::impl_focus_node!();
144        $crate::impl_modifier_node!($($rest)*);
145    };
146}