Write documentation for iced_futures
This commit is contained in:
parent
03da887339
commit
f14009601e
11 changed files with 131 additions and 20 deletions
|
|
@ -29,13 +29,26 @@ pub use wasm_bindgen::WasmBindgen;
|
|||
|
||||
use futures::Future;
|
||||
|
||||
/// A type that can run futures.
|
||||
pub trait Executor: Sized {
|
||||
/// Creates a new [`Executor`].
|
||||
///
|
||||
/// [`Executor`]: trait.Executor.html
|
||||
fn new() -> Result<Self, futures::io::Error>
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
/// Spawns a future in the [`Executor`].
|
||||
///
|
||||
/// [`Executor`]: trait.Executor.html
|
||||
fn spawn(&self, future: impl Future<Output = ()> + Send + 'static);
|
||||
|
||||
/// Runs the given closure inside the [`Executor`].
|
||||
///
|
||||
/// Some executors, like `tokio`, require some global state to be in place
|
||||
/// before creating futures. This method can be leveraged to set up this
|
||||
/// global state, call a function, restore the state, and obtain the result
|
||||
/// of the call.
|
||||
fn enter<R>(&self, f: impl FnOnce() -> R) -> R {
|
||||
f()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ use crate::Executor;
|
|||
|
||||
use futures::Future;
|
||||
|
||||
/// A type representing the `async-std` runtime.
|
||||
#[derive(Debug)]
|
||||
pub struct AsyncStd;
|
||||
|
||||
impl Executor for AsyncStd {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ use crate::Executor;
|
|||
|
||||
use futures::Future;
|
||||
|
||||
/// An executor that drops all the futures, instead of spawning them.
|
||||
#[derive(Debug)]
|
||||
pub struct Null;
|
||||
|
||||
impl Executor for Null {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use crate::Executor;
|
|||
|
||||
use futures::Future;
|
||||
|
||||
/// A thread pool for futures.
|
||||
pub type ThreadPool = futures::executor::ThreadPool;
|
||||
|
||||
impl Executor for futures::executor::ThreadPool {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use crate::Executor;
|
|||
|
||||
use futures::Future;
|
||||
|
||||
/// The `tokio` runtime.
|
||||
pub type Tokio = tokio::runtime::Runtime;
|
||||
|
||||
impl Executor for Tokio {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
//! Asynchronous tasks for GUI programming, inspired by Elm.
|
||||
#![deny(missing_docs)]
|
||||
#![deny(missing_debug_implementations)]
|
||||
#![deny(unused_results)]
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(rust_2018_idioms)]
|
||||
pub use futures;
|
||||
|
||||
mod command;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,15 @@ use crate::{subscription, Command, Executor, Subscription};
|
|||
use futures::Sink;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// A batteries-included runtime of commands and subscriptions.
|
||||
///
|
||||
/// If you have an [`Executor`], a [`Runtime`] can be leveraged to run any
|
||||
/// [`Command`] or [`Subscription`] and get notified of the results!
|
||||
///
|
||||
/// [`Runtime`]: struct.Runtime.html
|
||||
/// [`Executor`]: executor/trait.Executor.html
|
||||
/// [`Command`]: struct.Command.html
|
||||
/// [`Subscription`]: subscription/struct.Subscription.html
|
||||
#[derive(Debug)]
|
||||
pub struct Runtime<Hasher, Event, Executor, Sender, Message> {
|
||||
executor: Executor,
|
||||
|
|
@ -25,6 +34,13 @@ where
|
|||
+ 'static,
|
||||
Message: Send + 'static,
|
||||
{
|
||||
/// Creates a new empty [`Runtime`].
|
||||
///
|
||||
/// You need to provide:
|
||||
/// - an [`Executor`] to spawn futures
|
||||
/// - a `Sender` implementing `Sink` to receive the results
|
||||
///
|
||||
/// [`Runtime`]: struct.Runtime.html
|
||||
pub fn new(executor: Executor, sender: Sender) -> Self {
|
||||
Self {
|
||||
executor,
|
||||
|
|
@ -34,10 +50,24 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Runs the given closure inside the [`Executor`] of the [`Runtime`].
|
||||
///
|
||||
/// See [`Executor::enter`] to learn more.
|
||||
///
|
||||
/// [`Executor`]: executor/trait.Executor.html
|
||||
/// [`Runtime`]: struct.Runtime.html
|
||||
/// [`Executor::enter`]: executor/trait.Executor.html#method.enter
|
||||
pub fn enter<R>(&self, f: impl FnOnce() -> R) -> R {
|
||||
self.executor.enter(f)
|
||||
}
|
||||
|
||||
/// Spawns a [`Command`] in the [`Runtime`].
|
||||
///
|
||||
/// The resulting `Message` will be forwarded to the `Sender` of the
|
||||
/// [`Runtime`].
|
||||
///
|
||||
/// [`Command`]: struct.Command.html
|
||||
/// [`Runtime`]: struct.Runtime.html
|
||||
pub fn spawn(&mut self, command: Command<Message>) {
|
||||
use futures::{FutureExt, SinkExt};
|
||||
|
||||
|
|
@ -56,6 +86,14 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Tracks a [`Subscription`] in the [`Runtime`].
|
||||
///
|
||||
/// It will spawn new streams or close old ones as necessary! See
|
||||
/// [`Tracker::update`] to learn more about this!
|
||||
///
|
||||
/// [`Subscription`]: subscription/struct.Subscription.html
|
||||
/// [`Runtime`]: struct.Runtime.html
|
||||
/// [`Tracker::update`]: subscription/struct.Tracker.html#method.update
|
||||
pub fn track(
|
||||
&mut self,
|
||||
subscription: Subscription<Hasher, Event, Message>,
|
||||
|
|
@ -68,6 +106,13 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Broadcasts an event to all the subscriptions currently alive in the
|
||||
/// [`Runtime`].
|
||||
///
|
||||
/// See [`Tracker::broadcast`] to learn more.
|
||||
///
|
||||
/// [`Runtime`]: struct.Runtime.html
|
||||
/// [`Tracker::broadcast`]: subscription/struct.Tracker.html#method.broadcast
|
||||
pub fn broadcast(&mut self, event: Event) {
|
||||
self.subscriptions.broadcast(event);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,16 +16,16 @@ use futures::stream::BoxStream;
|
|||
/// For instance, you can use a [`Subscription`] to listen to a WebSocket
|
||||
/// connection, keyboard presses, mouse events, time ticks, etc.
|
||||
///
|
||||
/// This type is normally aliased by runtimes with a specific `Input` and/or
|
||||
/// This type is normally aliased by runtimes with a specific `Event` and/or
|
||||
/// `Hasher`.
|
||||
///
|
||||
/// [`Command`]: ../struct.Command.html
|
||||
/// [`Subscription`]: struct.Subscription.html
|
||||
pub struct Subscription<Hasher, Input, Output> {
|
||||
recipes: Vec<Box<dyn Recipe<Hasher, Input, Output = Output>>>,
|
||||
pub struct Subscription<Hasher, Event, Output> {
|
||||
recipes: Vec<Box<dyn Recipe<Hasher, Event, Output = Output>>>,
|
||||
}
|
||||
|
||||
impl<H, I, O> Subscription<H, I, O>
|
||||
impl<H, E, O> Subscription<H, E, O>
|
||||
where
|
||||
H: std::hash::Hasher,
|
||||
{
|
||||
|
|
@ -43,7 +43,7 @@ where
|
|||
/// [`Subscription`]: struct.Subscription.html
|
||||
/// [`Recipe`]: trait.Recipe.html
|
||||
pub fn from_recipe(
|
||||
recipe: impl Recipe<H, I, Output = O> + 'static,
|
||||
recipe: impl Recipe<H, E, Output = O> + 'static,
|
||||
) -> Self {
|
||||
Self {
|
||||
recipes: vec![Box::new(recipe)],
|
||||
|
|
@ -55,7 +55,7 @@ where
|
|||
///
|
||||
/// [`Subscription`]: struct.Subscription.html
|
||||
pub fn batch(
|
||||
subscriptions: impl IntoIterator<Item = Subscription<H, I, O>>,
|
||||
subscriptions: impl IntoIterator<Item = Subscription<H, E, O>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
recipes: subscriptions
|
||||
|
|
@ -68,7 +68,7 @@ where
|
|||
/// Returns the different recipes of the [`Subscription`].
|
||||
///
|
||||
/// [`Subscription`]: struct.Subscription.html
|
||||
pub fn recipes(self) -> Vec<Box<dyn Recipe<H, I, Output = O>>> {
|
||||
pub fn recipes(self) -> Vec<Box<dyn Recipe<H, E, Output = O>>> {
|
||||
self.recipes
|
||||
}
|
||||
|
||||
|
|
@ -78,10 +78,10 @@ where
|
|||
pub fn map<A>(
|
||||
mut self,
|
||||
f: impl Fn(O) -> A + Send + Sync + 'static,
|
||||
) -> Subscription<H, I, A>
|
||||
) -> Subscription<H, E, A>
|
||||
where
|
||||
H: 'static,
|
||||
I: 'static,
|
||||
E: 'static,
|
||||
O: 'static,
|
||||
A: 'static,
|
||||
{
|
||||
|
|
@ -93,7 +93,7 @@ where
|
|||
.drain(..)
|
||||
.map(|recipe| {
|
||||
Box::new(Map::new(recipe, function.clone()))
|
||||
as Box<dyn Recipe<H, I, Output = A>>
|
||||
as Box<dyn Recipe<H, E, Output = A>>
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
|
|
@ -114,7 +114,7 @@ impl<I, O, H> std::fmt::Debug for Subscription<I, O, H> {
|
|||
///
|
||||
/// [`Subscription`]: struct.Subscription.html
|
||||
/// [`Recipe`]: trait.Recipe.html
|
||||
pub trait Recipe<Hasher: std::hash::Hasher, Input> {
|
||||
pub trait Recipe<Hasher: std::hash::Hasher, Event> {
|
||||
/// The events that will be produced by a [`Subscription`] with this
|
||||
/// [`Recipe`].
|
||||
///
|
||||
|
|
@ -133,31 +133,32 @@ pub trait Recipe<Hasher: std::hash::Hasher, Input> {
|
|||
/// Executes the [`Recipe`] and produces the stream of events of its
|
||||
/// [`Subscription`].
|
||||
///
|
||||
/// It receives some generic `Input`, which is normally defined by runtimes.
|
||||
/// It receives some stream of generic events, which is normally defined by
|
||||
/// shells.
|
||||
///
|
||||
/// [`Subscription`]: struct.Subscription.html
|
||||
/// [`Recipe`]: trait.Recipe.html
|
||||
fn stream(
|
||||
self: Box<Self>,
|
||||
input: BoxStream<'static, Input>,
|
||||
input: BoxStream<'static, Event>,
|
||||
) -> BoxStream<'static, Self::Output>;
|
||||
}
|
||||
|
||||
struct Map<Hasher, Input, A, B> {
|
||||
recipe: Box<dyn Recipe<Hasher, Input, Output = A>>,
|
||||
struct Map<Hasher, Event, A, B> {
|
||||
recipe: Box<dyn Recipe<Hasher, Event, Output = A>>,
|
||||
mapper: std::sync::Arc<dyn Fn(A) -> B + Send + Sync>,
|
||||
}
|
||||
|
||||
impl<H, I, A, B> Map<H, I, A, B> {
|
||||
impl<H, E, A, B> Map<H, E, A, B> {
|
||||
fn new(
|
||||
recipe: Box<dyn Recipe<H, I, Output = A>>,
|
||||
recipe: Box<dyn Recipe<H, E, Output = A>>,
|
||||
mapper: std::sync::Arc<dyn Fn(A) -> B + Send + Sync + 'static>,
|
||||
) -> Self {
|
||||
Map { recipe, mapper }
|
||||
}
|
||||
}
|
||||
|
||||
impl<H, I, A, B> Recipe<H, I> for Map<H, I, A, B>
|
||||
impl<H, E, A, B> Recipe<H, E> for Map<H, E, A, B>
|
||||
where
|
||||
A: 'static,
|
||||
B: 'static,
|
||||
|
|
@ -174,7 +175,7 @@ where
|
|||
|
||||
fn stream(
|
||||
self: Box<Self>,
|
||||
input: BoxStream<'static, I>,
|
||||
input: BoxStream<'static, E>,
|
||||
) -> futures::stream::BoxStream<'static, Self::Output> {
|
||||
use futures::StreamExt;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@ use futures::{future::BoxFuture, sink::Sink};
|
|||
use std::collections::HashMap;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// A registry of subscription streams.
|
||||
///
|
||||
/// If you have an application that continuously returns a [`Subscription`],
|
||||
/// you can use a [`Tracker`] to keep track of the different recipes and keep
|
||||
/// its executions alive.
|
||||
#[derive(Debug)]
|
||||
pub struct Tracker<Hasher, Event> {
|
||||
subscriptions: HashMap<u64, Execution<Event>>,
|
||||
|
|
@ -21,6 +26,9 @@ where
|
|||
Hasher: std::hash::Hasher + Default,
|
||||
Event: 'static + Send + Clone,
|
||||
{
|
||||
/// Creates a new empty [`Tracker`].
|
||||
///
|
||||
/// [`Tracker`]: struct.Tracker.html
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
subscriptions: HashMap::new(),
|
||||
|
|
@ -28,6 +36,26 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Updates the [`Tracker`] with the given [`Subscription`].
|
||||
///
|
||||
/// A [`Subscription`] can cause new streams to be spawned or old streams
|
||||
/// to be closed.
|
||||
///
|
||||
/// The [`Tracker`] keeps track of these streams between calls to this
|
||||
/// method:
|
||||
///
|
||||
/// - If the provided [`Subscription`] contains a new [`Recipe`] that is
|
||||
/// currently not being run, it will spawn a new stream and keep it alive.
|
||||
/// - On the other hand, if a [`Recipe`] is currently in execution and the
|
||||
/// provided [`Subscription`] does not contain it anymore, then the
|
||||
/// [`Tracker`] will close and drop the relevant stream.
|
||||
///
|
||||
/// It returns a list of futures that need to be spawned to materialize
|
||||
/// the [`Tracker`] changes.
|
||||
///
|
||||
/// [`Tracker`]: struct.Tracker.html
|
||||
/// [`Subscription`]: struct.Subscription.html
|
||||
/// [`Recipe`]: trait.Recipe.html
|
||||
pub fn update<Message, Receiver>(
|
||||
&mut self,
|
||||
subscription: Subscription<Hasher, Event, Message>,
|
||||
|
|
@ -96,6 +124,14 @@ where
|
|||
futures
|
||||
}
|
||||
|
||||
/// Broadcasts an event to the subscriptions currently alive.
|
||||
///
|
||||
/// A subscription's [`Recipe::stream`] always receives a stream of events
|
||||
/// as input. This stream can be used by some subscription to listen to
|
||||
/// shell events.
|
||||
///
|
||||
/// This method publishes the given event to all the subscription streams
|
||||
/// currently open.
|
||||
pub fn broadcast(&mut self, event: Event) {
|
||||
self.subscriptions
|
||||
.values_mut()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue