From 7b8480f01489f84c4dcee01cea3e97b2ad21adea Mon Sep 17 00:00:00 2001 From: Kaede Hoshikawa Date: Wed, 20 Jul 2022 00:28:19 +0900 Subject: [PATCH 01/12] Rename runtime. --- packages/yew/src/platform/mod.rs | 6 ++-- packages/yew/src/platform/rt_none.rs | 26 ----------------- packages/yew/src/platform/rt_none/mod.rs | 28 +++++++++++++++++++ .../platform/{rt_tokio.rs => rt_tokio/mod.rs} | 0 .../mod.rs} | 0 5 files changed, 31 insertions(+), 29 deletions(-) delete mode 100644 packages/yew/src/platform/rt_none.rs create mode 100644 packages/yew/src/platform/rt_none/mod.rs rename packages/yew/src/platform/{rt_tokio.rs => rt_tokio/mod.rs} (100%) rename packages/yew/src/platform/{rt_wasm_bindgen.rs => rt_wasm_bindgen/mod.rs} (100%) diff --git a/packages/yew/src/platform/mod.rs b/packages/yew/src/platform/mod.rs index 48b35ddd4b0..2e93b44ad4d 100644 --- a/packages/yew/src/platform/mod.rs +++ b/packages/yew/src/platform/mod.rs @@ -48,13 +48,13 @@ pub(crate) mod io; pub mod sync; #[cfg(target_arch = "wasm32")] -#[path = "rt_wasm_bindgen.rs"] +#[path = "rt_wasm_bindgen/mod.rs"] mod imp; #[cfg(all(not(target_arch = "wasm32"), feature = "tokio"))] -#[path = "rt_tokio.rs"] +#[path = "rt_tokio/mod.rs"] mod imp; #[cfg(all(not(target_arch = "wasm32"), not(feature = "tokio")))] -#[path = "rt_none.rs"] +#[path = "rt_none/mod.rs"] mod imp; /// Spawns a task on current thread. diff --git a/packages/yew/src/platform/rt_none.rs b/packages/yew/src/platform/rt_none.rs deleted file mode 100644 index 3a8dc6a671f..00000000000 --- a/packages/yew/src/platform/rt_none.rs +++ /dev/null @@ -1,26 +0,0 @@ -use std::future::Future; - -#[inline(always)] -pub(super) fn spawn_local(_f: F) -where - F: Future + 'static, -{ - panic!( - r#"No runtime configured for this platform, features that requires task spawning can't be used. - Either compile with `target_arch = "wasm32", or enable the `tokio` feature."# - ); -} - -#[cfg(feature = "ssr")] -pub(crate) async fn run_pinned(_create_task: F) -> Fut::Output -where - F: FnOnce() -> Fut, - F: Send + 'static, - Fut: Future + 'static, - Fut::Output: Send + 'static, -{ - panic!( - r#"No runtime configured for this platform, features that requires task spawning can't be used. - Either compile with `target_arch = "wasm32", or enable the `tokio` feature."# - ) -} diff --git a/packages/yew/src/platform/rt_none/mod.rs b/packages/yew/src/platform/rt_none/mod.rs new file mode 100644 index 00000000000..93614ca8b3b --- /dev/null +++ b/packages/yew/src/platform/rt_none/mod.rs @@ -0,0 +1,28 @@ +use std::future::Future; + +static NO_RUNTIME_NOTICE: &str = r#"No runtime configured for this platform, \ + features that requires a runtime can't be used. \ + Either compile with `target_arch = "wasm32", or enable the `tokio` feature."#; + +fn panic_no_runtime() -> ! { + panic!("{}", NO_RUNTIME_NOTICE); +} + +#[inline(always)] +pub(super) fn spawn_local(_f: F) +where + F: Future + 'static, +{ + panic_no_runtime(); +} + +#[cfg(feature = "ssr")] +pub(crate) async fn run_pinned(_create_task: F) -> Fut::Output +where + F: FnOnce() -> Fut, + F: Send + 'static, + Fut: Future + 'static, + Fut::Output: Send + 'static, +{ + panic_no_runtime(); +} diff --git a/packages/yew/src/platform/rt_tokio.rs b/packages/yew/src/platform/rt_tokio/mod.rs similarity index 100% rename from packages/yew/src/platform/rt_tokio.rs rename to packages/yew/src/platform/rt_tokio/mod.rs diff --git a/packages/yew/src/platform/rt_wasm_bindgen.rs b/packages/yew/src/platform/rt_wasm_bindgen/mod.rs similarity index 100% rename from packages/yew/src/platform/rt_wasm_bindgen.rs rename to packages/yew/src/platform/rt_wasm_bindgen/mod.rs From 50aecd608ead2b9dfb3bffff81c2441de4160e3e Mon Sep 17 00:00:00 2001 From: Kaede Hoshikawa Date: Wed, 20 Jul 2022 00:33:45 +0900 Subject: [PATCH 02/12] Implement sleep and interval. --- packages/yew/Cargo.toml | 4 +-- packages/yew/src/platform/mod.rs | 1 + packages/yew/src/platform/rt_none/mod.rs | 2 ++ packages/yew/src/platform/rt_none/time.rs | 13 ++++++++ packages/yew/src/platform/rt_tokio/mod.rs | 2 ++ packages/yew/src/platform/rt_tokio/time.rs | 14 +++++++++ .../yew/src/platform/rt_wasm_bindgen/mod.rs | 2 ++ .../yew/src/platform/rt_wasm_bindgen/time.rs | 17 +++++++++++ packages/yew/src/platform/time.rs | 30 +++++++++++++++++++ 9 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 packages/yew/src/platform/rt_none/time.rs create mode 100644 packages/yew/src/platform/rt_tokio/time.rs create mode 100644 packages/yew/src/platform/rt_wasm_bindgen/time.rs create mode 100644 packages/yew/src/platform/time.rs diff --git a/packages/yew/Cargo.toml b/packages/yew/Cargo.toml index 29194e2dae6..24880925f0d 100644 --- a/packages/yew/Cargo.toml +++ b/packages/yew/Cargo.toml @@ -26,7 +26,7 @@ slab = "0.4" wasm-bindgen = "0.2" yew-macro = { version = "^0.19.0", path = "../yew-macro" } thiserror = "1.0" -futures = { version = "0.3", optional = true } +futures = { version = "0.3", default-features = false, features = ["std"] } html-escape = { version = "0.2.9", optional = true } implicit-clone = { version = "0.3", features = ["map"] } base64ct = { version = "1.5.0", features = ["std"], optional = true } @@ -96,7 +96,7 @@ features = [ [features] tokio = ["tokio/rt", "dep:num_cpus", "dep:tokio-util"] -ssr = ["dep:futures", "dep:html-escape", "dep:base64ct", "dep:bincode"] +ssr = ["dep:html-escape", "dep:base64ct", "dep:bincode"] csr = [] hydration = ["csr", "dep:bincode"] nightly = ["yew-macro/nightly"] diff --git a/packages/yew/src/platform/mod.rs b/packages/yew/src/platform/mod.rs index 2e93b44ad4d..bbab2211b03 100644 --- a/packages/yew/src/platform/mod.rs +++ b/packages/yew/src/platform/mod.rs @@ -46,6 +46,7 @@ use std::future::Future; pub(crate) mod io; pub mod sync; +pub mod time; #[cfg(target_arch = "wasm32")] #[path = "rt_wasm_bindgen/mod.rs"] diff --git a/packages/yew/src/platform/rt_none/mod.rs b/packages/yew/src/platform/rt_none/mod.rs index 93614ca8b3b..fa7c1fde384 100644 --- a/packages/yew/src/platform/rt_none/mod.rs +++ b/packages/yew/src/platform/rt_none/mod.rs @@ -1,5 +1,7 @@ use std::future::Future; +pub(crate) mod time; + static NO_RUNTIME_NOTICE: &str = r#"No runtime configured for this platform, \ features that requires a runtime can't be used. \ Either compile with `target_arch = "wasm32", or enable the `tokio` feature."#; diff --git a/packages/yew/src/platform/rt_none/time.rs b/packages/yew/src/platform/rt_none/time.rs new file mode 100644 index 00000000000..d15cbb18ff7 --- /dev/null +++ b/packages/yew/src/platform/rt_none/time.rs @@ -0,0 +1,13 @@ +use std::time::Duration; + +use futures::stream::LocalBoxStream; + +use super::panic_no_runtime; + +pub(crate) async fn sleep(_dur: Duration) { + panic_no_runtime(); +} + +pub(crate) fn interval(_dur: Duration) -> LocalBoxStream<'static, ()> { + panic_no_runtime(); +} diff --git a/packages/yew/src/platform/rt_tokio/mod.rs b/packages/yew/src/platform/rt_tokio/mod.rs index ee8e2251a71..e337676ecff 100644 --- a/packages/yew/src/platform/rt_tokio/mod.rs +++ b/packages/yew/src/platform/rt_tokio/mod.rs @@ -1,5 +1,7 @@ use std::future::Future; +pub(crate) mod time; + #[cfg(feature = "ssr")] pub(super) async fn run_pinned(create_task: F) -> Fut::Output where diff --git a/packages/yew/src/platform/rt_tokio/time.rs b/packages/yew/src/platform/rt_tokio/time.rs new file mode 100644 index 00000000000..c6d49abdbe2 --- /dev/null +++ b/packages/yew/src/platform/rt_tokio/time.rs @@ -0,0 +1,14 @@ +use std::future::Future; +use std::time::Duration; + +use futures::stream::{Stream, StreamExt}; +use tokio_stream::wrappers::IntervalStream; + +#[inline] +pub(crate) fn sleep(dur: Duration) -> impl Future { + tokio::time::sleep(dur) +} + +pub(crate) fn interval(dur: Duration) -> impl Stream { + IntervalStream::new(tokio::time::interval(dur)).then(|_| async {}) +} diff --git a/packages/yew/src/platform/rt_wasm_bindgen/mod.rs b/packages/yew/src/platform/rt_wasm_bindgen/mod.rs index 8307bfd4350..c0dde7f6a89 100644 --- a/packages/yew/src/platform/rt_wasm_bindgen/mod.rs +++ b/packages/yew/src/platform/rt_wasm_bindgen/mod.rs @@ -1,6 +1,8 @@ #[cfg(feature = "ssr")] use std::future::Future; +pub(crate) mod time; + pub(super) use wasm_bindgen_futures::spawn_local; #[cfg(feature = "ssr")] diff --git a/packages/yew/src/platform/rt_wasm_bindgen/time.rs b/packages/yew/src/platform/rt_wasm_bindgen/time.rs new file mode 100644 index 00000000000..2e4e7da9636 --- /dev/null +++ b/packages/yew/src/platform/rt_wasm_bindgen/time.rs @@ -0,0 +1,17 @@ +use std::future::Future; +use std::time::Duration; + +use futures::stream::Stream; +use wasm_bindgen::UnwrapThrowExt; + +#[inline] +pub(crate) fn sleep(dur: Duration) -> impl Future { + gloo::timers::future::sleep(dur) +} + +pub(crate) fn interval(dur: Duration) -> impl Stream { + let millis = u32::try_from(dur.as_millis()) + .expect_throw("failed to cast the duration into a u32 with Duration::as_millis."); + + gloo::timers::future::IntervalStream::new(millis) +} diff --git a/packages/yew/src/platform/time.rs b/packages/yew/src/platform/time.rs new file mode 100644 index 00000000000..8dbbb388c3a --- /dev/null +++ b/packages/yew/src/platform/time.rs @@ -0,0 +1,30 @@ +//! Utilities for bridging time and tasks. + +use std::future::Future; +use std::time::Duration; + +use futures::stream::Stream; + +use crate::platform::imp::time as imp; + +/// Waits until duration has elapsed. +/// +/// # Panics +/// +/// On some platforms, if the prodvided duration cannot be converted to u32 in milliseconds, this +/// function will panic. +#[inline(always)] +pub fn sleep(dur: Duration) -> impl Future { + imp::sleep(dur) +} + +/// Creates a Stream that yields an item after every period has elapsed. +/// +/// # Panics +/// +/// On some platforms, if the prodvided period cannot be converted to u32 in milliseconds, this +/// function will panic. +#[inline(always)] +pub fn interval(period: Duration) -> impl Stream { + imp::interval(period) +} From b1d9c5ae4c8c55fe7acae56a51e4df414355ba79 Mon Sep 17 00:00:00 2001 From: Kaede Hoshikawa Date: Wed, 20 Jul 2022 00:43:21 +0900 Subject: [PATCH 03/12] Replace sleep usage with one provided by the platform. --- packages/yew-router/tests/basename.rs | 2 +- packages/yew-router/tests/browser_router.rs | 2 +- packages/yew-router/tests/hash_router.rs | 2 +- packages/yew-router/tests/link.rs | 2 +- packages/yew/Cargo.toml | 2 +- packages/yew/src/virtual_dom/vsuspense.rs | 2 +- packages/yew/tests/hydration.rs | 4 +- packages/yew/tests/layout.rs | 2 +- packages/yew/tests/mod.rs | 2 +- packages/yew/tests/suspense.rs | 66 ++++++++++----------- packages/yew/tests/use_callback.rs | 2 +- packages/yew/tests/use_context.rs | 2 +- packages/yew/tests/use_effect.rs | 2 +- packages/yew/tests/use_memo.rs | 2 +- packages/yew/tests/use_prepared_state.rs | 2 +- packages/yew/tests/use_reducer.rs | 2 +- packages/yew/tests/use_ref.rs | 2 +- packages/yew/tests/use_state.rs | 2 +- packages/yew/tests/use_transitive_state.rs | 2 +- 19 files changed, 52 insertions(+), 52 deletions(-) diff --git a/packages/yew-router/tests/basename.rs b/packages/yew-router/tests/basename.rs index e92fec0426c..0ba058c5cd2 100644 --- a/packages/yew-router/tests/basename.rs +++ b/packages/yew-router/tests/basename.rs @@ -1,9 +1,9 @@ use std::time::Duration; -use gloo::timers::future::sleep; use serde::{Deserialize, Serialize}; use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure}; use yew::functional::function_component; +use yew::platform::time::sleep; use yew::prelude::*; use yew_router::prelude::*; diff --git a/packages/yew-router/tests/browser_router.rs b/packages/yew-router/tests/browser_router.rs index 77c3002e27c..f3a5f49379c 100644 --- a/packages/yew-router/tests/browser_router.rs +++ b/packages/yew-router/tests/browser_router.rs @@ -1,9 +1,9 @@ use std::time::Duration; -use gloo::timers::future::sleep; use serde::{Deserialize, Serialize}; use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure}; use yew::functional::function_component; +use yew::platform::time::sleep; use yew::prelude::*; use yew_router::prelude::*; diff --git a/packages/yew-router/tests/hash_router.rs b/packages/yew-router/tests/hash_router.rs index 7f8e79f3eec..48f793ca346 100644 --- a/packages/yew-router/tests/hash_router.rs +++ b/packages/yew-router/tests/hash_router.rs @@ -1,9 +1,9 @@ use std::time::Duration; -use gloo::timers::future::sleep; use serde::{Deserialize, Serialize}; use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure}; use yew::functional::function_component; +use yew::platform::time::sleep; use yew::prelude::*; use yew_router::prelude::*; diff --git a/packages/yew-router/tests/link.rs b/packages/yew-router/tests/link.rs index ddff1bd9556..50510b79242 100644 --- a/packages/yew-router/tests/link.rs +++ b/packages/yew-router/tests/link.rs @@ -1,9 +1,9 @@ use std::time::Duration; -use gloo::timers::future::sleep; use serde::{Deserialize, Serialize}; use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure}; use yew::functional::function_component; +use yew::platform::time::sleep; use yew::prelude::*; use yew_router::prelude::*; diff --git a/packages/yew/Cargo.toml b/packages/yew/Cargo.toml index 24880925f0d..b4ad06a1b7e 100644 --- a/packages/yew/Cargo.toml +++ b/packages/yew/Cargo.toml @@ -95,7 +95,7 @@ features = [ ] [features] -tokio = ["tokio/rt", "dep:num_cpus", "dep:tokio-util"] +tokio = ["tokio/rt", "tokio/time", "dep:num_cpus", "dep:tokio-util"] ssr = ["dep:html-escape", "dep:base64ct", "dep:bincode"] csr = [] hydration = ["csr", "dep:bincode"] diff --git a/packages/yew/src/virtual_dom/vsuspense.rs b/packages/yew/src/virtual_dom/vsuspense.rs index 35dd30253a1..c618a5dcd46 100644 --- a/packages/yew/src/virtual_dom/vsuspense.rs +++ b/packages/yew/src/virtual_dom/vsuspense.rs @@ -65,8 +65,8 @@ mod ssr_tests { use tokio::task::{spawn_local, LocalSet}; use tokio::test; - use tokio::time::sleep; + use crate::platform::time::sleep; use crate::prelude::*; use crate::suspense::{Suspension, SuspensionResult}; use crate::ServerRenderer; diff --git a/packages/yew/tests/hydration.rs b/packages/yew/tests/hydration.rs index 52fb193adcf..cdbd98c651c 100644 --- a/packages/yew/tests/hydration.rs +++ b/packages/yew/tests/hydration.rs @@ -8,11 +8,11 @@ use std::time::Duration; mod common; use common::{obtain_result, obtain_result_by_id}; -use gloo::timers::future::sleep; use wasm_bindgen::JsCast; use wasm_bindgen_futures::spawn_local; use wasm_bindgen_test::*; use web_sys::{HtmlElement, HtmlTextAreaElement}; +use yew::platform::time::sleep; use yew::prelude::*; use yew::suspense::{use_future, Suspension, SuspensionResult}; use yew::{Renderer, ServerRenderer}; @@ -769,7 +769,7 @@ async fn hydration_suspense_no_flickering() { #[hook] pub fn use_suspend() -> SuspensionResult<()> { use_future(|| async { - gloo::timers::future::sleep(std::time::Duration::from_millis(200)).await; + yew::platform::time::sleep(std::time::Duration::from_millis(200)).await; })?; Ok(()) } diff --git a/packages/yew/tests/layout.rs b/packages/yew/tests/layout.rs index 3cdaf918238..ff31909ce65 100644 --- a/packages/yew/tests/layout.rs +++ b/packages/yew/tests/layout.rs @@ -7,9 +7,9 @@ wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); use std::time::Duration; use common::obtain_result; -use gloo::timers::future::sleep; use wasm_bindgen_futures::spawn_local; use wasm_bindgen_test::*; +use yew::platform::time::sleep; use yew::prelude::*; #[wasm_bindgen_test] diff --git a/packages/yew/tests/mod.rs b/packages/yew/tests/mod.rs index f61f01d24f8..bf75edc29ed 100644 --- a/packages/yew/tests/mod.rs +++ b/packages/yew/tests/mod.rs @@ -5,8 +5,8 @@ mod common; use std::time::Duration; use common::obtain_result; -use gloo::timers::future::sleep; use wasm_bindgen_test::*; +use yew::platform::time::sleep; use yew::prelude::*; wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); diff --git a/packages/yew/tests/suspense.rs b/packages/yew/tests/suspense.rs index eb045a7c37b..1168f71d4cd 100644 --- a/packages/yew/tests/suspense.rs +++ b/packages/yew/tests/suspense.rs @@ -11,10 +11,10 @@ wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); use std::cell::RefCell; use std::rc::Rc; -use gloo::timers::future::TimeoutFuture; use wasm_bindgen::JsCast; use wasm_bindgen_futures::spawn_local; use web_sys::{HtmlElement, HtmlTextAreaElement}; +use yew::platform::time::sleep; use yew::suspense::{use_future, use_future_with_deps, Suspension, SuspensionResult}; #[wasm_bindgen_test] @@ -29,7 +29,7 @@ async fn suspense_works() { let (s, handle) = Suspension::new(); spawn_local(async move { - TimeoutFuture::new(50).await; + sleep(Duration::from_millis(50)).await; handle.resume(); }); @@ -100,11 +100,11 @@ async fn suspense_works() { yew::Renderer::::with_root(gloo_utils::document().get_element_by_id("output").unwrap()) .render(); - TimeoutFuture::new(10).await; + sleep(Duration::from_millis(10)).await; let result = obtain_result(); assert_eq!(result.as_str(), "
wait...
"); - TimeoutFuture::new(50).await; + sleep(Duration::from_millis(50)).await; let result = obtain_result(); assert_eq!( @@ -112,7 +112,7 @@ async fn suspense_works() { r#"
0
"# ); - TimeoutFuture::new(10).await; + sleep(Duration::from_millis(10)).await; gloo_utils::document() .query_selector(".increase") @@ -122,7 +122,7 @@ async fn suspense_works() { .unwrap() .click(); - TimeoutFuture::new(0).await; + sleep(Duration::ZERO).await; gloo_utils::document() .query_selector(".increase") @@ -132,7 +132,7 @@ async fn suspense_works() { .unwrap() .click(); - TimeoutFuture::new(1).await; + sleep(Duration::from_millis(1)).await; let result = obtain_result(); assert_eq!( @@ -148,11 +148,11 @@ async fn suspense_works() { .unwrap() .click(); - TimeoutFuture::new(10).await; + sleep(Duration::from_millis(10)).await; let result = obtain_result(); assert_eq!(result.as_str(), "
wait...
"); - TimeoutFuture::new(50).await; + sleep(Duration::from_millis(50)).await; let result = obtain_result(); assert_eq!( @@ -181,7 +181,7 @@ async fn suspense_not_suspended_at_start() { let (s, handle) = Suspension::new(); spawn_local(async move { - TimeoutFuture::new(50).await; + sleep(Duration::from_millis(50)).await; handle.resume(); }); @@ -250,7 +250,7 @@ async fn suspense_not_suspended_at_start() { yew::Renderer::::with_root(gloo_utils::document().get_element_by_id("output").unwrap()) .render(); - TimeoutFuture::new(10).await; + sleep(Duration::from_millis(10)).await; let result = obtain_result(); assert_eq!( @@ -265,11 +265,11 @@ async fn suspense_not_suspended_at_start() { .unwrap() .click(); - TimeoutFuture::new(10).await; + sleep(Duration::from_millis(10)).await; let result = obtain_result(); assert_eq!(result.as_str(), "
wait...
"); - TimeoutFuture::new(50).await; + sleep(Duration::from_millis(50)).await; let result = obtain_result(); assert_eq!( @@ -290,7 +290,7 @@ async fn suspense_nested_suspense_works() { let (s, handle) = Suspension::new(); spawn_local(async move { - TimeoutFuture::new(50).await; + sleep(Duration::from_millis(50)).await; handle.resume(); }); @@ -369,11 +369,11 @@ async fn suspense_nested_suspense_works() { yew::Renderer::::with_root(gloo_utils::document().get_element_by_id("output").unwrap()) .render(); - TimeoutFuture::new(10).await; + sleep(Duration::from_millis(10)).await; let result = obtain_result(); assert_eq!(result.as_str(), "
wait...(outer)
"); - TimeoutFuture::new(50).await; + sleep(Duration::from_millis(50)).await; let result = obtain_result(); assert_eq!( @@ -381,7 +381,7 @@ async fn suspense_nested_suspense_works() { r#"
wait...(inner)
"# ); - TimeoutFuture::new(50).await; + sleep(Duration::from_millis(50)).await; let result = obtain_result(); assert_eq!( @@ -397,14 +397,14 @@ async fn suspense_nested_suspense_works() { .unwrap() .click(); - TimeoutFuture::new(10).await; + sleep(Duration::from_millis(10)).await; let result = obtain_result(); assert_eq!( result.as_str(), r#"
wait...(inner)
"# ); - TimeoutFuture::new(50).await; + sleep(Duration::from_millis(50)).await; let result = obtain_result(); assert_eq!( @@ -425,7 +425,7 @@ async fn effects_not_run_when_suspended() { let (s, handle) = Suspension::new(); spawn_local(async move { - TimeoutFuture::new(50).await; + sleep(Duration::from_millis(50)).await; handle.resume(); }); @@ -528,12 +528,12 @@ async fn effects_not_run_when_suspended() { ) .render(); - TimeoutFuture::new(10).await; + sleep(Duration::from_millis(10)).await; let result = obtain_result(); assert_eq!(result.as_str(), "
wait...
"); assert_eq!(*counter.borrow(), 0); // effects not called. - TimeoutFuture::new(50).await; + sleep(Duration::from_millis(50)).await; let result = obtain_result(); assert_eq!( @@ -542,7 +542,7 @@ async fn effects_not_run_when_suspended() { ); assert_eq!(*counter.borrow(), 1); // effects ran 1 time. - TimeoutFuture::new(10).await; + sleep(Duration::from_millis(10)).await; gloo_utils::document() .query_selector(".increase") @@ -552,7 +552,7 @@ async fn effects_not_run_when_suspended() { .unwrap() .click(); - TimeoutFuture::new(0).await; + sleep(Duration::ZERO).await; gloo_utils::document() .query_selector(".increase") @@ -562,7 +562,7 @@ async fn effects_not_run_when_suspended() { .unwrap() .click(); - TimeoutFuture::new(0).await; + sleep(Duration::from_millis(0)).await; let result = obtain_result(); assert_eq!( @@ -579,12 +579,12 @@ async fn effects_not_run_when_suspended() { .unwrap() .click(); - TimeoutFuture::new(10).await; + sleep(Duration::from_millis(10)).await; let result = obtain_result(); assert_eq!(result.as_str(), "
wait...
"); assert_eq!(*counter.borrow(), 3); // effects ran 3 times. - TimeoutFuture::new(50).await; + sleep(Duration::from_millis(50)).await; let result = obtain_result(); assert_eq!( @@ -599,7 +599,7 @@ async fn use_suspending_future_works() { #[function_component(Content)] fn content() -> HtmlResult { let _sleep_handle = use_future(|| async move { - TimeoutFuture::new(50).await; + sleep(Duration::from_millis(50)).await; })?; Ok(html! { @@ -625,11 +625,11 @@ async fn use_suspending_future_works() { yew::Renderer::::with_root(gloo_utils::document().get_element_by_id("output").unwrap()) .render(); - TimeoutFuture::new(10).await; + sleep(Duration::from_millis(10)).await; let result = obtain_result(); assert_eq!(result.as_str(), "
wait...
"); - TimeoutFuture::new(50).await; + sleep(Duration::from_millis(50)).await; let result = obtain_result(); assert_eq!(result.as_str(), r#"
Content
"#); @@ -646,7 +646,7 @@ async fn use_suspending_future_with_deps_works() { fn content(ContentProps { delay_millis }: &ContentProps) -> HtmlResult { let delayed_result = use_future_with_deps( |delay_millis| async move { - TimeoutFuture::new(*delay_millis).await; + sleep(Duration::from_millis(*delay_millis)).await; 42 }, *delay_millis, @@ -675,11 +675,11 @@ async fn use_suspending_future_with_deps_works() { yew::Renderer::::with_root(gloo_utils::document().get_element_by_id("output").unwrap()) .render(); - TimeoutFuture::new(10).await; + sleep(Duration::from_millis(10)).await; let result = obtain_result(); assert_eq!(result.as_str(), "
wait...
"); - TimeoutFuture::new(50).await; + sleep(Duration::from_millis(50)).await; let result = obtain_result(); assert_eq!(result.as_str(), r#"
42
"#); diff --git a/packages/yew/tests/use_callback.rs b/packages/yew/tests/use_callback.rs index b7f8a45c1f8..9c619a8d1b8 100644 --- a/packages/yew/tests/use_callback.rs +++ b/packages/yew/tests/use_callback.rs @@ -7,8 +7,8 @@ mod common; use std::time::Duration; use common::obtain_result; -use gloo::timers::future::sleep; use wasm_bindgen_test::*; +use yew::platform::time::sleep; use yew::prelude::*; wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); diff --git a/packages/yew/tests/use_context.rs b/packages/yew/tests/use_context.rs index 19f58f494e1..63a2fa276a4 100644 --- a/packages/yew/tests/use_context.rs +++ b/packages/yew/tests/use_context.rs @@ -6,8 +6,8 @@ use std::rc::Rc; use std::time::Duration; use common::obtain_result_by_id; -use gloo::timers::future::sleep; use wasm_bindgen_test::*; +use yew::platform::time::sleep; use yew::prelude::*; wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); diff --git a/packages/yew/tests/use_effect.rs b/packages/yew/tests/use_effect.rs index c7969544be5..ce344e02083 100644 --- a/packages/yew/tests/use_effect.rs +++ b/packages/yew/tests/use_effect.rs @@ -7,8 +7,8 @@ use std::rc::Rc; use std::time::Duration; use common::obtain_result; -use gloo::timers::future::sleep; use wasm_bindgen_test::*; +use yew::platform::time::sleep; use yew::prelude::*; wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); diff --git a/packages/yew/tests/use_memo.rs b/packages/yew/tests/use_memo.rs index c62b71852c6..6ad0c1a29cb 100644 --- a/packages/yew/tests/use_memo.rs +++ b/packages/yew/tests/use_memo.rs @@ -7,8 +7,8 @@ mod common; use std::time::Duration; use common::obtain_result; -use gloo::timers::future::sleep; use wasm_bindgen_test::*; +use yew::platform::time::sleep; use yew::prelude::*; wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); diff --git a/packages/yew/tests/use_prepared_state.rs b/packages/yew/tests/use_prepared_state.rs index 2263aff4f46..a88d7de4297 100644 --- a/packages/yew/tests/use_prepared_state.rs +++ b/packages/yew/tests/use_prepared_state.rs @@ -7,8 +7,8 @@ use std::time::Duration; mod common; use common::obtain_result_by_id; -use gloo::timers::future::sleep; use wasm_bindgen_test::*; +use yew::platform::time::sleep; use yew::prelude::*; use yew::{Renderer, ServerRenderer}; diff --git a/packages/yew/tests/use_reducer.rs b/packages/yew/tests/use_reducer.rs index dddde7c8541..3364c4907f5 100644 --- a/packages/yew/tests/use_reducer.rs +++ b/packages/yew/tests/use_reducer.rs @@ -4,11 +4,11 @@ use std::collections::HashSet; use std::rc::Rc; use std::time::Duration; -use gloo::timers::future::sleep; use gloo_utils::document; use wasm_bindgen::JsCast; use wasm_bindgen_test::*; use web_sys::HtmlElement; +use yew::platform::time::sleep; use yew::prelude::*; mod common; diff --git a/packages/yew/tests/use_ref.rs b/packages/yew/tests/use_ref.rs index d0e34e4dc8a..142d87c1bb6 100644 --- a/packages/yew/tests/use_ref.rs +++ b/packages/yew/tests/use_ref.rs @@ -6,8 +6,8 @@ use std::ops::DerefMut; use std::time::Duration; use common::obtain_result; -use gloo::timers::future::sleep; use wasm_bindgen_test::*; +use yew::platform::time::sleep; use yew::prelude::*; wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); diff --git a/packages/yew/tests/use_state.rs b/packages/yew/tests/use_state.rs index 68800dae0f9..0562c6f71c0 100644 --- a/packages/yew/tests/use_state.rs +++ b/packages/yew/tests/use_state.rs @@ -5,8 +5,8 @@ mod common; use std::time::Duration; use common::obtain_result; -use gloo::timers::future::sleep; use wasm_bindgen_test::*; +use yew::platform::time::sleep; use yew::prelude::*; wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); diff --git a/packages/yew/tests/use_transitive_state.rs b/packages/yew/tests/use_transitive_state.rs index 3e180d2187d..31debb1d68b 100644 --- a/packages/yew/tests/use_transitive_state.rs +++ b/packages/yew/tests/use_transitive_state.rs @@ -6,8 +6,8 @@ use std::time::Duration; mod common; use common::obtain_result_by_id; -use gloo::timers::future::sleep; use wasm_bindgen_test::*; +use yew::platform::time::sleep; use yew::prelude::*; use yew::{Renderer, ServerRenderer}; From 89344b3eaaaf37f15161abd4f1a2c2d1a801809c Mon Sep 17 00:00:00 2001 From: Kaede Hoshikawa Date: Wed, 20 Jul 2022 00:51:40 +0900 Subject: [PATCH 04/12] Fix imports. --- packages/yew/tests/suspense.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/yew/tests/suspense.rs b/packages/yew/tests/suspense.rs index 1168f71d4cd..0705c8a23e8 100644 --- a/packages/yew/tests/suspense.rs +++ b/packages/yew/tests/suspense.rs @@ -2,21 +2,21 @@ mod common; -use common::obtain_result; -use wasm_bindgen_test::*; -use yew::prelude::*; - -wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); - use std::cell::RefCell; use std::rc::Rc; +use std::time::Duration; +use common::obtain_result; use wasm_bindgen::JsCast; use wasm_bindgen_futures::spawn_local; +use wasm_bindgen_test::*; use web_sys::{HtmlElement, HtmlTextAreaElement}; use yew::platform::time::sleep; +use yew::prelude::*; use yew::suspense::{use_future, use_future_with_deps, Suspension, SuspensionResult}; +wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + #[wasm_bindgen_test] async fn suspense_works() { #[derive(PartialEq)] From 8bf99f3a36b4dbd446de14e791f4955ed255a783 Mon Sep 17 00:00:00 2001 From: Kaede Hoshikawa Date: Wed, 20 Jul 2022 00:57:07 +0900 Subject: [PATCH 05/12] Fix tests. --- packages/yew/tests/suspense.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/yew/tests/suspense.rs b/packages/yew/tests/suspense.rs index 0705c8a23e8..1ebb65e1096 100644 --- a/packages/yew/tests/suspense.rs +++ b/packages/yew/tests/suspense.rs @@ -639,7 +639,7 @@ async fn use_suspending_future_works() { async fn use_suspending_future_with_deps_works() { #[derive(PartialEq, Properties)] struct ContentProps { - delay_millis: u32, + delay_millis: u64, } #[function_component(Content)] From 68fcea773136157ebd15d0dda87623c99658a4b7 Mon Sep 17 00:00:00 2001 From: Kaede Hoshikawa Date: Wed, 20 Jul 2022 01:01:41 +0900 Subject: [PATCH 06/12] Enable futures on gloo. --- packages/yew/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/yew/Cargo.toml b/packages/yew/Cargo.toml index b4ad06a1b7e..79063473d24 100644 --- a/packages/yew/Cargo.toml +++ b/packages/yew/Cargo.toml @@ -18,7 +18,7 @@ rust-version = "1.60.0" [dependencies] console_error_panic_hook = "0.1" -gloo = "0.8" +gloo = { version = "0.8", features = ["futures"] } gloo-utils = "0.1.0" indexmap = { version = "1", features = ["std"] } js-sys = "0.3" From 2968aecc854e817102b3e0e1c25998af791fc453 Mon Sep 17 00:00:00 2001 From: Kaede Hoshikawa Date: Wed, 20 Jul 2022 01:19:59 +0900 Subject: [PATCH 07/12] Always inline sleep. --- packages/yew/src/platform/rt_tokio/time.rs | 2 +- packages/yew/src/platform/rt_wasm_bindgen/time.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/yew/src/platform/rt_tokio/time.rs b/packages/yew/src/platform/rt_tokio/time.rs index c6d49abdbe2..bcab607c3ef 100644 --- a/packages/yew/src/platform/rt_tokio/time.rs +++ b/packages/yew/src/platform/rt_tokio/time.rs @@ -4,7 +4,7 @@ use std::time::Duration; use futures::stream::{Stream, StreamExt}; use tokio_stream::wrappers::IntervalStream; -#[inline] +#[inline(always)] pub(crate) fn sleep(dur: Duration) -> impl Future { tokio::time::sleep(dur) } diff --git a/packages/yew/src/platform/rt_wasm_bindgen/time.rs b/packages/yew/src/platform/rt_wasm_bindgen/time.rs index 2e4e7da9636..0cdc158a77e 100644 --- a/packages/yew/src/platform/rt_wasm_bindgen/time.rs +++ b/packages/yew/src/platform/rt_wasm_bindgen/time.rs @@ -4,7 +4,7 @@ use std::time::Duration; use futures::stream::Stream; use wasm_bindgen::UnwrapThrowExt; -#[inline] +#[inline(always)] pub(crate) fn sleep(dur: Duration) -> impl Future { gloo::timers::future::sleep(dur) } From 3193c1eb52fd08ba0233ed5b7d7e6265c0c786e7 Mon Sep 17 00:00:00 2001 From: Kaede Hoshikawa Date: Thu, 21 Jul 2022 01:43:43 +0900 Subject: [PATCH 08/12] Fix tests. --- packages/yew/tests/common/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/yew/tests/common/mod.rs b/packages/yew/tests/common/mod.rs index 0d56b773930..533e5e0c567 100644 --- a/packages/yew/tests/common/mod.rs +++ b/packages/yew/tests/common/mod.rs @@ -15,5 +15,5 @@ pub fn obtain_result_by_id(id: &str) -> String { } pub fn output_element() -> web_sys::Element { - gloo_utils::document().get_element_by_id("output").unwrap() + gloo::utils::document().get_element_by_id("output").unwrap() } From 5f3b15d40d1597ba4061ea6d4753a00594aef57e Mon Sep 17 00:00:00 2001 From: Kaede Hoshikawa Date: Thu, 21 Jul 2022 20:55:40 +0900 Subject: [PATCH 09/12] Implement sleep in house. --- packages/yew/src/dom_bundle/bcomp.rs | 6 +-- .../yew/src/platform/rt_wasm_bindgen/time.rs | 51 +++++++++++++++++-- packages/yew/src/platform/time.rs | 10 ---- 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/packages/yew/src/dom_bundle/bcomp.rs b/packages/yew/src/dom_bundle/bcomp.rs index 608bcf15076..3fcae3106a8 100644 --- a/packages/yew/src/dom_bundle/bcomp.rs +++ b/packages/yew/src/dom_bundle/bcomp.rs @@ -165,14 +165,12 @@ mod feat_hydration { #[cfg(target_arch = "wasm32")] #[cfg(test)] mod tests { - use std::ops::Deref; - use gloo::utils::document; use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure}; - use web_sys::{Element, Node}; + use web_sys::Element; use super::*; - use crate::dom_bundle::{Bundle, Reconcilable, ReconcileTarget}; + use crate::dom_bundle::{eeconcilable, ReconcileTarget}; use crate::virtual_dom::{Key, VChild, VNode}; use crate::{html, scheduler, Children, Component, Context, Html, NodeRef, Properties}; diff --git a/packages/yew/src/platform/rt_wasm_bindgen/time.rs b/packages/yew/src/platform/rt_wasm_bindgen/time.rs index 0cdc158a77e..99206d354af 100644 --- a/packages/yew/src/platform/rt_wasm_bindgen/time.rs +++ b/packages/yew/src/platform/rt_wasm_bindgen/time.rs @@ -1,17 +1,60 @@ use std::future::Future; +use std::pin::Pin; +use std::task::{Context, Poll}; use std::time::Duration; +use futures::stream; use futures::stream::Stream; +use gloo::timers::callback::Timeout; use wasm_bindgen::UnwrapThrowExt; #[inline(always)] pub(crate) fn sleep(dur: Duration) -> impl Future { - gloo::timers::future::sleep(dur) + pub struct Sleep { + inner: Option, + dur_millis: Option, + } + + impl Future for Sleep { + type Output = (); + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + // set_timeout can only accept maximum of i32, so we wrap around if it gets longer. + static I32_MAX_U128: u128 = 2_147_483_647; + static I32_MAX_U32: u32 = 2_147_483_647; + + match self.dur_millis.as_mut() { + Some(m) if *m > I32_MAX_U128 => { + *m -= I32_MAX_U128; + let waker = cx.waker().clone(); + self.inner = Some(Timeout::new(I32_MAX_U32, move || { + waker.wake(); + })); + Poll::Pending + } + Some(m) => { + let waker = cx.waker().clone(); + self.inner = Some(Timeout::new((*m).try_into().unwrap_throw(), move || { + waker.wake(); + })); + self.dur_millis = None; + Poll::Pending + } + None => Poll::Ready(()), + } + } + } + + Sleep { + inner: None, + dur_millis: Some(dur.as_millis()), + } } pub(crate) fn interval(dur: Duration) -> impl Stream { - let millis = u32::try_from(dur.as_millis()) - .expect_throw("failed to cast the duration into a u32 with Duration::as_millis."); + stream::unfold((), move |_: ()| async move { + sleep(dur).await; - gloo::timers::future::IntervalStream::new(millis) + Some(((), ())) + }) } diff --git a/packages/yew/src/platform/time.rs b/packages/yew/src/platform/time.rs index 8dbbb388c3a..2b359172dea 100644 --- a/packages/yew/src/platform/time.rs +++ b/packages/yew/src/platform/time.rs @@ -8,22 +8,12 @@ use futures::stream::Stream; use crate::platform::imp::time as imp; /// Waits until duration has elapsed. -/// -/// # Panics -/// -/// On some platforms, if the prodvided duration cannot be converted to u32 in milliseconds, this -/// function will panic. #[inline(always)] pub fn sleep(dur: Duration) -> impl Future { imp::sleep(dur) } /// Creates a Stream that yields an item after every period has elapsed. -/// -/// # Panics -/// -/// On some platforms, if the prodvided period cannot be converted to u32 in milliseconds, this -/// function will panic. #[inline(always)] pub fn interval(period: Duration) -> impl Stream { imp::interval(period) From 9d4c6d4f2db1a94541e857113a2839cc622ba59e Mon Sep 17 00:00:00 2001 From: Kaede Hoshikawa Date: Thu, 21 Jul 2022 21:11:47 +0900 Subject: [PATCH 10/12] Remove futures feature. --- packages/yew/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/yew/Cargo.toml b/packages/yew/Cargo.toml index 68b774ef88d..6742ddbbac0 100644 --- a/packages/yew/Cargo.toml +++ b/packages/yew/Cargo.toml @@ -18,7 +18,7 @@ rust-version = "1.60.0" [dependencies] console_error_panic_hook = "0.1" -gloo = { version = "0.8", features = ["futures"] } +gloo = "0.8" indexmap = { version = "1", features = ["std"] } js-sys = "0.3" slab = "0.4" From 31480c725bba6e2ce39439970ae7016964122a58 Mon Sep 17 00:00:00 2001 From: Kaede Hoshikawa Date: Thu, 21 Jul 2022 21:14:00 +0900 Subject: [PATCH 11/12] Oops. --- packages/yew/src/dom_bundle/bcomp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/yew/src/dom_bundle/bcomp.rs b/packages/yew/src/dom_bundle/bcomp.rs index 3fcae3106a8..1d3ab11c202 100644 --- a/packages/yew/src/dom_bundle/bcomp.rs +++ b/packages/yew/src/dom_bundle/bcomp.rs @@ -170,7 +170,7 @@ mod tests { use web_sys::Element; use super::*; - use crate::dom_bundle::{eeconcilable, ReconcileTarget}; + use crate::dom_bundle::{Reconcilable, ReconcileTarget}; use crate::virtual_dom::{Key, VChild, VNode}; use crate::{html, scheduler, Children, Component, Context, Html, NodeRef, Properties}; From 4f1973cd460ce8601889ab83eb1b09d7ef2bd67d Mon Sep 17 00:00:00 2001 From: Kaede Hoshikawa Date: Thu, 21 Jul 2022 22:28:23 +0900 Subject: [PATCH 12/12] Prevent Excessive Polling. --- .../yew/src/platform/rt_wasm_bindgen/time.rs | 57 ++++++++++++------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/packages/yew/src/platform/rt_wasm_bindgen/time.rs b/packages/yew/src/platform/rt_wasm_bindgen/time.rs index 99206d354af..c34dea6099c 100644 --- a/packages/yew/src/platform/rt_wasm_bindgen/time.rs +++ b/packages/yew/src/platform/rt_wasm_bindgen/time.rs @@ -1,53 +1,68 @@ +use std::cell::Cell; use std::future::Future; use std::pin::Pin; +use std::rc::Rc; use std::task::{Context, Poll}; use std::time::Duration; use futures::stream; use futures::stream::Stream; use gloo::timers::callback::Timeout; -use wasm_bindgen::UnwrapThrowExt; #[inline(always)] pub(crate) fn sleep(dur: Duration) -> impl Future { pub struct Sleep { inner: Option, - dur_millis: Option, + dur_left: Option, + timeout_registered: Rc>, } impl Future for Sleep { type Output = (); fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - // set_timeout can only accept maximum of i32, so we wrap around if it gets longer. static I32_MAX_U128: u128 = 2_147_483_647; static I32_MAX_U32: u32 = 2_147_483_647; - match self.dur_millis.as_mut() { - Some(m) if *m > I32_MAX_U128 => { - *m -= I32_MAX_U128; - let waker = cx.waker().clone(); - self.inner = Some(Timeout::new(I32_MAX_U32, move || { - waker.wake(); - })); - Poll::Pending + // If polling before the registered timeout is reached, return Pending. + if self.timeout_registered.get() { + return Poll::Pending; + } + + // set_timeout can only accept maximum of i32, so we wrap around if it gets longer. + let next_timeout = match self.dur_left.map(|m| (m, u32::try_from(m))) { + Some((m_u128, Err(_))) => { + self.dur_left = Some(m_u128 - I32_MAX_U128); + I32_MAX_U32 } - Some(m) => { - let waker = cx.waker().clone(); - self.inner = Some(Timeout::new((*m).try_into().unwrap_throw(), move || { - waker.wake(); - })); - self.dur_millis = None; - Poll::Pending + Some((m_u128, _)) if m_u128 > I32_MAX_U128 => { + self.dur_left = Some(m_u128 - I32_MAX_U128); + I32_MAX_U32 } - None => Poll::Ready(()), - } + Some((_, Ok(m_u32))) => { + self.dur_left = None; + m_u32 + } + None => return Poll::Ready(()), + }; + + let waker = cx.waker().clone(); + self.timeout_registered.set(true); + let timeout_registered = self.timeout_registered.clone(); + + self.inner = Some(Timeout::new(next_timeout, move || { + timeout_registered.set(false); + waker.wake(); + })); + + Poll::Pending } } Sleep { inner: None, - dur_millis: Some(dur.as_millis()), + dur_left: Some(dur.as_millis()), + timeout_registered: Cell::new(false).into(), } }