From baadcc150f54012668f5484f5fbe8dd2516ebb10 Mon Sep 17 00:00:00 2001 From: edwloef Date: Thu, 13 Mar 2025 23:12:44 +0100 Subject: [PATCH 1/6] don't use futures-executor when it's not the default executor --- Cargo.lock | 1 + Cargo.toml | 6 ++++-- examples/integration/Cargo.toml | 3 +++ futures/src/backend/native/async_std.rs | 4 ++++ futures/src/backend/native/smol.rs | 4 ++++ futures/src/backend/native/thread_pool.rs | 4 ++++ futures/src/backend/native/tokio.rs | 7 +++++++ futures/src/backend/null.rs | 6 ++++++ futures/src/backend/wasm/wasm_bindgen.rs | 4 ++++ futures/src/executor.rs | 3 +++ runtime/Cargo.toml | 1 - winit/src/program.rs | 10 +--------- 12 files changed, 41 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9606b9a6..ae3436ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2777,6 +2777,7 @@ version = "0.1.0" dependencies = [ "console_error_panic_hook", "console_log", + "futures", "iced_wgpu", "iced_widget", "iced_winit", diff --git a/Cargo.toml b/Cargo.toml index c5e8f865..f5527e53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ all-features = true maintenance = { status = "actively-developed" } [features] -default = ["wgpu", "tiny-skia", "auto-detect-theme"] +default = ["wgpu", "tiny-skia", "auto-detect-theme", "futures-executor"] # Enables the `wgpu` GPU-accelerated renderer backend wgpu = ["iced_renderer/wgpu", "iced_widget/wgpu"] # Enables the `tiny-skia` software renderer backend @@ -43,6 +43,8 @@ markdown = ["iced_widget/markdown"] lazy = ["iced_widget/lazy"] # Enables a debug view in native platforms (press F12) debug = ["iced_winit/debug"] +# Enables `futures-executor` as the `executor::Default` on native platforms +futures-executor = ["iced_futures/thread-pool"] # Enables `tokio` as the `executor::Default` on native platforms tokio = ["iced_futures/tokio"] # Enables `async-std` as the `executor::Default` on native platforms @@ -150,7 +152,7 @@ bytemuck = { version = "1.0", features = ["derive"] } bytes = "1.6" cosmic-text = "0.13" dark-light = "2.0" -futures = "0.3" +futures = { version = "0.3", default-features = false, features = ["std", "async-await"] } glam = "0.25" cryoglyph = { git = "https://github.com/iced-rs/cryoglyph.git", rev = "be2defe4a13fd7c97c6f4c81e8e085463eb578dc" } guillotiere = "0.6" diff --git a/examples/integration/Cargo.toml b/examples/integration/Cargo.toml index 3bdf9408..2b5f99e4 100644 --- a/examples/integration/Cargo.toml +++ b/examples/integration/Cargo.toml @@ -12,6 +12,9 @@ iced_wgpu.workspace = true iced_widget.workspace = true iced_widget.features = ["wgpu"] +futures.workspace = true +futures.features = ["thread-pool"] + [target.'cfg(not(target_arch = "wasm32"))'.dependencies] tracing-subscriber = "0.3" diff --git a/futures/src/backend/native/async_std.rs b/futures/src/backend/native/async_std.rs index be258b26..9acafd9c 100644 --- a/futures/src/backend/native/async_std.rs +++ b/futures/src/backend/native/async_std.rs @@ -13,6 +13,10 @@ impl crate::Executor for Executor { fn spawn(&self, future: impl Future + Send + 'static) { let _ = async_std::task::spawn(future); } + + fn block_on(future: impl Future + 'static) { + async_std::task::block_on(future); + } } pub mod time { diff --git a/futures/src/backend/native/smol.rs b/futures/src/backend/native/smol.rs index 9ac6a27d..27998e8f 100644 --- a/futures/src/backend/native/smol.rs +++ b/futures/src/backend/native/smol.rs @@ -12,6 +12,10 @@ impl crate::Executor for Executor { fn spawn(&self, future: impl Future + Send + 'static) { smol::spawn(future).detach(); } + + fn block_on(future: impl Future + 'static) { + smol::block_on(future); + } } pub mod time { diff --git a/futures/src/backend/native/thread_pool.rs b/futures/src/backend/native/thread_pool.rs index a90cc53a..92004bc7 100644 --- a/futures/src/backend/native/thread_pool.rs +++ b/futures/src/backend/native/thread_pool.rs @@ -11,6 +11,10 @@ impl crate::Executor for Executor { fn spawn(&self, future: impl Future + Send + 'static) { self.spawn_ok(future); } + + fn block_on(future: impl Future + 'static) { + futures::executor::block_on(future); + } } pub mod time { diff --git a/futures/src/backend/native/tokio.rs b/futures/src/backend/native/tokio.rs index 911d788c..0670c5ee 100644 --- a/futures/src/backend/native/tokio.rs +++ b/futures/src/backend/native/tokio.rs @@ -17,6 +17,13 @@ impl crate::Executor for Executor { let _guard = tokio::runtime::Runtime::enter(self); f() } + + fn block_on(future: impl Future + 'static) { + tokio::runtime::Builder::new_current_thread() + .build() + .unwrap() + .block_on(future); + } } pub mod time { diff --git a/futures/src/backend/null.rs b/futures/src/backend/null.rs index f31415b9..151d5587 100644 --- a/futures/src/backend/null.rs +++ b/futures/src/backend/null.rs @@ -14,6 +14,12 @@ impl crate::Executor for Executor { #[cfg(target_arch = "wasm32")] fn spawn(&self, _future: impl Future + 'static) {} + + #[cfg(not(target_arch = "wasm32"))] + fn block_on(_future: impl Future + 'static) {} + + #[cfg(target_arch = "wasm32")] + fn block_on(_future: impl Future + 'static) {} } pub mod time { diff --git a/futures/src/backend/wasm/wasm_bindgen.rs b/futures/src/backend/wasm/wasm_bindgen.rs index 4811e7f4..667bf2fa 100644 --- a/futures/src/backend/wasm/wasm_bindgen.rs +++ b/futures/src/backend/wasm/wasm_bindgen.rs @@ -12,6 +12,10 @@ impl crate::Executor for Executor { fn spawn(&self, future: impl futures::Future + 'static) { wasm_bindgen_futures::spawn_local(future); } + + fn block_on(future: impl futures::Future + 'static) { + wasm_bindgen_futures::spawn_local(future); + } } pub mod time { diff --git a/futures/src/executor.rs b/futures/src/executor.rs index 9c14a2c9..22ed4212 100644 --- a/futures/src/executor.rs +++ b/futures/src/executor.rs @@ -20,4 +20,7 @@ pub trait Executor: Sized { fn enter(&self, f: impl FnOnce() -> R) -> R { f() } + + /// Runs the future on the current thread, blocking it until it is completed. + fn block_on(future: impl Future + 'static); } diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index fc212ef8..35704e0f 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -21,7 +21,6 @@ multi-window = [] bytes.workspace = true iced_core.workspace = true iced_futures.workspace = true -iced_futures.features = ["thread-pool"] raw-window-handle.workspace = true sipper.workspace = true diff --git a/winit/src/program.rs b/winit/src/program.rs index 6904c02a..ee921adb 100644 --- a/winit/src/program.rs +++ b/winit/src/program.rs @@ -662,15 +662,7 @@ async fn run_instance( } }; - #[cfg(not(target_arch = "wasm32"))] - crate::futures::futures::executor::block_on( - create_compositor, - ); - - #[cfg(target_arch = "wasm32")] - { - wasm_bindgen_futures::spawn_local(create_compositor); - } + P::Executor::block_on(create_compositor); continue; } From 57cb14ce38360a885c2fb7e5d1e7a52797b7e73f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 2 Apr 2025 10:39:27 +0200 Subject: [PATCH 2/6] Remove `Executor::block_on` and simplify `Compositor` creation --- Cargo.toml | 8 +-- futures/Cargo.toml | 2 + futures/src/backend/native/async_std.rs | 4 -- futures/src/backend/native/smol.rs | 4 -- futures/src/backend/native/thread_pool.rs | 4 -- futures/src/backend/native/tokio.rs | 7 -- futures/src/backend/null.rs | 13 +--- futures/src/backend/wasm/wasm_bindgen.rs | 4 -- futures/src/executor.rs | 3 - futures/src/runtime.rs | 20 ++---- graphics/src/compositor.rs | 6 +- src/lib.rs | 7 ++ winit/src/program.rs | 84 ++++++++++------------- 13 files changed, 58 insertions(+), 108 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f5527e53..5df2f12b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ all-features = true maintenance = { status = "actively-developed" } [features] -default = ["wgpu", "tiny-skia", "auto-detect-theme", "futures-executor"] +default = ["wgpu", "tiny-skia", "auto-detect-theme", "thread-pool"] # Enables the `wgpu` GPU-accelerated renderer backend wgpu = ["iced_renderer/wgpu", "iced_widget/wgpu"] # Enables the `tiny-skia` software renderer backend @@ -43,8 +43,8 @@ markdown = ["iced_widget/markdown"] lazy = ["iced_widget/lazy"] # Enables a debug view in native platforms (press F12) debug = ["iced_winit/debug"] -# Enables `futures-executor` as the `executor::Default` on native platforms -futures-executor = ["iced_futures/thread-pool"] +# Enables the `thread-pool` futures executor as the `executor::Default` on native platforms +thread-pool = ["iced_futures/thread-pool"] # Enables `tokio` as the `executor::Default` on native platforms tokio = ["iced_futures/tokio"] # Enables `async-std` as the `executor::Default` on native platforms @@ -152,7 +152,7 @@ bytemuck = { version = "1.0", features = ["derive"] } bytes = "1.6" cosmic-text = "0.13" dark-light = "2.0" -futures = { version = "0.3", default-features = false, features = ["std", "async-await"] } +futures = { version = "0.3", default-features = false } glam = "0.25" cryoglyph = { git = "https://github.com/iced-rs/cryoglyph.git", rev = "be2defe4a13fd7c97c6f4c81e8e085463eb578dc" } guillotiere = "0.6" diff --git a/futures/Cargo.toml b/futures/Cargo.toml index 3984ce83..6a49e9e8 100644 --- a/futures/Cargo.toml +++ b/futures/Cargo.toml @@ -24,6 +24,8 @@ thread-pool = ["futures/thread-pool"] iced_core.workspace = true futures.workspace = true +futures.features = ["std"] + log.workspace = true rustc-hash.workspace = true diff --git a/futures/src/backend/native/async_std.rs b/futures/src/backend/native/async_std.rs index 9acafd9c..be258b26 100644 --- a/futures/src/backend/native/async_std.rs +++ b/futures/src/backend/native/async_std.rs @@ -13,10 +13,6 @@ impl crate::Executor for Executor { fn spawn(&self, future: impl Future + Send + 'static) { let _ = async_std::task::spawn(future); } - - fn block_on(future: impl Future + 'static) { - async_std::task::block_on(future); - } } pub mod time { diff --git a/futures/src/backend/native/smol.rs b/futures/src/backend/native/smol.rs index 27998e8f..9ac6a27d 100644 --- a/futures/src/backend/native/smol.rs +++ b/futures/src/backend/native/smol.rs @@ -12,10 +12,6 @@ impl crate::Executor for Executor { fn spawn(&self, future: impl Future + Send + 'static) { smol::spawn(future).detach(); } - - fn block_on(future: impl Future + 'static) { - smol::block_on(future); - } } pub mod time { diff --git a/futures/src/backend/native/thread_pool.rs b/futures/src/backend/native/thread_pool.rs index 92004bc7..a90cc53a 100644 --- a/futures/src/backend/native/thread_pool.rs +++ b/futures/src/backend/native/thread_pool.rs @@ -11,10 +11,6 @@ impl crate::Executor for Executor { fn spawn(&self, future: impl Future + Send + 'static) { self.spawn_ok(future); } - - fn block_on(future: impl Future + 'static) { - futures::executor::block_on(future); - } } pub mod time { diff --git a/futures/src/backend/native/tokio.rs b/futures/src/backend/native/tokio.rs index 0670c5ee..911d788c 100644 --- a/futures/src/backend/native/tokio.rs +++ b/futures/src/backend/native/tokio.rs @@ -17,13 +17,6 @@ impl crate::Executor for Executor { let _guard = tokio::runtime::Runtime::enter(self); f() } - - fn block_on(future: impl Future + 'static) { - tokio::runtime::Builder::new_current_thread() - .build() - .unwrap() - .block_on(future); - } } pub mod time { diff --git a/futures/src/backend/null.rs b/futures/src/backend/null.rs index 151d5587..59b740e3 100644 --- a/futures/src/backend/null.rs +++ b/futures/src/backend/null.rs @@ -1,4 +1,5 @@ //! A backend that does nothing! +use crate::MaybeSend; /// An executor that drops all the futures, instead of spawning them. #[derive(Debug)] @@ -9,17 +10,7 @@ impl crate::Executor for Executor { Ok(Self) } - #[cfg(not(target_arch = "wasm32"))] - fn spawn(&self, _future: impl Future + Send + 'static) {} - - #[cfg(target_arch = "wasm32")] - fn spawn(&self, _future: impl Future + 'static) {} - - #[cfg(not(target_arch = "wasm32"))] - fn block_on(_future: impl Future + 'static) {} - - #[cfg(target_arch = "wasm32")] - fn block_on(_future: impl Future + 'static) {} + fn spawn(&self, _future: impl Future + MaybeSend + 'static) {} } pub mod time { diff --git a/futures/src/backend/wasm/wasm_bindgen.rs b/futures/src/backend/wasm/wasm_bindgen.rs index 667bf2fa..4811e7f4 100644 --- a/futures/src/backend/wasm/wasm_bindgen.rs +++ b/futures/src/backend/wasm/wasm_bindgen.rs @@ -12,10 +12,6 @@ impl crate::Executor for Executor { fn spawn(&self, future: impl futures::Future + 'static) { wasm_bindgen_futures::spawn_local(future); } - - fn block_on(future: impl futures::Future + 'static) { - wasm_bindgen_futures::spawn_local(future); - } } pub mod time { diff --git a/futures/src/executor.rs b/futures/src/executor.rs index 22ed4212..9c14a2c9 100644 --- a/futures/src/executor.rs +++ b/futures/src/executor.rs @@ -20,7 +20,4 @@ pub trait Executor: Sized { fn enter(&self, f: impl FnOnce() -> R) -> R { f() } - - /// Runs the future on the current thread, blocking it until it is completed. - fn block_on(future: impl Future + 'static); } diff --git a/futures/src/runtime.rs b/futures/src/runtime.rs index 0f30b469..72252458 100644 --- a/futures/src/runtime.rs +++ b/futures/src/runtime.rs @@ -1,6 +1,6 @@ //! Run commands and keep track of subscriptions. use crate::subscription; -use crate::{BoxFuture, BoxStream, Executor, MaybeSend}; +use crate::{BoxStream, Executor, MaybeSend}; use futures::{Sink, channel::mpsc}; use std::marker::PhantomData; @@ -51,20 +51,10 @@ where } /// Spawns a [`Future`] in the [`Runtime`]. - /// - /// The resulting `Message` will be forwarded to the `Sender` of the - /// [`Runtime`]. - /// - /// [`Future`]: BoxFuture - pub fn spawn(&mut self, future: BoxFuture) { - use futures::{FutureExt, SinkExt}; - - let mut sender = self.sender.clone(); - - let future = future.then(|message| async move { - let _ = sender.send(message).await; - }); - + pub fn spawn( + &mut self, + future: impl Future + MaybeSend + 'static, + ) { self.executor.spawn(future); } diff --git a/graphics/src/compositor.rs b/graphics/src/compositor.rs index e9063678..f0f67607 100644 --- a/graphics/src/compositor.rs +++ b/graphics/src/compositor.rs @@ -10,7 +10,7 @@ use thiserror::Error; use std::borrow::Cow; /// A graphics compositor that can draw to windows. -pub trait Compositor: Sized { +pub trait Compositor: Sized + MaybeSend { /// The iced renderer of the backend. type Renderer; @@ -21,7 +21,7 @@ pub trait Compositor: Sized { fn new( settings: Settings, compatible_window: W, - ) -> impl Future> { + ) -> impl Future> + MaybeSend { Self::with_backend(settings, compatible_window, None) } @@ -33,7 +33,7 @@ pub trait Compositor: Sized { _settings: Settings, _compatible_window: W, _backend: Option<&str>, - ) -> impl Future>; + ) -> impl Future> + MaybeSend; /// Creates a [`Self::Renderer`] for the [`Compositor`]. fn create_renderer(&self) -> Self::Renderer; diff --git a/src/lib.rs b/src/lib.rs index 95820ed7..9b3f3788 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -480,6 +480,13 @@ use iced_winit::runtime; pub use iced_futures::futures; pub use iced_futures::stream; +#[cfg(not(any(feature = "thread-pool", feature = "tokio", feature = "smol")))] +compile_error!( + "No futures executor has been enabled! You must enable an + executor feature.\n + Available options: thread-pool, tokio, smol, or async-std." +); + #[cfg(feature = "highlighter")] pub use iced_highlighter as highlighter; diff --git a/winit/src/program.rs b/winit/src/program.rs index ee921adb..77b4f9d7 100644 --- a/winit/src/program.rs +++ b/winit/src/program.rs @@ -18,7 +18,7 @@ use crate::futures::futures::channel::oneshot; use crate::futures::futures::task; use crate::futures::futures::{Future, StreamExt}; use crate::futures::subscription::{self, Subscription}; -use crate::futures::{Executor, Runtime}; +use crate::futures::{Executor, MaybeSend, Runtime}; use crate::graphics; use crate::graphics::{Compositor, compositor}; use crate::runtime::Debug; @@ -149,7 +149,7 @@ pub fn run( ) -> Result<(), Error> where P: Program + 'static, - C: Compositor + 'static, + C: Compositor + MaybeSend + 'static, P::Theme: theme::Base, { use winit::event_loop::EventLoop; @@ -494,9 +494,7 @@ where event_loop.exit(); } }, - _ => { - break; - } + _ => break, }, task::Poll::Ready(_) => { event_loop.exit(); @@ -562,7 +560,7 @@ async fn run_instance( default_fonts: Vec>, ) where P: Program + 'static, - C: Compositor + 'static, + C: Compositor + MaybeSend + 'static, P::Theme: theme::Base, { use winit::event; @@ -579,35 +577,11 @@ async fn run_instance( let mut ui_caches = FxHashMap::default(); let mut user_interfaces = ManuallyDrop::new(FxHashMap::default()); let mut clipboard = Clipboard::unconnected(); - let mut compositor_receiver: Option> = None; debug.startup_finished(); loop { - let event = if compositor_receiver.is_some() { - let compositor_receiver = - compositor_receiver.take().expect("Waiting for compositor"); - - match compositor_receiver.await { - Ok(Ok((new_compositor, event))) => { - compositor = Some(new_compositor); - - Some(event) - } - Ok(Err(error)) => { - control_sender - .start_send(Control::Crash( - Error::GraphicsCreationFailed(error), - )) - .expect("Send control action"); - break; - } - Err(error) => { - panic!("Compositor initialization failed: {error}") - } - } - // Empty the queue if possible - } else if let Ok(event) = event_receiver.try_next() { + let event = if let Ok(event) = event_receiver.try_next() { event } else { event_receiver.next().await @@ -626,17 +600,17 @@ async fn run_instance( on_open, } => { if compositor.is_none() { - let (compositor_sender, new_compositor_receiver) = + let (compositor_sender, compositor_receiver) = oneshot::channel(); - compositor_receiver = Some(new_compositor_receiver); - let create_compositor = { + let window = window.clone(); + let mut proxy = proxy.clone(); let default_fonts = default_fonts.clone(); async move { let mut compositor = - C::new(graphics_settings, window.clone()).await; + C::new(graphics_settings, window).await; if let Ok(compositor) = &mut compositor { for font in default_fonts { @@ -645,26 +619,38 @@ async fn run_instance( } compositor_sender - .send(compositor.map(|compositor| { - ( - compositor, - Event::WindowCreated { - id, - window, - exit_on_close_request, - make_visible, - on_open, - }, - ) - })) + .send(compositor) .ok() .expect("Send compositor"); + + // HACK! Send a proxy event on completion to trigger + // a runtime re-poll + // TODO: Send compositor through proxy (?) + { + let (sender, _receiver) = oneshot::channel(); + + proxy.send_action(Action::Window( + runtime::window::Action::GetLatest(sender), + )); + } } }; - P::Executor::block_on(create_compositor); + runtime.spawn(create_compositor); - continue; + match compositor_receiver + .await + .expect("Wait for compositor") + { + Ok(new_compositor) => { + compositor = Some(new_compositor); + } + Err(error) => { + let _ = control_sender + .start_send(Control::Crash(error.into())); + break; + } + } } let window = window_manager.insert( From 91996372cb6bcf686f004ae5b313a28cc2e91ecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 2 Apr 2025 10:45:27 +0200 Subject: [PATCH 3/6] Remove `async-std` support (RIP) --- Cargo.lock | 4 +- Cargo.toml | 3 -- examples/todos/Cargo.toml | 4 +- examples/todos/src/main.rs | 27 +++--------- futures/Cargo.toml | 4 -- futures/src/backend/default.rs | 16 ++----- futures/src/backend/native.rs | 3 -- futures/src/backend/native/async_std.rs | 56 ------------------------- 8 files changed, 13 insertions(+), 104 deletions(-) delete mode 100644 futures/src/backend/native/async_std.rs diff --git a/Cargo.lock b/Cargo.lock index ae3436ca..dbcd5060 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -378,7 +378,6 @@ dependencies = [ "async-global-executor", "async-io", "async-lock", - "async-process", "crossbeam-utils", "futures-channel", "futures-core", @@ -2434,7 +2433,6 @@ dependencies = [ name = "iced_futures" version = "0.14.0-dev" dependencies = [ - "async-std", "futures", "iced_core", "log", @@ -5744,12 +5742,12 @@ dependencies = [ name = "todos" version = "0.1.0" dependencies = [ - "async-std", "directories", "iced", "iced_test", "serde", "serde_json", + "tokio", "tracing-subscriber", "uuid", "wasmtimer", diff --git a/Cargo.toml b/Cargo.toml index 5df2f12b..f7318b98 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,8 +47,6 @@ debug = ["iced_winit/debug"] thread-pool = ["iced_futures/thread-pool"] # Enables `tokio` as the `executor::Default` on native platforms tokio = ["iced_futures/tokio"] -# Enables `async-std` as the `executor::Default` on native platforms -async-std = ["iced_futures/async-std"] # Enables `smol` as the `executor::Default` on native platforms smol = ["iced_futures/smol"] # Enables querying system information @@ -146,7 +144,6 @@ iced_wgpu = { version = "0.14.0-dev", path = "wgpu" } iced_widget = { version = "0.14.0-dev", path = "widget" } iced_winit = { version = "0.14.0-dev", path = "winit" } -async-std = "1.0" bitflags = "2.0" bytemuck = { version = "1.0", features = ["derive"] } bytes = "1.6" diff --git a/examples/todos/Cargo.toml b/examples/todos/Cargo.toml index 77b776d5..981b9e5f 100644 --- a/examples/todos/Cargo.toml +++ b/examples/todos/Cargo.toml @@ -7,14 +7,14 @@ publish = false [dependencies] iced.workspace = true -iced.features = ["async-std", "debug"] +iced.features = ["tokio", "debug"] serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" uuid = { version = "1.0", features = ["v4", "fast-rng", "serde"] } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -async-std.workspace = true +tokio.workspace = true directories = "6.0" tracing-subscriber = "0.3" diff --git a/examples/todos/src/main.rs b/examples/todos/src/main.rs index 65a34c64..03e62d3c 100644 --- a/examples/todos/src/main.rs +++ b/examples/todos/src/main.rs @@ -482,7 +482,6 @@ enum LoadError { #[derive(Debug, Clone)] enum SaveError { - File, Write, Format, } @@ -504,15 +503,7 @@ impl SavedState { } async fn load() -> Result { - use async_std::prelude::*; - - let mut contents = String::new(); - - let mut file = async_std::fs::File::open(Self::path()) - .await - .map_err(|_| LoadError::File)?; - - file.read_to_string(&mut contents) + let contents = tokio::fs::read_to_string(Self::path()) .await .map_err(|_| LoadError::File)?; @@ -520,31 +511,25 @@ impl SavedState { } async fn save(self) -> Result<(), SaveError> { - use async_std::prelude::*; - let json = serde_json::to_string_pretty(&self) .map_err(|_| SaveError::Format)?; let path = Self::path(); if let Some(dir) = path.parent() { - async_std::fs::create_dir_all(dir) + tokio::fs::create_dir_all(dir) .await - .map_err(|_| SaveError::File)?; + .map_err(|_| SaveError::Write)?; } { - let mut file = async_std::fs::File::create(path) - .await - .map_err(|_| SaveError::File)?; - - file.write_all(json.as_bytes()) + tokio::fs::write(path, json.as_bytes()) .await .map_err(|_| SaveError::Write)?; } // This is a simple way to save at most once every couple seconds - async_std::task::sleep(std::time::Duration::from_secs(2)).await; + tokio::time::sleep(std::time::Duration::from_secs(2)).await; Ok(()) } @@ -570,7 +555,7 @@ impl SavedState { } async fn save(self) -> Result<(), SaveError> { - let storage = Self::storage().ok_or(SaveError::File)?; + let storage = Self::storage().ok_or(SaveError::Write)?; let json = serde_json::to_string_pretty(&self) .map_err(|_| SaveError::Format)?; diff --git a/futures/Cargo.toml b/futures/Cargo.toml index 6a49e9e8..e2c342ff 100644 --- a/futures/Cargo.toml +++ b/futures/Cargo.toml @@ -30,10 +30,6 @@ log.workspace = true rustc-hash.workspace = true [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -async-std.workspace = true -async-std.optional = true -async-std.features = ["unstable"] - smol.workspace = true smol.optional = true diff --git a/futures/src/backend/default.rs b/futures/src/backend/default.rs index 842b5927..4418834e 100644 --- a/futures/src/backend/default.rs +++ b/futures/src/backend/default.rs @@ -2,10 +2,9 @@ //! //! - On native platforms, it will use: //! - `backend::native::tokio` when the `tokio` feature is enabled. -//! - `backend::native::async-std` when the `async-std` feature is -//! enabled. //! - `backend::native::smol` when the `smol` feature is enabled. -//! - `backend::native::thread_pool` otherwise. +//! - `backend::native::thread_pool` when the `thread-pool` feature is enabled. +//! - `backend::null` otherwise. //! //! - On Wasm, it will use `backend::wasm::wasm_bindgen`. #[cfg(not(target_arch = "wasm32"))] @@ -13,24 +12,17 @@ mod platform { #[cfg(feature = "tokio")] pub use crate::backend::native::tokio::*; - #[cfg(all(feature = "async-std", not(feature = "tokio"),))] - pub use crate::backend::native::async_std::*; - - #[cfg(all( - feature = "smol", - not(any(feature = "tokio", feature = "async-std")), - ))] + #[cfg(all(feature = "smol", not(feature = "tokio"),))] pub use crate::backend::native::smol::*; #[cfg(all( feature = "thread-pool", - not(any(feature = "tokio", feature = "async-std", feature = "smol")) + not(any(feature = "tokio", feature = "smol")) ))] pub use crate::backend::native::thread_pool::*; #[cfg(not(any( feature = "tokio", - feature = "async-std", feature = "smol", feature = "thread-pool" )))] diff --git a/futures/src/backend/native.rs b/futures/src/backend/native.rs index 85af2c88..e5595bdb 100644 --- a/futures/src/backend/native.rs +++ b/futures/src/backend/native.rs @@ -2,9 +2,6 @@ #[cfg(feature = "tokio")] pub mod tokio; -#[cfg(feature = "async-std")] -pub mod async_std; - #[cfg(feature = "smol")] pub mod smol; diff --git a/futures/src/backend/native/async_std.rs b/futures/src/backend/native/async_std.rs deleted file mode 100644 index be258b26..00000000 --- a/futures/src/backend/native/async_std.rs +++ /dev/null @@ -1,56 +0,0 @@ -//! An `async-std` backend. - -/// An `async-std` executor. -#[derive(Debug)] -pub struct Executor; - -impl crate::Executor for Executor { - fn new() -> Result { - Ok(Self) - } - - #[allow(clippy::let_underscore_future)] - fn spawn(&self, future: impl Future + Send + 'static) { - let _ = async_std::task::spawn(future); - } -} - -pub mod time { - //! Listen and react to time. - use crate::subscription::{self, Hasher, Subscription}; - - /// Returns a [`Subscription`] that produces messages at a set interval. - /// - /// The first message is produced after a `duration`, and then continues to - /// produce more messages every `duration` after that. - pub fn every( - duration: std::time::Duration, - ) -> Subscription { - subscription::from_recipe(Every(duration)) - } - - #[derive(Debug)] - struct Every(std::time::Duration); - - impl subscription::Recipe for Every { - type Output = std::time::Instant; - - fn hash(&self, state: &mut Hasher) { - use std::hash::Hash; - - std::any::TypeId::of::().hash(state); - self.0.hash(state); - } - - fn stream( - self: Box, - _input: subscription::EventStream, - ) -> futures::stream::BoxStream<'static, Self::Output> { - use futures::stream::StreamExt; - - async_std::stream::interval(self.0) - .map(|_| std::time::Instant::now()) - .boxed() - } - } -} From cf827dd349f28bdab82f71c0d33791d67480c0f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 2 Apr 2025 10:46:25 +0200 Subject: [PATCH 4/6] Allow disabling all executor features on Wasm builds --- src/lib.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 9b3f3788..2d4b6b69 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -480,7 +480,12 @@ use iced_winit::runtime; pub use iced_futures::futures; pub use iced_futures::stream; -#[cfg(not(any(feature = "thread-pool", feature = "tokio", feature = "smol")))] +#[cfg(not(any( + target_arch = "wasm32", + feature = "thread-pool", + feature = "tokio", + feature = "smol" +)))] compile_error!( "No futures executor has been enabled! You must enable an executor feature.\n From 9f1beba5839fad7fa8fe22f37774e0ea900b87e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 2 Apr 2025 10:58:09 +0200 Subject: [PATCH 5/6] Make `sipper` dependency optional --- Cargo.lock | 1 + Cargo.toml | 3 +++ examples/download_progress/Cargo.toml | 2 +- examples/gallery/Cargo.toml | 2 +- examples/websocket/Cargo.toml | 2 +- runtime/Cargo.toml | 4 +++- runtime/src/task.rs | 5 ++++- src/lib.rs | 7 ++++--- 8 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dbcd5060..efa3db2b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2405,6 +2405,7 @@ dependencies = [ "iced_futures", "iced_highlighter", "iced_renderer", + "iced_runtime", "iced_wgpu", "iced_widget", "iced_winit", diff --git a/Cargo.toml b/Cargo.toml index f7318b98..b13c26f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,11 +67,14 @@ auto-detect-theme = ["iced_core/auto-detect-theme"] strict-assertions = ["iced_renderer/strict-assertions"] # Redraws on every runtime event, and not only when a widget requests it unconditional-rendering = ["iced_winit/unconditional-rendering"] +# Enables support for the `sipper` library +sipper = ["iced_runtime/sipper"] [dependencies] iced_core.workspace = true iced_futures.workspace = true iced_renderer.workspace = true +iced_runtime.workspace = true iced_widget.workspace = true iced_winit.features = ["program"] iced_winit.workspace = true diff --git a/examples/download_progress/Cargo.toml b/examples/download_progress/Cargo.toml index 9c52b2bd..56c538fe 100644 --- a/examples/download_progress/Cargo.toml +++ b/examples/download_progress/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] iced.workspace = true -iced.features = ["tokio"] +iced.features = ["tokio", "sipper"] [dependencies.reqwest] version = "0.12" diff --git a/examples/gallery/Cargo.toml b/examples/gallery/Cargo.toml index 5161f368..3dd5d378 100644 --- a/examples/gallery/Cargo.toml +++ b/examples/gallery/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] iced.workspace = true -iced.features = ["tokio", "image", "web-colors", "debug"] +iced.features = ["tokio", "sipper", "image", "web-colors", "debug"] reqwest.version = "0.12" reqwest.features = ["json"] diff --git a/examples/websocket/Cargo.toml b/examples/websocket/Cargo.toml index 88ebdae1..c47e3c93 100644 --- a/examples/websocket/Cargo.toml +++ b/examples/websocket/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] iced.workspace = true -iced.features = ["debug", "tokio"] +iced.features = ["debug", "tokio", "sipper"] warp = "0.3" diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 35704e0f..5fc67b97 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -23,5 +23,7 @@ iced_core.workspace = true iced_futures.workspace = true raw-window-handle.workspace = true -sipper.workspace = true thiserror.workspace = true + +sipper.workspace = true +sipper.optional = true diff --git a/runtime/src/task.rs b/runtime/src/task.rs index fd5970ac..624fc3a7 100644 --- a/runtime/src/task.rs +++ b/runtime/src/task.rs @@ -7,8 +7,10 @@ use crate::futures::futures::future::{self, FutureExt}; use crate::futures::futures::stream::{self, Stream, StreamExt}; use crate::futures::{BoxStream, MaybeSend, boxed_stream}; +use std::convert::Infallible; use std::sync::Arc; +#[cfg(feature = "sipper")] #[doc(no_inline)] pub use sipper::{Never, Sender, Sipper, Straw, sipper, stream}; @@ -60,6 +62,7 @@ impl Task { /// Creates a [`Task`] that runs the given [`Sipper`] to completion, mapping /// progress with the first closure and the output with the second one. + #[cfg(feature = "sipper")] pub fn sip( sipper: S, on_progress: impl FnMut(S::Progress) -> T + MaybeSend + 'static, @@ -391,7 +394,7 @@ where } /// Creates a new [`Task`] that executes the given [`Action`] and produces no output. -pub fn effect(action: impl Into>) -> Task { +pub fn effect(action: impl Into>) -> Task { let action = action.into(); Task(Some(boxed_stream(stream::once(async move { diff --git a/src/lib.rs b/src/lib.rs index 2d4b6b69..ebb80282 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -531,9 +531,10 @@ pub use alignment::Vertical::{Bottom, Top}; pub mod task { //! Create runtime tasks. - pub use crate::runtime::task::{ - Handle, Never, Sipper, Straw, Task, sipper, stream, - }; + pub use crate::runtime::task::{Handle, Task}; + + #[cfg(feature = "sipper")] + pub use crate::runtime::task::{Never, Sipper, Straw, sipper, stream}; } pub mod clipboard { From 5b8d92ed5bcb0719ec7ba6d0f067bd669e6d226d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 2 Apr 2025 11:08:23 +0200 Subject: [PATCH 6/6] Remove leftover mentions of `async-std` --- src/lib.rs | 15 ++------------- src/time.rs | 1 - 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ebb80282..dd879bf6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -489,7 +489,7 @@ pub use iced_futures::stream; compile_error!( "No futures executor has been enabled! You must enable an executor feature.\n - Available options: thread-pool, tokio, smol, or async-std." + Available options: thread-pool, tokio, or smol." ); #[cfg(feature = "highlighter")] @@ -547,18 +547,7 @@ pub mod clipboard { pub mod executor { //! Choose your preferred executor to power your application. pub use iced_futures::Executor; - - /// A default cross-platform executor. - /// - /// - On native platforms, it will use: - /// - `iced_futures::backend::native::tokio` when the `tokio` feature is enabled. - /// - `iced_futures::backend::native::async-std` when the `async-std` feature is - /// enabled. - /// - `iced_futures::backend::native::smol` when the `smol` feature is enabled. - /// - `iced_futures::backend::native::thread_pool` otherwise. - /// - /// - On Wasm, it will use `iced_futures::backend::wasm::wasm_bindgen`. - pub type Default = iced_futures::backend::default::Executor; + pub use iced_futures::backend::default::Executor as Default; } pub mod font { diff --git a/src/time.rs b/src/time.rs index 98a800ac..f32eeb17 100644 --- a/src/time.rs +++ b/src/time.rs @@ -6,7 +6,6 @@ pub use crate::core::time::*; docsrs, doc(cfg(any( feature = "tokio", - feature = "async-std", feature = "smol", target_arch = "wasm32" )))