Add `Application::Executor` associated type

This commit is contained in:
Héctor Ramón Jiménez 2020-01-20 04:47:36 +01:00
parent 35760ac68f
commit 90690702e1
29 changed files with 195 additions and 72 deletions

View File

@ -41,6 +41,7 @@ iced_web = { version = "0.1.0", path = "web" }
[dev-dependencies] [dev-dependencies]
iced_native = { version = "0.1", path = "./native" } iced_native = { version = "0.1", path = "./native" }
iced_wgpu = { version = "0.1", path = "./wgpu" } iced_wgpu = { version = "0.1", path = "./wgpu" }
iced_futures = { version = "0.1.0-alpha", path = "./futures", features = ["async-std"] }
env_logger = "0.7" env_logger = "0.7"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"

View File

@ -1,6 +1,6 @@
use iced::{ use iced::{
Align, Application, Checkbox, Column, Command, Container, Element, Length, executor, Align, Application, Checkbox, Column, Command, Container,
Settings, Subscription, Text, Element, Length, Settings, Subscription, Text,
}; };
pub fn main() { pub fn main() {
@ -20,6 +20,7 @@ enum Message {
} }
impl Application for Events { impl Application for Events {
type Executor = executor::Default;
type Message = Message; type Message = Message;
fn new() -> (Events, Command<Message>) { fn new() -> (Events, Command<Message>) {

View File

@ -27,6 +27,7 @@ enum Message {
} }
impl Application for Pokedex { impl Application for Pokedex {
type Executor = iced_futures::executor::AsyncStd;
type Message = Message; type Message = Message;
fn new() -> (Pokedex, Command<Message>) { fn new() -> (Pokedex, Command<Message>) {

View File

@ -28,6 +28,7 @@ enum Message {
} }
impl Application for Stopwatch { impl Application for Stopwatch {
type Executor = iced_futures::executor::AsyncStd;
type Message = Message; type Message = Message;
fn new() -> (Stopwatch, Command<Message>) { fn new() -> (Stopwatch, Command<Message>) {

View File

@ -38,6 +38,7 @@ enum Message {
} }
impl Application for Todos { impl Application for Todos {
type Executor = iced_futures::executor::AsyncStd;
type Message = Message; type Message = Message;
fn new() -> (Todos, Command<Message>) { fn new() -> (Todos, Command<Message>) {

View File

@ -23,3 +23,7 @@ version = "0.3"
version = "0.2" version = "0.2"
optional = true optional = true
features = ["rt-core"] features = ["rt-core"]
[dependencies.async-std]
version = "1.0"
optional = true

36
futures/src/executor.rs Normal file
View File

@ -0,0 +1,36 @@
//! Choose your preferred executor to power a runtime.
mod null;
#[cfg(feature = "thread-pool")]
mod thread_pool;
#[cfg(feature = "thread-pool")]
pub use thread_pool::ThreadPool;
#[cfg(feature = "tokio")]
mod tokio;
#[cfg(feature = "async-std")]
mod async_std;
pub use null::Null;
#[cfg(feature = "tokio")]
pub use self::tokio::Tokio;
#[cfg(feature = "async-std")]
pub use self::async_std::AsyncStd;
use futures::Future;
pub trait Executor: Sized {
fn new() -> Result<Self, futures::io::Error>
where
Self: Sized;
fn spawn(&self, future: impl Future<Output = ()> + Send + 'static);
fn enter<R>(&self, f: impl FnOnce() -> R) -> R {
f()
}
}

View File

@ -0,0 +1,15 @@
use crate::Executor;
use futures::Future;
pub struct AsyncStd;
impl Executor for AsyncStd {
fn new() -> Result<Self, futures::io::Error> {
Ok(Self)
}
fn spawn(&self, future: impl Future<Output = ()> + Send + 'static) {
let _ = async_std::task::spawn(future);
}
}

View File

@ -0,0 +1,13 @@
use crate::Executor;
use futures::Future;
pub struct Null;
impl Executor for Null {
fn new() -> Result<Self, futures::io::Error> {
Ok(Self)
}
fn spawn(&self, _future: impl Future<Output = ()> + Send + 'static) {}
}

View File

@ -0,0 +1,15 @@
use crate::Executor;
use futures::Future;
pub type ThreadPool = futures::executor::ThreadPool;
impl Executor for futures::executor::ThreadPool {
fn new() -> Result<Self, futures::io::Error> {
futures::executor::ThreadPool::new()
}
fn spawn(&self, future: impl Future<Output = ()> + Send + 'static) {
self.spawn_ok(future);
}
}

View File

@ -0,0 +1,19 @@
use crate::Executor;
use futures::Future;
pub type Tokio = tokio::runtime::Runtime;
impl Executor for Tokio {
fn new() -> Result<Self, futures::io::Error> {
tokio::runtime::Runtime::new()
}
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)
}
}

View File

@ -1,8 +1,12 @@
mod command; pub use futures;
pub mod runtime; mod command;
mod runtime;
pub mod executor;
pub mod subscription; pub mod subscription;
pub use command::Command; pub use command::Command;
pub use executor::Executor;
pub use runtime::Runtime; pub use runtime::Runtime;
pub use subscription::Subscription; pub use subscription::Subscription;

View File

@ -1,9 +1,5 @@
//! Run commands and subscriptions. //! Run commands and keep track of subscriptions.
mod executor; use crate::{subscription, Command, Executor, Subscription};
pub use executor::Executor;
use crate::{subscription, Command, Subscription};
use futures::Sink; use futures::Sink;
use std::marker::PhantomData; use std::marker::PhantomData;

View File

@ -1,27 +0,0 @@
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()
}
}
#[cfg(feature = "thread-pool")]
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)
}
}

View File

@ -11,7 +11,6 @@ repository = "https://github.com/hecrj/iced"
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"
[dependencies.iced_core] [dependencies.iced_core]
version = "0.1.0" version = "0.1.0"
@ -20,3 +19,4 @@ path = "../core"
[dependencies.iced_futures] [dependencies.iced_futures]
version = "0.1.0-alpha" version = "0.1.0-alpha"
path = "../futures" path = "../futures"
features = ["thread-pool"]

View File

@ -42,7 +42,6 @@
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;
@ -52,6 +51,7 @@ mod element;
mod event; mod event;
mod hasher; mod hasher;
mod mouse_cursor; mod mouse_cursor;
mod runtime;
mod size; mod size;
mod user_interface; mod user_interface;
@ -59,7 +59,10 @@ pub use iced_core::{
Align, Background, Color, Font, HorizontalAlignment, Length, Point, Align, Background, Color, Font, HorizontalAlignment, Length, Point,
Rectangle, Vector, VerticalAlignment, Rectangle, Vector, VerticalAlignment,
}; };
pub use iced_futures::Command; pub use iced_futures::{executor, futures, Command};
#[doc(no_inline)]
pub use executor::Executor;
pub use clipboard::Clipboard; pub use clipboard::Clipboard;
pub use element::Element; pub use element::Element;

View File

@ -10,5 +10,3 @@ use crate::{Event, Hasher};
/// [`Subscription`]: ../struct.Subscription.html /// [`Subscription`]: ../struct.Subscription.html
pub type Runtime<Executor, Receiver, Message> = pub type Runtime<Executor, Receiver, Message> =
iced_futures::Runtime<Hasher, Event, Executor, Receiver, Message>; iced_futures::Runtime<Hasher, Event, Executor, Receiver, Message>;
pub use iced_futures::runtime::Executor;

View File

@ -1,6 +1,6 @@
//! Listen to external events in your application. //! Listen to external events in your application.
use crate::{Event, Hasher}; use crate::{Event, Hasher};
use futures::stream::BoxStream; use iced_futures::futures::stream::BoxStream;
/// A request to listen to external events. /// A request to listen to external events.
/// ///

View File

@ -2,6 +2,7 @@ use crate::{
subscription::{EventStream, Recipe}, subscription::{EventStream, Recipe},
Event, Hasher, Event, Hasher,
}; };
use iced_futures::futures::stream::BoxStream;
pub struct Events; pub struct Events;
@ -17,7 +18,7 @@ impl Recipe<Hasher, Event> for Events {
fn stream( fn stream(
self: Box<Self>, self: Box<Self>,
event_stream: EventStream, event_stream: EventStream,
) -> futures::stream::BoxStream<'static, Self::Output> { ) -> BoxStream<'static, Self::Output> {
event_stream event_stream
} }
} }

View File

@ -1,4 +1,4 @@
use crate::{window, Command, Element, Settings, Subscription}; use crate::{window, Command, Element, Executor, Settings, Subscription};
/// An interactive cross-platform application. /// An interactive cross-platform application.
/// ///
@ -19,7 +19,7 @@ use crate::{window, Command, Element, Settings, Subscription};
/// before](index.html#overview). We just need to fill in the gaps: /// before](index.html#overview). We just need to fill in the gaps:
/// ///
/// ```no_run /// ```no_run
/// use iced::{button, Application, Button, Column, Command, Element, Settings, Text}; /// use iced::{button, executor, Application, Button, Column, Command, Element, Settings, Text};
/// ///
/// pub fn main() { /// pub fn main() {
/// Counter::run(Settings::default()) /// Counter::run(Settings::default())
@ -39,6 +39,7 @@ use crate::{window, Command, Element, Settings, Subscription};
/// } /// }
/// ///
/// impl Application for Counter { /// impl Application for Counter {
/// type Executor = executor::Null;
/// type Message = Message; /// type Message = Message;
/// ///
/// fn new() -> (Self, Command<Message>) { /// fn new() -> (Self, Command<Message>) {
@ -80,6 +81,14 @@ use crate::{window, Command, Element, Settings, Subscription};
/// } /// }
/// ``` /// ```
pub trait Application: Sized { pub trait Application: Sized {
/// The [`Executor`] that will run commands and subscriptions.
///
/// The [`executor::Default`] can be a good starting point!
///
/// [`Executor`]: trait.Executor.html
/// [`executor::Default`]: executor/struct.Default.html
type Executor: Executor;
/// The type of __messages__ your [`Application`] will produce. /// The type of __messages__ your [`Application`] will produce.
/// ///
/// [`Application`]: trait.Application.html /// [`Application`]: trait.Application.html
@ -185,6 +194,7 @@ where
A: Application, A: Application,
{ {
type Renderer = iced_wgpu::Renderer; type Renderer = iced_wgpu::Renderer;
type Executor = A::Executor;
type Message = A::Message; type Message = A::Message;
fn new() -> (Self, Command<A::Message>) { fn new() -> (Self, Command<A::Message>) {

View File

@ -180,18 +180,26 @@
#![deny(unsafe_code)] #![deny(unsafe_code)]
#![deny(rust_2018_idioms)] #![deny(rust_2018_idioms)]
mod application; mod application;
#[cfg(target_arch = "wasm32")]
#[path = "web.rs"]
mod platform;
#[cfg(not(target_arch = "wasm32"))]
#[path = "native.rs"]
mod platform;
mod sandbox; mod sandbox;
#[cfg(not(target_arch = "wasm32"))]
mod native;
#[cfg(not(target_arch = "wasm32"))]
pub use native::*;
#[cfg(target_arch = "wasm32")]
mod web;
#[cfg(target_arch = "wasm32")]
pub use web::*;
pub mod settings; pub mod settings;
pub mod window; pub mod window;
#[doc(no_inline)]
pub use executor::Executor;
pub use application::Application; pub use application::Application;
pub use platform::*;
pub use sandbox::Sandbox; pub use sandbox::Sandbox;
pub use settings::Settings; pub use settings::Settings;

View File

@ -3,6 +3,8 @@ pub use iced_winit::{
Space, Subscription, Vector, VerticalAlignment, Space, Subscription, Vector, VerticalAlignment,
}; };
pub mod executor;
pub mod widget { pub mod widget {
//! Display information and interactive controls in your application. //! Display information and interactive controls in your application.
//! //!

23
src/native/executor.rs Normal file
View File

@ -0,0 +1,23 @@
//! Choose your preferred executor to power your application.
pub use iced_winit::{executor::Null, Executor};
use iced_winit::{executor::ThreadPool, futures};
/// The default cross-platform executor.
///
/// - On native platforms, it will use a `ThreadPool`.
/// - On the Web, it will use `wasm-bindgen-futures::spawn_local`.
#[derive(Debug)]
pub struct Default(ThreadPool);
impl Executor for Default {
fn new() -> Result<Self, futures::io::Error> {
Ok(Default(ThreadPool::new()?))
}
fn spawn(
&self,
future: impl futures::Future<Output = ()> + Send + 'static,
) {
self.0.spawn(future);
}
}

View File

@ -1,4 +1,4 @@
use crate::{Application, Command, Element, Settings, Subscription}; use crate::{executor, Application, Command, Element, Settings, Subscription};
/// A sandboxed [`Application`]. /// A sandboxed [`Application`].
/// ///
@ -133,6 +133,7 @@ impl<T> Application for T
where where
T: Sandbox, T: Sandbox,
{ {
type Executor = executor::Null;
type Message = T::Message; type Message = T::Message;
fn new() -> (Self, Command<T::Message>) { fn new() -> (Self, Command<T::Message>) {

View File

@ -18,7 +18,6 @@ maintenance = { status = "actively-developed" }
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"
[dependencies.iced_core] [dependencies.iced_core]
version = "0.1.0" version = "0.1.0"

View File

@ -75,7 +75,7 @@ pub use iced_core::{
Align, Background, Color, Font, HorizontalAlignment, Length, Align, Background, Color, Font, HorizontalAlignment, Length,
VerticalAlignment, VerticalAlignment,
}; };
pub use iced_futures::Command; pub use iced_futures::{futures, Command};
pub use style::Style; pub use style::Style;
pub use subscription::Subscription; pub use subscription::Subscription;
pub use widget::*; pub use widget::*;

View File

@ -16,17 +16,11 @@ debug = []
[dependencies] [dependencies]
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"}
log = "0.4" log = "0.4"
futures = "0.3"
[dependencies.iced_native] [dependencies.iced_native]
version = "0.1.0-alpha" version = "0.1.0-alpha"
path = "../native" path = "../native"
[dependencies.iced_futures]
version = "0.1.0-alpha"
path = "../futures"
features = ["thread-pool"]
[dependencies.window_clipboard] [dependencies.window_clipboard]
git = "https://github.com/hecrj/window_clipboard" git = "https://github.com/hecrj/window_clipboard"
rev = "22c6dd6c04cd05d528029b50a30c56417cd4bebf" rev = "22c6dd6c04cd05d528029b50a30c56417cd4bebf"

View File

@ -1,10 +1,9 @@
use crate::{ use crate::{
conversion, conversion,
input::{keyboard, mouse}, input::{keyboard, mouse},
window, Cache, Clipboard, Command, Debug, Element, Event, Mode, window, Cache, Clipboard, Command, Debug, Element, Event, Executor, Mode,
MouseCursor, Proxy, Settings, Size, Subscription, UserInterface, MouseCursor, Proxy, Runtime, Settings, Size, Subscription, UserInterface,
}; };
use iced_native::Runtime;
/// An interactive, native cross-platform application. /// An interactive, native cross-platform application.
/// ///
@ -20,6 +19,11 @@ pub trait Application: Sized {
/// [`Application`]: trait.Application.html /// [`Application`]: trait.Application.html
type Renderer: window::Renderer; type Renderer: window::Renderer;
/// The [`Executor`] that will run commands and subscriptions.
///
/// [`Executor`]: trait.Executor.html
type Executor: Executor;
/// The type of __messages__ your [`Application`] will produce. /// The type of __messages__ your [`Application`] will produce.
/// ///
/// [`Application`]: trait.Application.html /// [`Application`]: trait.Application.html
@ -110,14 +114,14 @@ 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 mut runtime = {
let thread_pool = futures::executor::ThreadPool::new()
.expect("Create thread pool");
Runtime::new(thread_pool, Proxy::new(event_loop.create_proxy()))
};
let mut external_messages = Vec::new(); let mut external_messages = Vec::new();
let mut runtime = {
let executor = Self::Executor::new().expect("Create executor");
Runtime::new(executor, Proxy::new(event_loop.create_proxy()))
};
let (mut application, init_command) = Self::new(); let (mut application, init_command) = Self::new();
runtime.spawn(init_command); runtime.spawn(init_command);

View File

@ -1,4 +1,4 @@
use futures::{ use iced_native::futures::{
task::{Context, Poll}, task::{Context, Poll},
Sink, Sink,
}; };