Create iced_futures
and wire everything up
This commit is contained in:
parent
d50ff9b5d9
commit
b5b17ed4d8
@ -23,6 +23,7 @@ maintenance = { status = "actively-developed" }
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"core",
|
"core",
|
||||||
|
"futures",
|
||||||
"native",
|
"native",
|
||||||
"style",
|
"style",
|
||||||
"web",
|
"web",
|
||||||
|
@ -7,14 +7,4 @@ description = "The essential concepts of Iced"
|
|||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://github.com/hecrj/iced"
|
repository = "https://github.com/hecrj/iced"
|
||||||
|
|
||||||
[features]
|
|
||||||
# Exposes a future-based `Command` type
|
|
||||||
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]
|
[dependencies]
|
||||||
futures = { version = "0.3", optional = true }
|
|
||||||
log = { version = "0.4", optional = true }
|
|
||||||
|
@ -32,21 +32,3 @@ pub use length::Length;
|
|||||||
pub use point::Point;
|
pub use point::Point;
|
||||||
pub use rectangle::Rectangle;
|
pub use rectangle::Rectangle;
|
||||||
pub use vector::Vector;
|
pub use vector::Vector;
|
||||||
|
|
||||||
#[cfg(feature = "command")]
|
|
||||||
mod command;
|
|
||||||
|
|
||||||
#[cfg(feature = "command")]
|
|
||||||
pub use command::Command;
|
|
||||||
|
|
||||||
#[cfg(feature = "subscription")]
|
|
||||||
pub mod subscription;
|
|
||||||
|
|
||||||
#[cfg(feature = "subscription")]
|
|
||||||
pub use subscription::Subscription;
|
|
||||||
|
|
||||||
#[cfg(feature = "runtime")]
|
|
||||||
mod runtime;
|
|
||||||
|
|
||||||
#[cfg(feature = "runtime")]
|
|
||||||
pub use runtime::Runtime;
|
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
23
futures/Cargo.toml
Normal file
23
futures/Cargo.toml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
[package]
|
||||||
|
name = "iced_futures"
|
||||||
|
version = "0.1.0-alpha"
|
||||||
|
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
description = "Commands, subscriptions, and runtimes for Iced"
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://github.com/hecrj/iced"
|
||||||
|
documentation = "https://docs.rs/iced_futures"
|
||||||
|
keywords = ["gui", "ui", "graphics", "interface", "futures"]
|
||||||
|
categories = ["gui"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
log = "0.4"
|
||||||
|
|
||||||
|
[dependencies.futures]
|
||||||
|
version = "0.3"
|
||||||
|
features = ["thread-pool"]
|
||||||
|
|
||||||
|
[dependencies.tokio]
|
||||||
|
version = "0.2"
|
||||||
|
optional = true
|
||||||
|
features = ["rt-core"]
|
8
futures/src/lib.rs
Normal file
8
futures/src/lib.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
mod command;
|
||||||
|
|
||||||
|
pub mod runtime;
|
||||||
|
pub mod subscription;
|
||||||
|
|
||||||
|
pub use command::Command;
|
||||||
|
pub use runtime::Runtime;
|
||||||
|
pub use subscription::Subscription;
|
@ -1,3 +1,4 @@
|
|||||||
|
//! Run commands and subscriptions.
|
||||||
mod executor;
|
mod executor;
|
||||||
|
|
||||||
pub use executor::Executor;
|
pub use executor::Executor;
|
||||||
@ -10,8 +11,8 @@ use std::marker::PhantomData;
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Runtime<Hasher, Event, Executor, Receiver, Message> {
|
pub struct Runtime<Hasher, Event, Executor, Receiver, Message> {
|
||||||
executor: Executor,
|
executor: Executor,
|
||||||
subscriptions: subscription::Tracker<Hasher, Event>,
|
|
||||||
receiver: Receiver,
|
receiver: Receiver,
|
||||||
|
subscriptions: subscription::Tracker<Hasher, Event>,
|
||||||
_message: PhantomData<Message>,
|
_message: PhantomData<Message>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,15 +29,19 @@ where
|
|||||||
+ 'static,
|
+ 'static,
|
||||||
Message: Send + 'static,
|
Message: Send + 'static,
|
||||||
{
|
{
|
||||||
pub fn new(receiver: Receiver) -> Self {
|
pub fn new(executor: Executor, receiver: Receiver) -> Self {
|
||||||
Self {
|
Self {
|
||||||
executor: Executor::new(),
|
executor,
|
||||||
subscriptions: subscription::Tracker::new(),
|
|
||||||
receiver,
|
receiver,
|
||||||
|
subscriptions: subscription::Tracker::new(),
|
||||||
_message: PhantomData,
|
_message: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn enter<R>(&self, f: impl FnOnce() -> R) -> R {
|
||||||
|
self.executor.enter(f)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn spawn(&mut self, command: Command<Message>) {
|
pub fn spawn(&mut self, command: Command<Message>) {
|
||||||
use futures::{FutureExt, SinkExt};
|
use futures::{FutureExt, SinkExt};
|
||||||
|
|
26
futures/src/runtime/executor.rs
Normal file
26
futures/src/runtime/executor.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use futures::Future;
|
||||||
|
|
||||||
|
pub trait Executor {
|
||||||
|
fn spawn(&self, future: impl Future<Output = ()> + Send + 'static);
|
||||||
|
|
||||||
|
fn enter<R>(&self, f: impl FnOnce() -> R) -> R {
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Executor for futures::executor::ThreadPool {
|
||||||
|
fn spawn(&self, future: impl Future<Output = ()> + Send + 'static) {
|
||||||
|
self.spawn_ok(future);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "tokio")]
|
||||||
|
impl Executor for tokio::runtime::Runtime {
|
||||||
|
fn spawn(&self, future: impl Future<Output = ()> + Send + 'static) {
|
||||||
|
let _ = tokio::runtime::Runtime::spawn(self, future);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enter<R>(&self, f: impl FnOnce() -> R) -> R {
|
||||||
|
tokio::runtime::Runtime::enter(self, f)
|
||||||
|
}
|
||||||
|
}
|
@ -8,8 +8,15 @@ license = "MIT"
|
|||||||
repository = "https://github.com/hecrj/iced"
|
repository = "https://github.com/hecrj/iced"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
iced_core = { version = "0.1.0", path = "../core", features = ["command", "subscription"] }
|
|
||||||
twox-hash = "1.5"
|
twox-hash = "1.5"
|
||||||
raw-window-handle = "0.3"
|
raw-window-handle = "0.3"
|
||||||
unicode-segmentation = "1.6"
|
unicode-segmentation = "1.6"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
|
|
||||||
|
[dependencies.iced_core]
|
||||||
|
version = "0.1.0"
|
||||||
|
path = "../core"
|
||||||
|
|
||||||
|
[dependencies.iced_futures]
|
||||||
|
version = "0.1.0-alpha"
|
||||||
|
path = "../futures"
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
pub mod input;
|
pub mod input;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
pub mod renderer;
|
pub mod renderer;
|
||||||
|
pub mod runtime;
|
||||||
pub mod subscription;
|
pub mod subscription;
|
||||||
pub mod widget;
|
pub mod widget;
|
||||||
pub mod window;
|
pub mod window;
|
||||||
@ -55,9 +56,10 @@ mod size;
|
|||||||
mod user_interface;
|
mod user_interface;
|
||||||
|
|
||||||
pub use iced_core::{
|
pub use iced_core::{
|
||||||
Align, Background, Color, Command, Font, HorizontalAlignment, Length,
|
Align, Background, Color, Font, HorizontalAlignment, Length, Point,
|
||||||
Point, Rectangle, Vector, VerticalAlignment,
|
Rectangle, Vector, VerticalAlignment,
|
||||||
};
|
};
|
||||||
|
pub use iced_futures::Command;
|
||||||
|
|
||||||
pub use clipboard::Clipboard;
|
pub use clipboard::Clipboard;
|
||||||
pub use element::Element;
|
pub use element::Element;
|
||||||
@ -66,6 +68,7 @@ pub use hasher::Hasher;
|
|||||||
pub use layout::Layout;
|
pub use layout::Layout;
|
||||||
pub use mouse_cursor::MouseCursor;
|
pub use mouse_cursor::MouseCursor;
|
||||||
pub use renderer::Renderer;
|
pub use renderer::Renderer;
|
||||||
|
pub use runtime::Runtime;
|
||||||
pub use size::Size;
|
pub use size::Size;
|
||||||
pub use subscription::Subscription;
|
pub use subscription::Subscription;
|
||||||
pub use user_interface::{Cache, UserInterface};
|
pub use user_interface::{Cache, UserInterface};
|
||||||
|
14
native/src/runtime.rs
Normal file
14
native/src/runtime.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
//! Run commands and subscriptions.
|
||||||
|
use crate::{Event, Hasher};
|
||||||
|
|
||||||
|
/// A native runtime with a generic executor and receiver of results.
|
||||||
|
///
|
||||||
|
/// It can be used by shells to easily spawn a [`Command`] or track a
|
||||||
|
/// [`Subscription`].
|
||||||
|
///
|
||||||
|
/// [`Command`]: ../struct.Command.html
|
||||||
|
/// [`Subscription`]: ../struct.Subscription.html
|
||||||
|
pub type Runtime<Executor, Receiver, Message> =
|
||||||
|
iced_futures::Runtime<Hasher, Event, Executor, Receiver, Message>;
|
||||||
|
|
||||||
|
pub use iced_futures::runtime::Executor;
|
@ -15,7 +15,7 @@ use futures::stream::BoxStream;
|
|||||||
///
|
///
|
||||||
/// [`Command`]: ../struct.Command.html
|
/// [`Command`]: ../struct.Command.html
|
||||||
/// [`Subscription`]: struct.Subscription.html
|
/// [`Subscription`]: struct.Subscription.html
|
||||||
pub type Subscription<T> = iced_core::Subscription<Hasher, Event, T>;
|
pub type Subscription<T> = iced_futures::Subscription<Hasher, Event, T>;
|
||||||
|
|
||||||
/// A stream of runtime events.
|
/// A stream of runtime events.
|
||||||
///
|
///
|
||||||
@ -27,9 +27,9 @@ pub type EventStream = BoxStream<'static, Event>;
|
|||||||
/// A native [`Subscription`] tracker.
|
/// A native [`Subscription`] tracker.
|
||||||
///
|
///
|
||||||
/// [`Subscription`]: type.Subscription.html
|
/// [`Subscription`]: type.Subscription.html
|
||||||
pub type Tracker = iced_core::subscription::Tracker<Hasher, Event>;
|
pub type Tracker = iced_futures::subscription::Tracker<Hasher, Event>;
|
||||||
|
|
||||||
pub use iced_core::subscription::Recipe;
|
pub use iced_futures::subscription::Recipe;
|
||||||
|
|
||||||
mod events;
|
mod events;
|
||||||
|
|
||||||
|
@ -15,12 +15,19 @@ categories = ["web-programming"]
|
|||||||
maintenance = { status = "actively-developed" }
|
maintenance = { status = "actively-developed" }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
iced_core = { version = "0.1.0", path = "../core", features = ["command", "subscription"] }
|
|
||||||
dodrio = "0.1.0"
|
dodrio = "0.1.0"
|
||||||
wasm-bindgen = "0.2.51"
|
wasm-bindgen = "0.2.51"
|
||||||
wasm-bindgen-futures = "0.4"
|
wasm-bindgen-futures = "0.4"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
|
|
||||||
|
[dependencies.iced_core]
|
||||||
|
version = "0.1.0"
|
||||||
|
path = "../core"
|
||||||
|
|
||||||
|
[dependencies.iced_futures]
|
||||||
|
version = "0.1.0-alpha"
|
||||||
|
path = "../futures"
|
||||||
|
|
||||||
[dependencies.web-sys]
|
[dependencies.web-sys]
|
||||||
version = "0.3.27"
|
version = "0.3.27"
|
||||||
features = [
|
features = [
|
||||||
|
@ -72,9 +72,10 @@ pub use dodrio;
|
|||||||
pub use element::Element;
|
pub use element::Element;
|
||||||
pub use hasher::Hasher;
|
pub use hasher::Hasher;
|
||||||
pub use iced_core::{
|
pub use iced_core::{
|
||||||
Align, Background, Color, Command, Font, HorizontalAlignment, Length,
|
Align, Background, Color, Font, HorizontalAlignment, Length,
|
||||||
VerticalAlignment,
|
VerticalAlignment,
|
||||||
};
|
};
|
||||||
|
pub use iced_futures::Command;
|
||||||
pub use style::Style;
|
pub use style::Style;
|
||||||
pub use subscription::Subscription;
|
pub use subscription::Subscription;
|
||||||
pub use widget::*;
|
pub use widget::*;
|
||||||
@ -148,7 +149,6 @@ pub trait Application {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct Instance<Message> {
|
struct Instance<Message> {
|
||||||
title: String,
|
title: String,
|
||||||
ui: Rc<RefCell<Box<dyn Application<Message = Message>>>>,
|
ui: Rc<RefCell<Box<dyn Application<Message = Message>>>>,
|
||||||
@ -167,7 +167,7 @@ impl<Message> Clone for Instance<Message> {
|
|||||||
|
|
||||||
impl<Message> Instance<Message>
|
impl<Message> Instance<Message>
|
||||||
where
|
where
|
||||||
Message: 'static
|
Message: 'static,
|
||||||
{
|
{
|
||||||
fn new(ui: impl Application<Message = Message> + 'static) -> Self {
|
fn new(ui: impl Application<Message = Message> + 'static) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -14,6 +14,6 @@ use crate::Hasher;
|
|||||||
///
|
///
|
||||||
/// [`Command`]: ../struct.Command.html
|
/// [`Command`]: ../struct.Command.html
|
||||||
/// [`Subscription`]: struct.Subscription.html
|
/// [`Subscription`]: struct.Subscription.html
|
||||||
pub type Subscription<T> = iced_core::Subscription<Hasher, (), T>;
|
pub type Subscription<T> = iced_futures::Subscription<Hasher, (), T>;
|
||||||
|
|
||||||
pub use iced_core::subscription::Recipe;
|
pub use iced_futures::subscription::Recipe;
|
||||||
|
@ -14,11 +14,17 @@ categories = ["gui"]
|
|||||||
debug = []
|
debug = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
iced_native = { version = "0.1.0-alpha", path = "../native" }
|
|
||||||
winit = { version = "0.20.0-alpha3", git = "https://github.com/hecrj/winit", rev = "709808eb4e69044705fcb214bcc30556db761405"}
|
winit = { version = "0.20.0-alpha3", git = "https://github.com/hecrj/winit", rev = "709808eb4e69044705fcb214bcc30556db761405"}
|
||||||
window_clipboard = { git = "https://github.com/hecrj/window_clipboard", rev = "22c6dd6c04cd05d528029b50a30c56417cd4bebf" }
|
|
||||||
futures = { version = "0.3", features = ["thread-pool"] }
|
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
futures = { version = "0.3", features = ["thread-pool"] }
|
||||||
|
|
||||||
|
[dependencies.iced_native]
|
||||||
|
version = "0.1.0-alpha"
|
||||||
|
path = "../native"
|
||||||
|
|
||||||
|
[dependencies.window_clipboard]
|
||||||
|
git = "https://github.com/hecrj/window_clipboard"
|
||||||
|
rev = "22c6dd6c04cd05d528029b50a30c56417cd4bebf"
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies.winapi]
|
[target.'cfg(target_os = "windows")'.dependencies.winapi]
|
||||||
version = "0.3.6"
|
version = "0.3.6"
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
conversion,
|
conversion,
|
||||||
input::{keyboard, mouse},
|
input::{keyboard, mouse},
|
||||||
subscription, window, Cache, Clipboard, Command, Debug, Element, Event,
|
window, Cache, Clipboard, Command, Debug, Element, Event, Mode,
|
||||||
Mode, MouseCursor, Settings, Size, Subscription, UserInterface,
|
MouseCursor, Proxy, Settings, Size, Subscription, UserInterface,
|
||||||
};
|
};
|
||||||
|
use iced_native::Runtime;
|
||||||
|
|
||||||
/// An interactive, native cross-platform application.
|
/// An interactive, native cross-platform application.
|
||||||
///
|
///
|
||||||
@ -109,17 +110,19 @@ pub trait Application: Sized {
|
|||||||
|
|
||||||
debug.startup_started();
|
debug.startup_started();
|
||||||
let event_loop = EventLoop::with_user_event();
|
let event_loop = EventLoop::with_user_event();
|
||||||
let proxy = event_loop.create_proxy();
|
let mut runtime = {
|
||||||
let mut thread_pool =
|
let thread_pool = futures::executor::ThreadPool::new()
|
||||||
futures::executor::ThreadPool::new().expect("Create thread pool");
|
.expect("Create thread pool");
|
||||||
let mut subscription_pool = subscription::Pool::new();
|
|
||||||
|
Runtime::new(thread_pool, Proxy::new(event_loop.create_proxy()))
|
||||||
|
};
|
||||||
let mut external_messages = Vec::new();
|
let mut external_messages = Vec::new();
|
||||||
|
|
||||||
let (mut application, init_command) = Self::new();
|
let (mut application, init_command) = Self::new();
|
||||||
spawn(init_command, &mut thread_pool, &proxy);
|
runtime.spawn(init_command);
|
||||||
|
|
||||||
let subscription = application.subscription();
|
let subscription = application.subscription();
|
||||||
subscription_pool.update(subscription, &mut thread_pool, &proxy);
|
runtime.track(subscription);
|
||||||
|
|
||||||
let mut title = application.title();
|
let mut title = application.title();
|
||||||
let mut mode = application.mode();
|
let mut mode = application.mode();
|
||||||
@ -212,7 +215,7 @@ pub trait Application: Sized {
|
|||||||
events
|
events
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.for_each(|event| subscription_pool.broadcast_event(event));
|
.for_each(|event| runtime.broadcast(event));
|
||||||
|
|
||||||
let mut messages = user_interface.update(
|
let mut messages = user_interface.update(
|
||||||
&renderer,
|
&renderer,
|
||||||
@ -241,17 +244,15 @@ pub trait Application: Sized {
|
|||||||
debug.log_message(&message);
|
debug.log_message(&message);
|
||||||
|
|
||||||
debug.update_started();
|
debug.update_started();
|
||||||
let command = application.update(message);
|
let command =
|
||||||
spawn(command, &mut thread_pool, &proxy);
|
runtime.enter(|| application.update(message));
|
||||||
|
runtime.spawn(command);
|
||||||
debug.update_finished();
|
debug.update_finished();
|
||||||
}
|
}
|
||||||
|
|
||||||
let subscription = application.subscription();
|
let subscription =
|
||||||
subscription_pool.update(
|
runtime.enter(|| application.subscription());
|
||||||
subscription,
|
runtime.track(subscription);
|
||||||
&mut thread_pool,
|
|
||||||
&proxy,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Update window title
|
// Update window title
|
||||||
let new_title = application.title();
|
let new_title = application.title();
|
||||||
@ -463,28 +464,6 @@ fn to_physical(size: winit::dpi::LogicalSize, dpi: f64) -> (u16, u16) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn<Message: Send>(
|
|
||||||
command: Command<Message>,
|
|
||||||
thread_pool: &mut futures::executor::ThreadPool,
|
|
||||||
proxy: &winit::event_loop::EventLoopProxy<Message>,
|
|
||||||
) {
|
|
||||||
use futures::FutureExt;
|
|
||||||
|
|
||||||
let futures = command.futures();
|
|
||||||
|
|
||||||
for future in futures {
|
|
||||||
let proxy = proxy.clone();
|
|
||||||
|
|
||||||
let future = future.map(move |message| {
|
|
||||||
proxy
|
|
||||||
.send_event(message)
|
|
||||||
.expect("Send command result to event loop");
|
|
||||||
});
|
|
||||||
|
|
||||||
thread_pool.spawn_ok(future);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// As defined in: http://www.unicode.org/faq/private_use.html
|
// As defined in: http://www.unicode.org/faq/private_use.html
|
||||||
// TODO: Remove once https://github.com/rust-windowing/winit/pull/1254 lands
|
// TODO: Remove once https://github.com/rust-windowing/winit/pull/1254 lands
|
||||||
fn is_private_use_character(c: char) -> bool {
|
fn is_private_use_character(c: char) -> bool {
|
||||||
|
@ -31,7 +31,7 @@ pub mod settings;
|
|||||||
mod application;
|
mod application;
|
||||||
mod clipboard;
|
mod clipboard;
|
||||||
mod mode;
|
mod mode;
|
||||||
mod subscription;
|
mod proxy;
|
||||||
|
|
||||||
// We disable debug capabilities on release builds unless the `debug` feature
|
// We disable debug capabilities on release builds unless the `debug` feature
|
||||||
// is explicitly enabled.
|
// is explicitly enabled.
|
||||||
@ -48,3 +48,4 @@ pub use settings::Settings;
|
|||||||
|
|
||||||
use clipboard::Clipboard;
|
use clipboard::Clipboard;
|
||||||
use debug::Debug;
|
use debug::Debug;
|
||||||
|
use proxy::Proxy;
|
||||||
|
57
winit/src/proxy.rs
Normal file
57
winit/src/proxy.rs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
use futures::{
|
||||||
|
task::{Context, Poll},
|
||||||
|
Sink,
|
||||||
|
};
|
||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
pub struct Proxy<Message: 'static> {
|
||||||
|
raw: winit::event_loop::EventLoopProxy<Message>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Message: 'static> Clone for Proxy<Message> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
raw: self.raw.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Message: 'static> Proxy<Message> {
|
||||||
|
pub fn new(raw: winit::event_loop::EventLoopProxy<Message>) -> Self {
|
||||||
|
Self { raw }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Message: 'static> Sink<Message> for Proxy<Message> {
|
||||||
|
type Error = core::convert::Infallible;
|
||||||
|
|
||||||
|
fn poll_ready(
|
||||||
|
self: Pin<&mut Self>,
|
||||||
|
_cx: &mut Context<'_>,
|
||||||
|
) -> Poll<Result<(), Self::Error>> {
|
||||||
|
Poll::Ready(Ok(()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_send(
|
||||||
|
self: Pin<&mut Self>,
|
||||||
|
message: Message,
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
let _ = self.raw.send_event(message);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll_flush(
|
||||||
|
self: Pin<&mut Self>,
|
||||||
|
_cx: &mut Context<'_>,
|
||||||
|
) -> Poll<Result<(), Self::Error>> {
|
||||||
|
Poll::Ready(Ok(()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll_close(
|
||||||
|
self: Pin<&mut Self>,
|
||||||
|
_cx: &mut Context<'_>,
|
||||||
|
) -> Poll<Result<(), Self::Error>> {
|
||||||
|
Poll::Ready(Ok(()))
|
||||||
|
}
|
||||||
|
}
|
@ -1,97 +0,0 @@
|
|||||||
use iced_native::{Event, Hasher, Subscription};
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
pub struct Pool {
|
|
||||||
alive: HashMap<u64, Handle>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Handle {
|
|
||||||
_cancel: futures::channel::oneshot::Sender<()>,
|
|
||||||
listener: Option<futures::channel::mpsc::Sender<Event>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Pool {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
alive: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update<Message: Send>(
|
|
||||||
&mut self,
|
|
||||||
subscription: Subscription<Message>,
|
|
||||||
thread_pool: &mut futures::executor::ThreadPool,
|
|
||||||
proxy: &winit::event_loop::EventLoopProxy<Message>,
|
|
||||||
) {
|
|
||||||
use futures::{future::FutureExt, stream::StreamExt};
|
|
||||||
|
|
||||||
let recipes = subscription.recipes();
|
|
||||||
let mut alive = std::collections::HashSet::new();
|
|
||||||
|
|
||||||
for recipe in recipes {
|
|
||||||
let id = {
|
|
||||||
use std::hash::Hasher as _;
|
|
||||||
|
|
||||||
let mut hasher = Hasher::default();
|
|
||||||
recipe.hash(&mut hasher);
|
|
||||||
|
|
||||||
hasher.finish()
|
|
||||||
};
|
|
||||||
|
|
||||||
let _ = alive.insert(id);
|
|
||||||
|
|
||||||
if !self.alive.contains_key(&id) {
|
|
||||||
let (cancel, cancelled) = futures::channel::oneshot::channel();
|
|
||||||
|
|
||||||
// TODO: Use bus if/when it supports async
|
|
||||||
let (event_sender, event_receiver) =
|
|
||||||
futures::channel::mpsc::channel(100);
|
|
||||||
|
|
||||||
let stream = recipe.stream(event_receiver.boxed());
|
|
||||||
let proxy = proxy.clone();
|
|
||||||
|
|
||||||
let future = futures::future::select(
|
|
||||||
cancelled,
|
|
||||||
stream.for_each(move |message| {
|
|
||||||
proxy
|
|
||||||
.send_event(message)
|
|
||||||
.expect("Send subscription result to event loop");
|
|
||||||
|
|
||||||
futures::future::ready(())
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.map(|_| ());
|
|
||||||
|
|
||||||
thread_pool.spawn_ok(future);
|
|
||||||
|
|
||||||
let _ = self.alive.insert(
|
|
||||||
id,
|
|
||||||
Handle {
|
|
||||||
_cancel: cancel,
|
|
||||||
listener: if event_sender.is_closed() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(event_sender)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.alive.retain(|id, _| alive.contains(&id));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn broadcast_event(&mut self, event: Event) {
|
|
||||||
self.alive
|
|
||||||
.values_mut()
|
|
||||||
.filter_map(|connection| connection.listener.as_mut())
|
|
||||||
.for_each(|listener| {
|
|
||||||
if let Err(error) = listener.try_send(event.clone()) {
|
|
||||||
log::error!(
|
|
||||||
"Error sending event to subscription: {:?}",
|
|
||||||
error
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user