Skip to main content

euv_core/vdom/node/
fn.rs

1use crate::*;
2
3/// Constructs a `VirtualNode::Dynamic` from a render closure with hook context management.
4///
5/// This function replaces the boilerplate that was previously generated inline
6/// by the `html!` macro for every `Dynamic`, `If`, `Match`, and `For` node.
7/// The macro now emits `euv_core::create_dynamic_node(render_fn)` instead of
8/// the full `HookContext` + `DynamicNode` + `render_fn` setup block.
9///
10/// # Arguments
11///
12/// - `FnMut() -> VirtualNode + 'static` - The render closure that produces
13///   a virtual node tree. Called on initial render and on every signal update.
14///
15/// # Returns
16///
17/// - `VirtualNode` - A `VirtualNode::Dynamic` wrapping the render closure
18///   with a fresh `HookContext`.
19pub fn create_dynamic_node<F>(mut render_fn: F) -> VirtualNode
20where
21    F: FnMut() -> VirtualNode + 'static,
22{
23    let hook_context: HookContext = create_hook_context();
24    let mut hook_context_for_closure: HookContext = hook_context;
25    let inner: Box<RenderFnInner> = Box::new(RenderFnInner {
26        render_fn: Box::new(move || {
27            hook_context_for_closure.reset_hook_index();
28            render_fn()
29        }),
30    });
31    let render_fn_addr: usize = Box::leak(inner) as *mut RenderFnInner as usize;
32    let dynamic_node: DynamicNode = DynamicNode {
33        render_fn: render_fn_addr as *mut RenderFnInner,
34        hook_context,
35    };
36    VirtualNode::Dynamic(dynamic_node)
37}
38
39/// Constructs a `VirtualNode::Dynamic` for match expressions where arm hook
40/// isolation is required. The render closure receives a `&mut HookContext`
41/// so it can call `set_arm_changed` before each arm body.
42///
43/// This function replaces the inline `HookContext` + `DynamicNode` setup that
44/// was previously generated for match nodes, where the hook context had to be
45/// accessible inside the render closure for arm switching.
46///
47/// # Arguments
48///
49/// - `FnMut(&mut HookContext) -> VirtualNode + 'static` - The render closure
50///   that receives a mutable reference to the hook context. The closure is
51///   responsible for calling `set_arm_changed` before each match arm.
52///
53/// # Returns
54///
55/// - `VirtualNode` - A `VirtualNode::Dynamic` wrapping the render closure
56///   with a fresh `HookContext`.
57pub fn create_dynamic_node_with_context<F>(mut render_fn: F) -> VirtualNode
58where
59    F: FnMut(&mut HookContext) -> VirtualNode + 'static,
60{
61    let hook_context: HookContext = create_hook_context();
62    let mut hook_context_for_closure: HookContext = hook_context;
63    let inner: Box<RenderFnInner> = Box::new(RenderFnInner {
64        render_fn: Box::new(move || {
65            hook_context_for_closure.reset_hook_index();
66            render_fn(&mut hook_context_for_closure)
67        }),
68    });
69    let render_fn_addr: usize = Box::leak(inner) as *mut RenderFnInner as usize;
70    let dynamic_node: DynamicNode = DynamicNode {
71        render_fn: render_fn_addr as *mut RenderFnInner,
72        hook_context,
73    };
74    VirtualNode::Dynamic(dynamic_node)
75}