diff --git a/Cargo.lock b/Cargo.lock index c5e9443f4e..2b4efc1c57 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2592,6 +2592,7 @@ dependencies = [ "iced_core", "iced_futures", "raw-window-handle 0.6.2", + "sipper", "thiserror 1.0.69", ] @@ -5227,6 +5228,15 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" +[[package]] +name = "sipper" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d936de9741a68cb9452b683ffcc1fce44be7a79446ac5918319a42738da2d165" +dependencies = [ + "futures", +] + [[package]] name = "skrifa" version = "0.22.3" diff --git a/Cargo.toml b/Cargo.toml index c95fbd1e78..021ac4d436 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -172,6 +172,7 @@ raw-window-handle = "0.6" resvg = "0.42" rustc-hash = "2.0" sha2 = "0.10" +sipper = "0.0.4" smol = "1.0" smol_str = "0.2" softbuffer = "0.4" diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 703c3ed955..fc212ef81f 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -23,5 +23,6 @@ iced_core.workspace = true iced_futures.workspace = true iced_futures.features = ["thread-pool"] -thiserror.workspace = true raw-window-handle.workspace = true +sipper.workspace = true +thiserror.workspace = true diff --git a/runtime/src/task.rs b/runtime/src/task.rs index 22cfb63e4e..6af4aa20ee 100644 --- a/runtime/src/task.rs +++ b/runtime/src/task.rs @@ -3,7 +3,6 @@ use crate::core::widget; use crate::futures::futures::channel::mpsc; use crate::futures::futures::channel::oneshot; use crate::futures::futures::future::{self, FutureExt}; -use crate::futures::futures::never::Never; use crate::futures::futures::stream::{self, Stream, StreamExt}; use crate::futures::{boxed_stream, BoxStream, MaybeSend}; use crate::Action; @@ -11,6 +10,9 @@ use crate::Action; use std::future::Future; use std::sync::Arc; +#[doc(no_inline)] +pub use sipper::{sipper, stream, Never, Sender, Sipper, Straw}; + /// A set of concurrent actions to be performed by the iced runtime. /// /// A [`Task`] _may_ produce a bunch of values of type `T`. @@ -57,6 +59,25 @@ impl Task { Self::stream(stream.map(f)) } + /// Creates a [`Task`] that runs the given [`Sipper`] to completion, mapping + /// progress with the first closure and the output with the second one. + pub fn sip( + sipper: S, + on_progress: impl Fn(Progress) -> T + MaybeSend + 'static, + on_output: impl FnOnce(Output) -> T + MaybeSend + 'static, + ) -> Self + where + S: Sipper + MaybeSend + 'static, + S::Future: MaybeSend + 'static, + Output: MaybeSend, + Progress: MaybeSend, + T: MaybeSend + 'static, + { + Self::stream(stream(sipper::sipper(move |sender| async move { + on_output(sipper.map(on_progress).run(sender).await) + }))) + } + /// Combines the given tasks and produces a single [`Task`] that will run all of them /// in parallel. pub fn batch(tasks: impl IntoIterator) -> Self