bloom_core/
render_loop.rs

1use std::{any::Any, collections::HashMap, pin::Pin, sync::Arc};
2
3use async_channel::{bounded, unbounded, Receiver, Sender};
4use futures_util::{
5    future,
6    task::{Spawn, SpawnExt},
7    Future,
8};
9
10use crate::{
11    component::{AnyComponent, ComponentDiff},
12    context::ContextMap,
13    hook::Hook,
14    render_queue::{RenderContext, RenderQueue, RenderQueueItem},
15    state::StateUpdate,
16    suspense::{run_or_suspend, RunOrSuspendResult},
17    Element,
18};
19
20pub(crate) struct TreeComponent<N, E>
21where
22    N: From<String>,
23{
24    component: Arc<dyn AnyComponent<Node = N, Error = E> + Send + Sync>,
25    state: HashMap<u16, Arc<dyn Any + Send + Sync>>,
26    updates: Receiver<StateUpdate>,
27    updater: Sender<StateUpdate>,
28    render_result: Option<Pin<Box<dyn Future<Output = (Result<Element<N, E>, E>, Hook)> + Send>>>,
29    child: Option<Box<TreeNode<N, E>>>,
30    refs: HashMap<u16, Arc<dyn Any + Send + Sync + 'static>>,
31}
32
33impl<N, E> TreeComponent<N, E>
34where
35    N: From<String>,
36{
37    fn new(component: Arc<dyn AnyComponent<Node = N, Error = E> + Send + Sync>) -> Self {
38        let (update_sender, update_receiver) = unbounded::<StateUpdate>();
39        Self {
40            component,
41            state: HashMap::new(),
42            updates: update_receiver,
43            updater: update_sender,
44            child: None,
45            render_result: None,
46            refs: HashMap::new(),
47        }
48    }
49}
50
51pub(crate) enum TreeNode<N, E>
52where
53    N: From<String>,
54{
55    Component(TreeComponent<N, E>),
56    Node(Arc<N>, Vec<TreeNode<N, E>>),
57    Fragment(Vec<TreeNode<N, E>>),
58    Provider(Arc<dyn Any + Send + Sync>, Vec<TreeNode<N, E>>),
59}
60
61impl<N, E> TreeNode<N, E>
62where
63    N: From<String>,
64{
65    fn from(element: Element<N, E>) -> Self {
66        match element {
67            Element::Component(component) => TreeNode::Component(TreeComponent::new(component)),
68            Element::Node(node, children) => TreeNode::Node(
69                Arc::new(node),
70                children
71                    .into_iter()
72                    .map(|child| TreeNode::from(child))
73                    .collect(),
74            ),
75            Element::Fragment(children) => TreeNode::Fragment(
76                children
77                    .into_iter()
78                    .map(|child| TreeNode::from(child))
79                    .collect(),
80            ),
81            Element::Provider(value, children) => {
82                TreeNode::Provider(value, children.into_iter().map(TreeNode::from).collect())
83            }
84        }
85    }
86
87    fn get_first_node(&self) -> Option<Arc<N>> {
88        match self {
89            Self::Component(component) => component
90                .child
91                .as_ref()
92                .and_then(|child| child.get_first_node()),
93            Self::Node(node, _) => Some(Arc::clone(node)),
94            Self::Fragment(children) => {
95                for child in children {
96                    if let Some(node) = child.get_first_node() {
97                        return Some(node);
98                    }
99                }
100                return None;
101            }
102            Self::Provider(_, children) => {
103                for child in children {
104                    if let Some(node) = child.get_first_node() {
105                        return Some(node);
106                    }
107                }
108                return None;
109            }
110        }
111    }
112}
113
114pub trait ObjectModel {
115    type Node;
116    fn start(&mut self) -> impl Future<Output = ()> + Send {
117        // Do nothing by default
118        future::ready(())
119    }
120    fn create(
121        &mut self,
122        node: &Arc<Self::Node>,
123        parent: &Arc<Self::Node>,
124        sibling: &Option<Arc<Self::Node>>,
125    );
126    fn remove(&mut self, node: &Arc<Self::Node>, parent: &Arc<Self::Node>);
127    fn update(&mut self, node: &Arc<Self::Node>, next: &Arc<Self::Node>);
128    fn finalize(&mut self) -> impl Future<Output = ()> + Send {
129        // Do nothing by default
130        future::ready(())
131    }
132    fn subscribe(&mut self, _signal: Sender<()>) {
133        // do nothing by default
134    }
135    fn get_context(&mut self) -> ContextMap {
136        Arc::default()
137    }
138    fn set_context(&mut self, _ctx: ContextMap) {
139        // do nothing by default
140    }
141}
142
143/// render_loop can be used to implement interactive renderers on top of bloom-core.
144/// The primary renderer is the bloom-client library which implements client side rendering
145/// in the browser on top of bloom using webassembly.
146/// The root is the root node in the host environment which will contain the rendered UI.
147/// In web-environments the root might be a div within the body that is part of the server-sent html:
148/// ```html
149/// <html>
150///   <body>
151///     <div id="root"></div>
152///   </body>
153/// </html>
154/// ```
155///
156/// ```
157/// render_loop(get_element_by_id('root'), ...)
158/// ```
159///
160/// The element is the root of the component tree that represents the intended UI.
161/// This is usually a component:
162/// ```
163/// render_loop(root_node, rsx!(<MyComponent />), ...)
164/// ```
165///
166/// The spawner-argument is
167/// an object that implements the Spawn-trait so bloom can spawn async tasts on
168/// arbitrary task runners such as tokio or async-std.
169///
170///  The object model is the interface to the host environment.
171pub async fn render_loop<N, E, S, P>(
172    root: Arc<N>,
173    element: Element<N, E>,
174    spawner: S,
175    mut object_model: P,
176) -> Result<(), E>
177where
178    N: From<String> + Send + 'static,
179    E: Send + 'static,
180    S: Spawn,
181    P: ObjectModel<Node = N>,
182{
183    let mut tree_root = TreeNode::from(element);
184
185    let (signal_sender, signal_receiver) = bounded::<()>(1);
186
187    object_model.subscribe(signal_sender.clone());
188
189    signal_sender
190        .try_send(())
191        .expect("Failed to send message to trigger initial render");
192
193    while let Ok(_) = signal_receiver.recv().await {
194        println!("start render cycle");
195        object_model.start().await;
196        {
197            let mut render_queue = RenderQueue::new();
198            render_queue.reload(
199                &mut tree_root,
200                RenderContext::new(root.clone(), None, object_model.get_context()),
201            );
202
203            while let Some(item) = render_queue.next() {
204                println!("rendering item");
205                match item {
206                    RenderQueueItem::Create { current, ctx } => match unsafe { &mut *current } {
207                        TreeNode::Component(component) => render_component(
208                            component,
209                            &mut render_queue,
210                            &signal_sender,
211                            ctx,
212                            &spawner,
213                        )?,
214                        TreeNode::Node(node, children) => {
215                            object_model.create(node, &ctx.parent, &ctx.sibling);
216                            for child in children.iter_mut().rev() {
217                                render_queue.create(child, ctx.with_parent(node.clone()));
218                            }
219                        }
220                        TreeNode::Fragment(children) => {
221                            let mut sibling = ctx.sibling.clone();
222                            for child in children.iter_mut().rev() {
223                                render_queue.create(child, ctx.with_sibling(sibling));
224                                sibling = child.get_first_node();
225                            }
226                        }
227                        TreeNode::Provider(value, children) => {
228                            let mut sibling = ctx.sibling.clone();
229                            for child in children.iter_mut().rev() {
230                                render_queue.create(
231                                    child,
232                                    ctx.with_sibling_and_context(sibling, value.clone()),
233                                );
234                                sibling = child.get_first_node();
235                            }
236                        }
237                    },
238                    RenderQueueItem::Reload { current, ctx } => match unsafe { &mut *current } {
239                        TreeNode::Component(component) => {
240                            dbg!("reload component");
241                            if component.updates.is_empty() {
242                                if let Some(render_result) = component.render_result.take() {
243                                    match run_or_suspend(render_result) {
244                                        RunOrSuspendResult::Suspend(render_result) => {
245                                            component.render_result = Some(render_result);
246                                            if let Some(ref mut child) = component.child {
247                                                render_queue.reload(child.as_mut(), ctx);
248                                            }
249                                        }
250                                        RunOrSuspendResult::Done((result, hook)) => {
251                                            render_queue
252                                                .queue_effects(&component.component, hook.effects);
253                                            component.refs = hook.refs;
254                                            if let Some(ref mut child) = component.child {
255                                                render_queue.update(child.as_mut(), result?, ctx);
256                                            } else {
257                                                let mut child = Box::new(TreeNode::from(result?));
258                                                render_queue.create(child.as_mut(), ctx);
259                                                component.child = Some(child);
260                                            }
261                                        }
262                                    }
263                                } else if let Some(ref mut child) = component.child {
264                                    render_queue.reload(child.as_mut(), ctx);
265                                } else {
266                                    render_component(
267                                        component,
268                                        &mut render_queue,
269                                        &signal_sender,
270                                        ctx,
271                                        &spawner,
272                                    )?
273                                }
274                            } else {
275                                render_component(
276                                    component,
277                                    &mut render_queue,
278                                    &signal_sender,
279                                    ctx,
280                                    &spawner,
281                                )?
282                            }
283                        }
284                        TreeNode::Node(node, children) => {
285                            dbg!("reload node");
286                            let mut sibling = None;
287                            for child in children.iter_mut().rev() {
288                                render_queue.reload(
289                                    child,
290                                    ctx.with_parent_and_sibling(node.clone(), sibling),
291                                );
292                                sibling = child.get_first_node();
293                            }
294                        }
295                        TreeNode::Fragment(children) => {
296                            let mut sibling = ctx.sibling.clone();
297                            for child in children.iter_mut().rev() {
298                                render_queue.reload(child, ctx.with_sibling(sibling));
299                                sibling = child.get_first_node();
300                            }
301                        }
302                        TreeNode::Provider(value, children) => {
303                            let mut sibling = ctx.sibling.clone();
304                            for child in children.iter_mut().rev() {
305                                render_queue.reload(
306                                    child,
307                                    ctx.with_sibling_and_context(sibling, value.clone()),
308                                );
309                                sibling = child.get_first_node();
310                            }
311                        }
312                    },
313                    RenderQueueItem::Update { current, next, ctx } => {
314                        dbg!("update item");
315                        let current_node = unsafe { &mut *current };
316                        match (current_node, next) {
317                            (
318                                TreeNode::Component(ref mut current_component),
319                                Element::Component(next_component),
320                            ) => match next_component.compare(current_component.component.as_any())
321                            {
322                                ComponentDiff::Equal => {
323                                    render_queue.reload(unsafe { &mut *current }, ctx)
324                                }
325                                ComponentDiff::NewProps => {
326                                    render_queue.move_cleanups(
327                                        &current_component.component,
328                                        &next_component,
329                                    );
330                                    current_component.component = next_component;
331                                    render_component(
332                                        current_component,
333                                        &mut render_queue,
334                                        &signal_sender,
335                                        ctx,
336                                        &spawner,
337                                    )?;
338                                }
339                                ComponentDiff::NewType => {
340                                    render_queue.queue_cleanups(&current_component.component);
341                                    replace_node(
342                                        unsafe { &mut *current },
343                                        Element::Component(next_component),
344                                        &mut render_queue,
345                                        ctx,
346                                    );
347                                }
348                            },
349                            (
350                                TreeNode::Node(current, current_children),
351                                Element::Node(next, next_children),
352                            ) => {
353                                let next = Arc::new(next);
354                                object_model.update(current, &next);
355                                *current = next.clone();
356                                update_children(
357                                    current_children,
358                                    next_children,
359                                    &mut render_queue,
360                                    ctx.with_parent(next),
361                                );
362                            }
363                            (
364                                TreeNode::Fragment(current_children),
365                                Element::Fragment(next_children),
366                            ) => update_children(
367                                current_children,
368                                next_children,
369                                &mut render_queue,
370                                ctx,
371                            ),
372                            (
373                                TreeNode::Provider(_, current_children),
374                                Element::Provider(next_value, next_children),
375                            ) => update_children(
376                                current_children,
377                                next_children,
378                                &mut render_queue,
379                                ctx.with_context(next_value),
380                            ),
381                            (current_node, next) => {
382                                if let TreeNode::Component(current_component) = current_node {
383                                    render_queue.queue_cleanups(&current_component.component);
384                                }
385                                replace_node(current_node, next, &mut render_queue, ctx)
386                            }
387                        }
388                    }
389                    RenderQueueItem::Remove { current, parent } => match current {
390                        TreeNode::Component(component) => {
391                            render_queue.queue_cleanups(&component.component);
392                            if let Some(child) = component.child {
393                                render_queue.remove(*child, parent);
394                            }
395                        }
396                        TreeNode::Node(node, children) => {
397                            object_model.remove(&node, &parent);
398                            for child in children {
399                                render_queue.remove(child, Arc::clone(&node));
400                            }
401                        }
402                        TreeNode::Fragment(children) => {
403                            for child in children {
404                                render_queue.remove(child, Arc::clone(&parent));
405                            }
406                        }
407                        TreeNode::Provider(_, children) => {
408                            for child in children {
409                                render_queue.remove(child, Arc::clone(&parent));
410                            }
411                        }
412                    },
413                }
414            }
415
416            render_queue.run_effects();
417        }
418        object_model.finalize().await;
419    }
420
421    Ok(())
422}
423
424fn update_children<N, E>(
425    tree_nodes: &mut Vec<TreeNode<N, E>>,
426    mut elements: Vec<Element<N, E>>,
427    render_queue: &mut RenderQueue<N, E, TreeNode<N, E>>,
428    ctx: RenderContext<N>,
429) where
430    N: From<String>,
431{
432    let old_len = tree_nodes.len();
433
434    for tree_node in tree_nodes.drain(elements.len()..).rev() {
435        render_queue.remove(tree_node, ctx.parent.clone());
436    }
437
438    tree_nodes.shrink_to_fit();
439
440    for element in elements.drain(tree_nodes.len()..) {
441        tree_nodes.push(TreeNode::from(element));
442    }
443
444    for tree_node in tree_nodes.iter_mut().skip(old_len).rev() {
445        render_queue.create(tree_node, ctx.clone());
446    }
447
448    let mut sibling = ctx.sibling.clone();
449    for (tree_node, element) in tree_nodes.iter_mut().zip(elements.into_iter()).rev() {
450        let next_sibling = tree_node.get_first_node();
451        render_queue.update(tree_node, element, ctx.with_sibling(sibling));
452        sibling = next_sibling;
453    }
454}
455
456fn render_component<N, E, S>(
457    tree_component: &mut TreeComponent<N, E>,
458    render_queue: &mut RenderQueue<N, E, TreeNode<N, E>>,
459    signal_sender: &Sender<()>,
460    ctx: RenderContext<N>,
461    spawner: &S,
462) -> Result<(), E>
463where
464    N: From<String> + Send + 'static,
465    E: Send + 'static,
466    S: Spawn,
467{
468    dbg!("render component");
469    while let Ok(state_update) = tree_component.updates.try_recv() {
470        state_update.apply(&mut tree_component.state);
471    }
472
473    let component = Arc::clone(&tree_component.component);
474    let hook = Hook::new(
475        signal_sender.clone(),
476        tree_component.updater.clone(),
477        tree_component.state.clone(),
478        tree_component.refs.clone(),
479        ctx.context.clone(),
480    );
481    let result = run_or_suspend(Box::pin(async_context::provide_async_context(
482        hook,
483        component.render(),
484    )));
485
486    Ok(match result {
487        RunOrSuspendResult::Done((element, hook)) => {
488            tree_component.render_result = None;
489            match tree_component.child {
490                Some(ref mut node) => render_queue.update(node.as_mut(), element?, ctx.clone()),
491                None => {
492                    let tree_node = TreeNode::from(element?);
493                    let mut child = Box::new(tree_node);
494                    render_queue.create(child.as_mut(), ctx.clone());
495                    tree_component.child = Some(child);
496                }
497            }
498            render_queue.queue_effects(&tree_component.component, hook.effects);
499            tree_component.refs = hook.refs;
500        }
501        RunOrSuspendResult::Suspend(render_future) => {
502            let signal_sender = signal_sender.clone();
503            tree_component.render_result = Some(Box::pin(
504                spawner
505                    .spawn_with_handle(async move {
506                        let result = render_future.await;
507                        let _ = signal_sender.try_send(());
508                        result
509                    })
510                    .expect("Failed to spawn async task"),
511            ));
512        }
513    })
514}
515
516fn replace_node<N, E>(
517    node: &mut TreeNode<N, E>,
518    element: Element<N, E>,
519    render_queue: &mut RenderQueue<N, E, TreeNode<N, E>>,
520    ctx: RenderContext<N>,
521) where
522    N: From<String>,
523{
524    let mut old_node = TreeNode::from(element);
525    std::mem::swap(node, &mut old_node);
526    render_queue.remove(old_node, ctx.parent.clone());
527    render_queue.create(node, ctx);
528}
529
530#[cfg(test)]
531mod tests {
532    use std::{
533        collections::VecDeque,
534        hash::Hash,
535        sync::{Arc, Mutex},
536    };
537
538    use async_channel::{Receiver, RecvError, Sender};
539    use async_trait::async_trait;
540    use futures_util::{task::Spawn, Future, FutureExt};
541
542    use crate::{use_effect, use_state, Component, Element, ObjectModel};
543
544    struct InnerMockObjectModel {
545        created: VecDeque<Arc<MockNode>>,
546        updated: VecDeque<Arc<MockNode>>,
547        removed: VecDeque<Arc<MockNode>>,
548        start_signal: (Sender<()>, Receiver<()>),
549        finalize_signal: (Sender<()>, Receiver<()>),
550    }
551
552    impl InnerMockObjectModel {
553        fn new() -> Arc<Mutex<Self>> {
554            Arc::new(Mutex::new(Self {
555                created: VecDeque::new(),
556                updated: VecDeque::new(),
557                removed: VecDeque::new(),
558                start_signal: async_channel::bounded(1),
559                finalize_signal: async_channel::bounded(2),
560            }))
561        }
562
563        fn assert_created(&mut self, expected: MockNode) {
564            assert_eq!(
565                &self.created.pop_front(),
566                &Some(Arc::new(expected)),
567                "Node not created"
568            );
569        }
570
571        fn assert_updated(&mut self, expected: MockNode) {
572            assert_eq!(
573                &self.updated.pop_front(),
574                &Some(Arc::new(expected)),
575                "Node not updated"
576            );
577        }
578
579        #[allow(dead_code)]
580        fn assert_removed(&mut self, expected: MockNode) {
581            assert_eq!(
582                &self.removed.pop_front(),
583                &Some(Arc::new(expected)),
584                "Node not removed"
585            );
586        }
587
588        fn assert_noop(&self) {
589            assert!(self.created.is_empty());
590            assert!(self.updated.is_empty());
591            assert!(self.removed.is_empty());
592        }
593
594        fn render_cycle(&self) -> impl Future<Output = ()> {
595            let start_signal = self.start_signal.1.clone();
596            let finalize_signal = self.finalize_signal.1.clone();
597            async move {
598                start_signal.recv().await.unwrap();
599                finalize_signal.recv().await.unwrap();
600            }
601        }
602    }
603
604    struct MockObjectModel(Arc<Mutex<InnerMockObjectModel>>);
605
606    #[derive(Debug, PartialEq)]
607    struct MockNode(i32);
608
609    impl From<String> for MockNode {
610        fn from(_value: String) -> Self {
611            MockNode(0)
612        }
613    }
614
615    impl ObjectModel for MockObjectModel {
616        type Node = MockNode;
617        fn create(
618            &mut self,
619            node: &std::sync::Arc<Self::Node>,
620            _parent: &std::sync::Arc<Self::Node>,
621            _sibling: &Option<std::sync::Arc<Self::Node>>,
622        ) {
623            println!("create {:?}", node);
624            self.0.lock().unwrap().created.push_back(node.clone());
625        }
626
627        fn update(
628            &mut self,
629            _node: &std::sync::Arc<Self::Node>,
630            next: &std::sync::Arc<Self::Node>,
631        ) {
632            self.0.lock().unwrap().updated.push_back(next.clone());
633        }
634
635        fn remove(
636            &mut self,
637            node: &std::sync::Arc<Self::Node>,
638            _parent: &std::sync::Arc<Self::Node>,
639        ) {
640            self.0.lock().unwrap().removed.push_back(node.clone());
641        }
642
643        async fn start(&mut self) {
644            let signal = self.0.lock().unwrap().start_signal.0.clone();
645            signal.send(()).await.unwrap();
646        }
647
648        async fn finalize(&mut self) {
649            let signal = self.0.lock().unwrap().finalize_signal.0.clone();
650            signal.send(()).await.unwrap();
651        }
652    }
653
654    struct TokioSpawner;
655
656    impl Spawn for TokioSpawner {
657        fn spawn_obj(
658            &self,
659            future: futures_util::task::FutureObj<'static, ()>,
660        ) -> Result<(), futures_util::task::SpawnError> {
661            tokio::spawn(future.map(|_| ()));
662            Ok(())
663        }
664    }
665
666    #[tokio::test]
667    async fn render_basic_component() {
668        #[derive(PartialEq)]
669        struct MockComponent;
670
671        #[async_trait]
672        impl Component for MockComponent {
673            type Error = ();
674            type Node = MockNode;
675            async fn render(
676                self: Arc<Self>,
677            ) -> Result<Element<Self::Node, Self::Error>, Self::Error> {
678                Ok(Element::Node(MockNode(0), Vec::new()))
679            }
680        }
681
682        let inner_object_model = InnerMockObjectModel::new();
683        let object_model = MockObjectModel(inner_object_model.clone());
684        let handle = tokio::spawn(async move {
685            let root = Arc::new(MockNode(0));
686            let element = Element::Component(Arc::new(MockComponent));
687            super::render_loop(root, element, TokioSpawner, object_model)
688                .await
689                .unwrap();
690        });
691
692        let render_cycle = inner_object_model.lock().unwrap().render_cycle();
693        render_cycle.await;
694        inner_object_model
695            .lock()
696            .unwrap()
697            .assert_created(MockNode(0));
698
699        handle.abort();
700    }
701
702    #[tokio::test]
703    async fn with_callback() {
704        #[derive(PartialEq)]
705        struct AutoCounter;
706
707        #[async_trait]
708        impl Component for AutoCounter {
709            type Error = ();
710            type Node = MockNode;
711            async fn render(
712                self: Arc<Self>,
713            ) -> Result<Element<Self::Node, Self::Error>, Self::Error> {
714                let counter = use_state(|| 0i32);
715                if *counter == 0 {
716                    counter.update(|count| *count + 1);
717                }
718                Ok(Element::Node(MockNode(*counter), Vec::new()))
719            }
720        }
721
722        let inner_object_model = InnerMockObjectModel::new();
723        let object_model = MockObjectModel(inner_object_model.clone());
724        let handle = tokio::spawn(async move {
725            let root = Arc::new(MockNode(0));
726            let element = Element::Component(Arc::new(AutoCounter));
727            super::render_loop(root, element, TokioSpawner, object_model)
728                .await
729                .unwrap();
730        });
731
732        let render_cycle = inner_object_model.lock().unwrap().render_cycle();
733        render_cycle.await;
734        inner_object_model
735            .lock()
736            .unwrap()
737            .assert_created(MockNode(0));
738
739        let render_cycle = inner_object_model.lock().unwrap().render_cycle();
740        render_cycle.await;
741        inner_object_model
742            .lock()
743            .unwrap()
744            .assert_updated(MockNode(1));
745
746        handle.abort();
747    }
748
749    #[tokio::test]
750    async fn update_order() {
751        #[derive(PartialEq)]
752        struct MultiContent;
753
754        #[async_trait]
755        impl Component for MultiContent {
756            type Error = ();
757            type Node = MockNode;
758            async fn render(
759                self: Arc<Self>,
760            ) -> Result<Element<Self::Node, Self::Error>, Self::Error> {
761                let counter = use_state(|| 0i32);
762
763                if *counter == 0 {
764                    let counter = counter.clone();
765                    tokio::spawn(async move { counter.update(|count| *count + 1) });
766                }
767
768                Ok(Element::Node(
769                    MockNode(*counter),
770                    vec![
771                        Element::Node(MockNode(3), Vec::new()),
772                        Element::Node(MockNode(4), Vec::new()),
773                        Element::Node(MockNode(5), Vec::new()),
774                    ],
775                ))
776            }
777        }
778        let inner_object_model = InnerMockObjectModel::new();
779        let object_model = MockObjectModel(inner_object_model.clone());
780        let handle = tokio::spawn(async move {
781            let root = Arc::new(MockNode(0));
782            let element = Element::Component(Arc::new(MultiContent));
783            super::render_loop(root, element, TokioSpawner, object_model)
784                .await
785                .unwrap();
786        });
787
788        let render_cycle = inner_object_model.lock().unwrap().render_cycle();
789        render_cycle.await;
790        println!("start first checks");
791        {
792            let mut lock = inner_object_model.lock().unwrap();
793            lock.assert_created(MockNode(0));
794            lock.assert_created(MockNode(3));
795            lock.assert_created(MockNode(4));
796            lock.assert_created(MockNode(5));
797        }
798        println!("first cycle done");
799        let render_cycle = inner_object_model.lock().unwrap().render_cycle();
800        render_cycle.await;
801        {
802            let mut lock = inner_object_model.lock().unwrap();
803            lock.assert_updated(MockNode(1));
804            lock.assert_updated(MockNode(3));
805            lock.assert_updated(MockNode(4));
806            lock.assert_updated(MockNode(5));
807        }
808
809        handle.abort();
810    }
811
812    #[tokio::test]
813    async fn async_component() {
814        let (sender, receiver) = async_channel::bounded::<()>(1);
815
816        struct AsyncComponent(Receiver<()>);
817
818        impl PartialEq for AsyncComponent {
819            fn eq(&self, _: &Self) -> bool {
820                true
821            }
822        }
823
824        #[async_trait]
825        impl Component for AsyncComponent {
826            type Error = RecvError;
827            type Node = MockNode;
828
829            async fn render(
830                self: Arc<Self>,
831            ) -> Result<Element<Self::Node, Self::Error>, Self::Error> {
832                self.0.recv().await?;
833                Ok(Element::Node(MockNode(0), Vec::new()))
834            }
835        }
836
837        let inner_object_model = InnerMockObjectModel::new();
838        let object_model = MockObjectModel(inner_object_model.clone());
839        let handle = tokio::spawn(async move {
840            let root = Arc::new(MockNode(0));
841            let element = Element::Component(Arc::new(AsyncComponent(receiver)));
842            super::render_loop(root, element, TokioSpawner, object_model)
843                .await
844                .unwrap();
845        });
846
847        let render_cycle = inner_object_model.lock().unwrap().render_cycle();
848        render_cycle.await;
849        inner_object_model.lock().unwrap().assert_noop();
850
851        sender.send(()).await.unwrap();
852        let render_cycle = inner_object_model.lock().unwrap().render_cycle();
853        render_cycle.await;
854
855        inner_object_model
856            .lock()
857            .unwrap()
858            .assert_created(MockNode(0));
859
860        handle.abort();
861    }
862
863    #[tokio::test]
864    async fn with_effect() {
865        let (sender, receiver) = async_channel::bounded::<()>(1);
866
867        #[derive(Clone)]
868        struct MySender(Sender<()>);
869
870        impl Hash for MySender {
871            fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
872                std::ptr::hash(&self.0 as *const Sender<()>, state);
873            }
874        }
875
876        impl PartialEq for MySender {
877            fn eq(&self, other: &Self) -> bool {
878                &self.0 as *const Sender<()> == &other.0 as *const Sender<()>
879            }
880        }
881
882        #[derive(PartialEq)]
883        struct EffectComponent(MySender);
884
885        #[async_trait]
886        impl Component for EffectComponent {
887            type Error = ();
888            type Node = MockNode;
889
890            async fn render(
891                self: Arc<Self>,
892            ) -> Result<Element<Self::Node, Self::Error>, Self::Error> {
893                use_effect(self.0.clone(), |sender| {
894                    sender.0.try_send(()).unwrap();
895                });
896                Ok(Element::Node(MockNode(0), Vec::new()))
897            }
898        }
899
900        let inner_object_model = InnerMockObjectModel::new();
901        let object_model = MockObjectModel(inner_object_model.clone());
902        let handle = tokio::spawn(async move {
903            let root = Arc::new(MockNode(0));
904            let element = Element::Component(Arc::new(EffectComponent(MySender(sender))));
905            super::render_loop(root, element, TokioSpawner, object_model)
906                .await
907                .unwrap();
908        });
909
910        let render_cycle = inner_object_model.lock().unwrap().render_cycle();
911        render_cycle.await;
912
913        assert_eq!(Ok(()), receiver.recv().await);
914
915        handle.abort();
916    }
917}