make all core tests compile

This commit is contained in:
Evan Almloff committed 2024-01-11 15:18:11 -06:00
1 parent a9d09d858b
commit fd0a53ab63
21 files changed
+123 -148

No files matched your search

+1 -1
View File
@@ -76,7 +76,7 @@ impl<const A: bool> FragmentBuilder<A> {
/// children: Element /// children: Element
/// } /// }
/// ///
/// fn CustomCard(cx: Scope<CardProps>) -> Element { /// fn CustomCard(cx: CardProps) -> Element {
/// cx.render(rsx!{ /// cx.render(rsx!{
/// div { /// div {
/// h1 {"Title card"} /// h1 {"Title card"}
+2 -2
View File
@@ -50,7 +50,7 @@ pub(crate) mod innerlude {
/// ## Rust-Style /// ## Rust-Style
/// ///
/// ```rust, ignore /// ```rust, ignore
/// fn example(cx: Scope<Props>) -> Element { /// fn example(cx: Props) -> Element {
/// // ... /// // ...
/// } /// }
/// ///
@@ -60,7 +60,7 @@ pub(crate) mod innerlude {
/// ``` /// ```
/// ## React-Style /// ## React-Style
/// ```rust, ignore /// ```rust, ignore
/// fn Example(cx: Scope<Props>) -> Element { /// fn Example(cx: Props) -> Element {
/// // ... /// // ...
/// } /// }
/// ///
+2 -2
View File
@@ -461,7 +461,7 @@ impl VComponent {
/// async fn(Scope<'_>) -> Element; /// async fn(Scope<'_>) -> Element;
/// ///
/// // With explicit props /// // With explicit props
/// fn(Scope<Props>) -> Element; /// fn(Props) -> Element;
/// async fn(Scope<Props<'_>>) -> Element; /// async fn(Scope<Props<'_>>) -> Element;
/// ``` /// ```
pub fn new<F: HasProps<P> + 'static, P: 'static>( pub fn new<F: HasProps<P> + 'static, P: 'static>(
@@ -649,7 +649,7 @@ impl AttributeValue {
} }
/// Create a new [`AttributeValue`] with a value that implements [`AnyValue`] /// Create a new [`AttributeValue`] with a value that implements [`AnyValue`]
pub fn any_value<T: AnyValue>(&self, value: T) -> AttributeValue { pub fn any_value<T: AnyValue>(value: T) -> AttributeValue {
AttributeValue::Any(Box::new(value)) AttributeValue::Any(Box::new(value))
} }
} }
+1 -1
View File
@@ -131,7 +131,7 @@ impl Runtime {
/// } /// }
/// } /// }
/// ///
/// fn Component(cx: Scope<ComponentProps>) -> Element { /// fn Component(cx: ComponentProps) -> Element {
/// cx.use_hook(|| RuntimeGuard::new(cx.runtime.clone())); /// cx.use_hook(|| RuntimeGuard::new(cx.runtime.clone()));
/// ///
/// render! { div {} } /// render! { div {} }
+5
View File
@@ -383,4 +383,9 @@ impl ScopeId {
pub fn schedule_update(&self) -> Arc<dyn Fn() + Send + Sync + 'static> { pub fn schedule_update(&self) -> Arc<dyn Fn() + Send + Sync + 'static> {
with_scope(*self, |cx| cx.schedule_update()).expect("to be in a dioxus runtime") with_scope(*self, |cx| cx.schedule_update()).expect("to be in a dioxus runtime")
} }
/// Get the height of the current scope
pub fn height(self) -> u32 {
with_scope(self, |cx| cx.height()).expect("to be in a dioxus runtime")
}
} }
+3 -3
View File
@@ -34,7 +34,7 @@ use std::{any::Any, cell::Cell, collections::BTreeSet, future::Future, rc::Rc};
/// title: String /// title: String
/// } /// }
/// ///
/// fn App(cx: Scope<AppProps>) -> Element { /// fn App(cx: AppProps) -> Element {
/// cx.render(rsx!( /// cx.render(rsx!(
/// div {"hello, {cx.title}"} /// div {"hello, {cx.title}"}
/// )) /// ))
@@ -55,7 +55,7 @@ use std::{any::Any, cell::Cell, collections::BTreeSet, future::Future, rc::Rc};
/// static ROUTES: &str = ""; /// static ROUTES: &str = "";
/// ///
/// #[component] /// #[component]
/// fn App(cx: Scope<AppProps>) -> Element { /// fn App(cx: AppProps) -> Element {
/// cx.render(rsx!( /// cx.render(rsx!(
/// NavBar { routes: ROUTES } /// NavBar { routes: ROUTES }
/// Title { "{cx.title}" } /// Title { "{cx.title}" }
@@ -247,7 +247,7 @@ impl VirtualDom {
/// name: &'static str /// name: &'static str
/// } /// }
/// ///
/// fn Example(cx: Scope<SomeProps>) -> Element { /// fn Example(cx: SomeProps) -> Element {
/// cx.render(rsx!{ div{ "hello {cx.name}" } }) /// cx.render(rsx!{ div{ "hello {cx.name}" } })
/// } /// }
/// ///
+2 -6
View File
@@ -2,10 +2,8 @@
//! //!
//! This tests to ensure we clean it up //! This tests to ensure we clean it up
use bumpalo::Bump;
use dioxus::core::{ElementId, Mutation::*}; use dioxus::core::{ElementId, Mutation::*};
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus_core::BorrowedAttributeValue;
#[test] #[test]
fn attrs_cycle() { fn attrs_cycle() {
@@ -20,8 +18,6 @@ fn attrs_cycle() {
} }
}); });
let bump = Bump::new();
assert_eq!( assert_eq!(
dom.rebuild_to_vec().santize().edits, dom.rebuild_to_vec().santize().edits,
[ [
@@ -59,13 +55,13 @@ fn attrs_cycle() {
AssignId { path: &[0], id: ElementId(3) }, AssignId { path: &[0], id: ElementId(3) },
SetAttribute { SetAttribute {
name: "class", name: "class",
value: BorrowedAttributeValue::Text("3"), value: dioxus_core::AttributeValue::Text("3".to_string()),
id: ElementId(3), id: ElementId(3),
ns: None ns: None
}, },
SetAttribute { SetAttribute {
name: "id", name: "id",
value: BorrowedAttributeValue::Text("3"), value: dioxus_core::AttributeValue::Text("3".to_string()),
id: ElementId(3), id: ElementId(3),
ns: None ns: None
}, },
+1 -3
View File
@@ -1,11 +1,9 @@
use bumpalo::Bump;
use dioxus::core::{ElementId, Mutation::*}; use dioxus::core::{ElementId, Mutation::*};
use dioxus::prelude::*; use dioxus::prelude::*;
#[test] #[test]
fn bool_test() { fn bool_test() {
let mut app = VirtualDom::new(|cx| render!(div { hidden: false }))); let mut app = VirtualDom::new(|| render!(div { hidden: false }));
let bump = Bump::new();
assert_eq!( assert_eq!(
app.rebuild_to_vec().santize().edits, app.rebuild_to_vec().santize().edits,
+2 -2
View File
@@ -4,7 +4,7 @@ use dioxus::prelude::*;
#[test] #[test]
fn state_shares() { fn state_shares() {
fn app() -> Element { fn app() -> Element {
cx.provide_context(generation() as i32); provide_context(generation() as i32);
render!(child_1 {}) render!(child_1 {})
} }
@@ -14,7 +14,7 @@ fn state_shares() {
} }
fn child_2() -> Element { fn child_2() -> Element {
let value = cx.consume_context::<i32>().unwrap(); let value = consume_context::<i32>().unwrap();
render!("Value is {value}") render!("Value is {value}")
} }
+4 -4
View File
@@ -75,7 +75,7 @@ fn create() {
#[test] #[test]
fn create_list() { fn create_list() {
let mut dom = VirtualDom::new(|cx| render! {(0..3).map(|f| render!( div { "hello" } ))})); let mut dom = VirtualDom::new(|| render! {(0..3).map(|f| render!( div { "hello" } ))});
let _edits = dom.rebuild_to_vec().santize(); let _edits = dom.rebuild_to_vec().santize();
@@ -129,12 +129,12 @@ fn create_components() {
} }
}); });
#[derive(Props)] #[derive(Props, Clone, PartialEq)]
struct ChildProps<'a> { struct ChildProps {
children: Element, children: Element,
} }
fn Child<'a>(cx: ChildProps) -> Element { fn Child(cx: ChildProps) -> Element {
render! { render! {
h1 {} h1 {}
div { &cx.children } div { &cx.children }
+1 -1
View File
@@ -16,7 +16,7 @@ fn nested_passthru_creates() {
} }
#[component] #[component]
fn PassThru<'a>(children: Element) -> Element { fn PassThru(children: Element) -> Element {
render!(children) render!(children)
} }
+1 -1
View File
@@ -4,7 +4,7 @@ use dioxus::prelude::*;
/// As we clean up old templates, the ID for the node should cycle /// As we clean up old templates, the ID for the node should cycle
#[test] #[test]
fn cycling_elements() { fn cycling_elements() {
let mut dom = VirtualDom::new(|cx| match generation() % 2 { let mut dom = VirtualDom::new(|| match generation() % 2 {
0 => render! { div { "wasd" } }, 0 => render! { div { "wasd" } },
1 => render! { div { "abcd" } }, 1 => render! { div { "abcd" } },
_ => unreachable!(), _ => unreachable!(),
+3 -3
View File
@@ -8,11 +8,11 @@ use dioxus::prelude::*;
#[test] #[test]
fn component_swap() { fn component_swap() {
fn app() -> Element { fn app() -> Element {
let render_phase = cx.use_hook(|| 0); let mut render_phase = use_signal(|| 0);
*render_phase += 1; render_phase += 1;
match *render_phase { match *render_phase() {
0 => render! { 0 => render! {
nav_bar {} nav_bar {}
dash_board {} dash_board {}
+1 -1
View File
@@ -19,7 +19,7 @@ fn app() -> Element {
} }
} }
fn NoneChild(_) -> Element { fn NoneChild() -> Element {
None None
} }
+47 -76
View File
@@ -1,8 +1,8 @@
#![cfg(not(miri))] #![cfg(not(miri))]
use dioxus::prelude::Props; use dioxus::prelude::*;
use dioxus_core::*; use dioxus_core::{prelude::EventHandler, AttributeValue, DynamicNode, VComponent, *};
use std::{cfg, collections::HashSet}; use std::{cfg, collections::HashSet, default::Default};
fn random_ns() -> Option<&'static str> { fn random_ns() -> Option<&'static str> {
let namespace = rand::random::<u8>() % 2; let namespace = rand::random::<u8>() % 2;
@@ -38,7 +38,7 @@ fn create_random_template_node(
template_idx: &mut usize, template_idx: &mut usize,
attr_idx: &mut usize, attr_idx: &mut usize,
depth: usize, depth: usize,
) -> TemplateNode<'static> { ) -> TemplateNode {
match rand::random::<u8>() % 4 { match rand::random::<u8>() % 4 {
0 => { 0 => {
let attrs = { let attrs = {
@@ -94,7 +94,7 @@ fn create_random_template_node(
} }
fn generate_paths( fn generate_paths(
node: &TemplateNode<'static>, node: &TemplateNode,
current_path: &[u8], current_path: &[u8],
node_paths: &mut Vec<Vec<u8>>, node_paths: &mut Vec<Vec<u8>>,
attr_paths: &mut Vec<Vec<u8>>, attr_paths: &mut Vec<Vec<u8>>,
@@ -166,58 +166,48 @@ fn create_random_template(name: &'static str) -> (Template, Vec<DynamicNodeType>
) )
} }
fn create_random_dynamic_node(cx: &ScopeState, depth: usize) -> DynamicNode { fn create_random_dynamic_node(depth: usize) -> DynamicNode {
let range = if depth > 5 { 1 } else { 4 }; let range = if depth > 5 { 1 } else { 3 };
match rand::random::<u8>() % range { match rand::random::<u8>() % range {
0 => DynamicNode::Placeholder(Default::default()), 0 => DynamicNode::Placeholder(Default::default()),
1 => cx.make_node((0..(rand::random::<u8>() % 5)).map(|_| { 1 => (0..(rand::random::<u8>() % 5))
VNode::new( .map(|_| {
None, VNode::new(
Template { None,
name: concat!(file!(), ":", line!(), ":", column!(), ":0"), Template {
roots: &[TemplateNode::Dynamic { id: 0 }], name: concat!(file!(), ":", line!(), ":", column!(), ":0"),
node_paths: &[&[0]], roots: &[TemplateNode::Dynamic { id: 0 }],
attr_paths: &[], node_paths: &[&[0]],
}, attr_paths: &[],
bumpalo::collections::Vec::new_in(cx.bump()), },
cx.bump().alloc([cx.component( Box::new([DynamicNode::Component(VComponent::new(
create_random_element, create_random_element,
DepthProps { depth, root: false }, DepthProps { depth, root: false },
"create_random_element", "create_random_element",
)]), ))]),
&[], Box::new([]),
) )
})), })
2 => cx.component( .into_dyn_node(),
2 => DynamicNode::Component(VComponent::new(
create_random_element, create_random_element,
DepthProps { depth, root: false }, DepthProps { depth, root: false },
"create_random_element", "create_random_element",
), )),
3 => {
let data = String::from("borrowed data");
let bumpped = cx.bump().alloc(data);
cx.component(
create_random_element_borrowed,
BorrowedDepthProps { borrow: &*bumpped, inner: DepthProps { depth, root: false } },
"create_random_element_borrowed",
)
}
_ => unreachable!(), _ => unreachable!(),
} }
} }
fn create_random_dynamic_attr(cx: &ScopeState) -> Attribute { fn create_random_dynamic_attr() -> Attribute {
let value = match rand::random::<u8>() % 7 { let value = match rand::random::<u8>() % 7 {
0 => AttributeValue::Text(Box::leak( 0 => AttributeValue::Text(format!("{}", rand::random::<usize>())),
format!("{}", rand::random::<usize>()).into_boxed_str(),
)),
1 => AttributeValue::Float(rand::random()), 1 => AttributeValue::Float(rand::random()),
2 => AttributeValue::Int(rand::random()), 2 => AttributeValue::Int(rand::random()),
3 => AttributeValue::Bool(rand::random()), 3 => AttributeValue::Bool(rand::random()),
4 => cx.any_value(rand::random::<usize>()), 4 => AttributeValue::any_value(rand::random::<usize>()),
5 => AttributeValue::None, 5 => AttributeValue::None,
6 => { 6 => {
let value = cx.listener(|e: Event<String>| println!("{:?}", e)); let value = AttributeValue::listener(|e: Event<String>| println!("{:?}", e));
return Attribute::new("ondata", value, None, false); return Attribute::new("ondata", value, None, false);
} }
_ => unreachable!(), _ => unreachable!(),
@@ -232,28 +222,15 @@ fn create_random_dynamic_attr(cx: &ScopeState) -> Attribute {
static mut TEMPLATE_COUNT: usize = 0; static mut TEMPLATE_COUNT: usize = 0;
#[derive(Props)] #[derive(PartialEq, Props, Clone)]
struct BorrowedDepthProps<'a> {
borrow: &'a str,
inner: DepthProps,
}
fn create_random_element_borrowed<'a>(cx: BorrowedDepthProps) -> Element {
println!("{}", cx.borrow);
let bump = cx.bump();
let allocated = bump.alloc(Scoped { scope: cx, props: &cx.inner });
create_random_element(allocated)
}
#[derive(PartialEq, Props)]
struct DepthProps { struct DepthProps {
depth: usize, depth: usize,
root: bool, root: bool,
} }
fn create_random_element(cx: Scope<DepthProps>) -> Element { fn create_random_element(cx: DepthProps) -> Element {
if rand::random::<usize>() % 10 == 0 { if rand::random::<usize>() % 10 == 0 {
cx.needs_update(); needs_update();
} }
let range = if cx.root { 2 } else { 3 }; let range = if cx.root { 2 } else { 3 };
let node = match rand::random::<usize>() % range { let node = match rand::random::<usize>() % range {
@@ -275,24 +252,18 @@ fn create_random_element(cx: Scope<DepthProps>) -> Element {
let node = VNode::new( let node = VNode::new(
None, None,
template, template,
bumpalo::collections::Vec::new_in(cx.bump()), dynamic_node_types
{ .iter()
let dynamic_nodes: Vec<_> = dynamic_node_types .map(|ty| match ty {
.iter() DynamicNodeType::Text => {
.map(|ty| match ty { DynamicNode::Text(VText::new(format!("{}", rand::random::<usize>())))
DynamicNodeType::Text => DynamicNode::Text(VText::new(Box::leak( }
format!("{}", rand::random::<usize>()).into_boxed_str(), DynamicNodeType::Other => create_random_dynamic_node(cx.depth + 1),
))), })
DynamicNodeType::Other => create_random_dynamic_node(cx, cx.depth + 1), .collect(),
}) (0..template.attr_paths.len())
.collect(); .map(|_| create_random_dynamic_attr())
cx.bump().alloc(dynamic_nodes) .collect(),
},
cx.bump().alloc(
(0..template.attr_paths.len())
.map(|_| create_random_dynamic_attr(cx))
.collect::<Vec<_>>(),
),
); );
Some(node) Some(node)
} }
-2
View File
@@ -1,4 +1,3 @@
use bumpalo::Bump;
use dioxus::core::{ElementId, Mutation}; use dioxus::core::{ElementId, Mutation};
use dioxus::prelude::*; use dioxus::prelude::*;
@@ -32,7 +31,6 @@ fn basic_syntax_is_a_template() -> Element {
#[test] #[test]
fn dual_stream() { fn dual_stream() {
let mut dom = VirtualDom::new(basic_syntax_is_a_template); let mut dom = VirtualDom::new(basic_syntax_is_a_template);
let bump = Bump::new();
let edits = dom.rebuild_to_vec().santize(); let edits = dom.rebuild_to_vec().santize();
use Mutation::*; use Mutation::*;
+5 -4
View File
@@ -12,6 +12,7 @@ type Shared<T> = Arc<Mutex<T>>;
#[test] #[test]
fn manual_diffing() { fn manual_diffing() {
#[derive(Clone)]
struct AppProps { struct AppProps {
value: Shared<&'static str>, value: Shared<&'static str>,
} }
@@ -42,11 +43,11 @@ fn manual_diffing() {
fn events_generate() { fn events_generate() {
set_event_converter(Box::new(SerializedHtmlEventConverter)); set_event_converter(Box::new(SerializedHtmlEventConverter));
fn app() -> Element { fn app() -> Element {
let count = cx.use_hook(|| 0); let mut count = use_signal(|| 0);
match *count { match *count() {
0 => render! { 0 => render! {
div { onclick: move |_| *count += 1, div { onclick: move |_| count += 1,
div { "nested" } div { "nested" }
"Click me!" "Click me!"
} }
@@ -80,7 +81,7 @@ fn events_generate() {
// #[test] // #[test]
// fn components_generate() { // fn components_generate() {
// fn app() -> Element { // fn app() -> Element {
// let render_phase = cx.use_hook(|| 0); // let render_phase = once(|| 0);
// *render_phase += 1; // *render_phase += 1;
// match *render_phase { // match *render_phase {
+7 -7
View File
@@ -16,10 +16,10 @@ fn app_drops() {
#[test] #[test]
fn hooks_drop() { fn hooks_drop() {
fn App() -> Element { fn App() -> Element {
cx.use_hook(|| String::from("asd")); once(|| String::from("asd"));
cx.use_hook(|| String::from("asd")); once(|| String::from("asd"));
cx.use_hook(|| String::from("asd")); once(|| String::from("asd"));
cx.use_hook(|| String::from("asd")); once(|| String::from("asd"));
render! { div {} } render! { div {} }
} }
@@ -34,7 +34,7 @@ fn hooks_drop() {
#[test] #[test]
fn contexts_drop() { fn contexts_drop() {
fn App() -> Element { fn App() -> Element {
cx.provide_context(String::from("asd")); provide_context(String::from("asd"));
render! { render! {
div { ChildComp {} } div { ChildComp {} }
@@ -42,7 +42,7 @@ fn contexts_drop() {
} }
fn ChildComp() -> Element { fn ChildComp() -> Element {
let el = cx.consume_context::<String>().unwrap(); let el = consume_context::<String>().unwrap();
render! { div { "hello {el}" } } render! { div { "hello {el}" } }
} }
@@ -57,7 +57,7 @@ fn contexts_drop() {
#[test] #[test]
fn tasks_drop() { fn tasks_drop() {
fn App() -> Element { fn App() -> Element {
cx.spawn(async { spawn(async {
// tokio::time::sleep(std::time::Duration::from_millis(100000)).await; // tokio::time::sleep(std::time::Duration::from_millis(100000)).await;
}); });
+27 -23
View File
@@ -12,13 +12,13 @@ fn test_memory_leak() {
fn app() -> Element { fn app() -> Element {
let val = generation(); let val = generation();
cx.spawn(async {}); spawn(async {});
if val == 2 || val == 4 { if val == 2 || val == 4 {
return render!(()); return render!(());
} }
let name = cx.use_hook(|| String::from("numbers: ")); let mut name = once(|| String::from("numbers: "));
name.push_str("123 "); name.push_str("123 ");
@@ -30,11 +30,11 @@ fn test_memory_leak() {
Child {} Child {}
Child {} Child {}
Child {} Child {}
BorrowedChild { name: name } BorrowedChild { name: name.clone() }
BorrowedChild { name: name } BorrowedChild { name: name.clone() }
BorrowedChild { name: name } BorrowedChild { name: name.clone() }
BorrowedChild { name: name } BorrowedChild { name: name.clone() }
BorrowedChild { name: name } BorrowedChild { name: name.clone() }
) )
} }
@@ -76,7 +76,7 @@ fn memo_works_properly() {
return render!(()); return render!(());
} }
let name = cx.use_hook(|| String::from("asd")); let name = once(|| String::from("asd"));
render!( render!(
div { "Hello, world! {name}" } div { "Hello, world! {name}" }
@@ -89,7 +89,7 @@ fn memo_works_properly() {
na: String, na: String,
} }
fn Child(cx: Scope<ChildProps>) -> Element { fn Child(cx: ChildProps) -> Element {
render!( div { "goodbye world" } ) render!( div { "goodbye world" } )
} }
@@ -116,8 +116,8 @@ fn free_works_on_root_hooks() {
inner: Rc<String>, inner: Rc<String>,
} }
fn app(cx: Scope<AppProps>) -> Element { fn app(cx: AppProps) -> Element {
let name: &AppProps = cx.use_hook(|| cx.clone()); let name: AppProps = once(|| cx.clone());
render!(child_component { inner: name.inner.clone() }) render!(child_component { inner: name.inner.clone() })
} }
@@ -146,20 +146,24 @@ fn supports_async() {
let colors = use_signal(|| vec!["green", "blue", "red"]); let colors = use_signal(|| vec!["green", "blue", "red"]);
let padding = use_signal(|| 10); let padding = use_signal(|| 10);
use_effect(cx, colors, |colors| async move { once(|| {
sleep(Duration::from_millis(1000)).await; spawn(async move {
colors.with_mut(|colors| colors.reverse()); sleep(Duration::from_millis(1000)).await;
colors.with_mut(|colors| colors.reverse());
})
}); });
use_effect(cx, padding, |padding| async move { once(|| {
sleep(Duration::from_millis(10)).await; spawn(async move {
padding.with_mut(|padding| { sleep(Duration::from_millis(10)).await;
if *padding < 65 { padding.with_mut(|padding| {
*padding += 1; if *padding < 65 {
} else { *padding += 1;
*padding = 5; } else {
} *padding = 5;
}); }
});
})
}); });
let colors = colors(); let colors = colors();
+5 -3
View File
@@ -5,13 +5,15 @@ use dioxus::prelude::*;
/// Ensure no issues with not calling rebuild_to_vec /// Ensure no issues with not calling rebuild_to_vec
#[test] #[test]
fn root_node_isnt_null() { fn root_node_isnt_null() {
let dom = VirtualDom::new(|cx| render!("Hello world!")); let dom = VirtualDom::new(|| render!("Hello world!"));
let scope = dom.base_scope(); let scope = dom.base_scope();
// We haven't built the tree, so trying to get out the root node should fail // We haven't built the tree, so trying to get out the root node should fail
assert!(scope.try_root_node().is_none()); assert!(scope.try_root_node().is_none());
// The height should be 0 dom.in_runtime(|| {
assert_eq!(scope.height(), 0); // The height should be 0
assert_eq!(ScopeId::ROOT.height(), 0);
});
} }
+3 -3
View File
@@ -9,15 +9,15 @@ async fn it_works() {
static POLL_COUNT: AtomicUsize = AtomicUsize::new(0); static POLL_COUNT: AtomicUsize = AtomicUsize::new(0);
fn app() -> Element { fn app() -> Element {
cx.use_hook(|| { once(|| {
cx.spawn(async { spawn(async {
for x in 0..10 { for x in 0..10 {
tokio::time::sleep(Duration::from_micros(50)).await; tokio::time::sleep(Duration::from_micros(50)).await;
POLL_COUNT.fetch_add(x, std::sync::atomic::Ordering::Relaxed); POLL_COUNT.fetch_add(x, std::sync::atomic::Ordering::Relaxed);
} }
}); });
cx.spawn(async { spawn(async {
for x in 0..10 { for x in 0..10 {
tokio::time::sleep(Duration::from_micros(25)).await; tokio::time::sleep(Duration::from_micros(25)).await;
POLL_COUNT.fetch_add(x * 2, std::sync::atomic::Ordering::Relaxed); POLL_COUNT.fetch_add(x * 2, std::sync::atomic::Ordering::Relaxed);