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 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 future::ready(())
131 }
132 fn subscribe(&mut self, _signal: Sender<()>) {
133 }
135 fn get_context(&mut self) -> ContextMap {
136 Arc::default()
137 }
138 fn set_context(&mut self, _ctx: ContextMap) {
139 }
141}
142
143pub 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 ¤t_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(¤t_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(¤t_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}