Implement Runtime and Executor in iced_core

They can be leveraged by shells to easily execute commands
and track subscriptions.
This commit is contained in:
Héctor Ramón Jiménez 2020-01-19 09:06:48 +01:00
parent 32f7ca261f
commit d50ff9b5d9
5 changed files with 97 additions and 4 deletions

View File

@ -12,6 +12,8 @@ repository = "https://github.com/hecrj/iced"
command = ["futures"]
# Exposes a future-based `Subscription` type
subscription = ["futures", "log"]
# Exposes a `runtime` module meant to abstract over different future executors
runtime = ["command", "subscription"]
[dependencies]
futures = { version = "0.3", optional = true }

View File

@ -44,3 +44,9 @@ pub mod subscription;
#[cfg(feature = "subscription")]
pub use subscription::Subscription;
#[cfg(feature = "runtime")]
mod runtime;
#[cfg(feature = "runtime")]
pub use runtime::Runtime;

74
core/src/runtime.rs Normal file
View File

@ -0,0 +1,74 @@
mod executor;
pub use executor::Executor;
use crate::{subscription, Command, Subscription};
use futures::Sink;
use std::marker::PhantomData;
#[derive(Debug)]
pub struct Runtime<Hasher, Event, Executor, Receiver, Message> {
executor: Executor,
subscriptions: subscription::Tracker<Hasher, Event>,
receiver: Receiver,
_message: PhantomData<Message>,
}
impl<Hasher, Event, Executor, Receiver, Message>
Runtime<Hasher, Event, Executor, Receiver, Message>
where
Hasher: std::hash::Hasher + Default,
Event: Send + Clone + 'static,
Executor: self::Executor,
Receiver: Sink<Message, Error = core::convert::Infallible>
+ Unpin
+ Send
+ Clone
+ 'static,
Message: Send + 'static,
{
pub fn new(receiver: Receiver) -> Self {
Self {
executor: Executor::new(),
subscriptions: subscription::Tracker::new(),
receiver,
_message: PhantomData,
}
}
pub fn spawn(&mut self, command: Command<Message>) {
use futures::{FutureExt, SinkExt};
let futures = command.futures();
for future in futures {
let mut receiver = self.receiver.clone();
self.executor.spawn(future.then(|message| {
async move {
let _ = receiver.send(message).await;
()
}
}));
}
}
pub fn track(
&mut self,
subscription: Subscription<Hasher, Event, Message>,
) {
let futures = self
.subscriptions
.update(subscription, self.receiver.clone());
for future in futures {
self.executor.spawn(future);
}
}
pub fn broadcast(&mut self, event: Event) {
self.subscriptions.broadcast(event);
}
}

View File

@ -0,0 +1,11 @@
use futures::Future;
pub trait Executor {
fn new() -> Self;
fn spawn(&self, future: impl Future<Output = ()> + Send + 'static);
fn enter<R>(&self, f: impl FnOnce() -> R) -> R {
f()
}
}

View File

@ -28,14 +28,14 @@ where
}
}
pub fn update<Message, S>(
pub fn update<Message, Receiver>(
&mut self,
subscription: Subscription<Hasher, Event, Message>,
sink: S,
receiver: Receiver,
) -> Vec<BoxFuture<'static, ()>>
where
Message: 'static + Send,
S: 'static
Receiver: 'static
+ Sink<Message, Error = core::convert::Infallible>
+ Unpin
+ Send
@ -72,7 +72,7 @@ where
let future = futures::future::select(
cancelled,
stream.map(Ok).forward(sink.clone()),
stream.map(Ok).forward(receiver.clone()),
)
.map(|_| ());