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]
iced_native = { version = "0.1", path = "./native" }
iced_wgpu = { version = "0.1", path = "./wgpu" }
iced_futures = { version = "0.1.0-alpha", path = "./futures", features = ["async-std"] }
env_logger = "0.7"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

View File

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

View File

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

View File

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

View File

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

View File

@ -23,3 +23,7 @@ version = "0.3"
version = "0.2"
optional = true
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 use command::Command;
pub use executor::Executor;
pub use runtime::Runtime;
pub use subscription::Subscription;

View File

@ -1,9 +1,5 @@
//! Run commands and subscriptions.
mod executor;
pub use executor::Executor;
use crate::{subscription, Command, Subscription};
//! Run commands and keep track of subscriptions.
use crate::{subscription, Command, Executor, Subscription};
use futures::Sink;
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"
raw-window-handle = "0.3"
unicode-segmentation = "1.6"
futures = "0.3"
[dependencies.iced_core]
version = "0.1.0"
@ -20,3 +19,4 @@ path = "../core"
[dependencies.iced_futures]
version = "0.1.0-alpha"
path = "../futures"
features = ["thread-pool"]

View File

@ -42,7 +42,6 @@
pub mod input;
pub mod layout;
pub mod renderer;
pub mod runtime;
pub mod subscription;
pub mod widget;
pub mod window;
@ -52,6 +51,7 @@ mod element;
mod event;
mod hasher;
mod mouse_cursor;
mod runtime;
mod size;
mod user_interface;
@ -59,7 +59,10 @@ pub use iced_core::{
Align, Background, Color, Font, HorizontalAlignment, Length, Point,
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 element::Element;

View File

@ -10,5 +10,3 @@ use crate::{Event, Hasher};
/// [`Subscription`]: ../struct.Subscription.html
pub type Runtime<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.
use crate::{Event, Hasher};
use futures::stream::BoxStream;
use iced_futures::futures::stream::BoxStream;
/// A request to listen to external events.
///

View File

@ -2,6 +2,7 @@ use crate::{
subscription::{EventStream, Recipe},
Event, Hasher,
};
use iced_futures::futures::stream::BoxStream;
pub struct Events;
@ -17,7 +18,7 @@ impl Recipe<Hasher, Event> for Events {
fn stream(
self: Box<Self>,
event_stream: EventStream,
) -> futures::stream::BoxStream<'static, Self::Output> {
) -> BoxStream<'static, Self::Output> {
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.
///
@ -19,7 +19,7 @@ use crate::{window, Command, Element, Settings, Subscription};
/// before](index.html#overview). We just need to fill in the gaps:
///
/// ```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() {
/// Counter::run(Settings::default())
@ -39,6 +39,7 @@ use crate::{window, Command, Element, Settings, Subscription};
/// }
///
/// impl Application for Counter {
/// type Executor = executor::Null;
/// type Message = Message;
///
/// fn new() -> (Self, Command<Message>) {
@ -80,6 +81,14 @@ use crate::{window, Command, Element, Settings, Subscription};
/// }
/// ```
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.
///
/// [`Application`]: trait.Application.html
@ -185,6 +194,7 @@ where
A: Application,
{
type Renderer = iced_wgpu::Renderer;
type Executor = A::Executor;
type Message = A::Message;
fn new() -> (Self, Command<A::Message>) {

View File

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

View File

@ -3,6 +3,8 @@ pub use iced_winit::{
Space, Subscription, Vector, VerticalAlignment,
};
pub mod executor;
pub mod widget {
//! 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`].
///
@ -133,6 +133,7 @@ impl<T> Application for T
where
T: Sandbox,
{
type Executor = executor::Null;
type Message = T::Message;
fn new() -> (Self, Command<T::Message>) {

View File

@ -18,7 +18,6 @@ maintenance = { status = "actively-developed" }
dodrio = "0.1.0"
wasm-bindgen = "0.2.51"
wasm-bindgen-futures = "0.4"
futures = "0.3"
[dependencies.iced_core]
version = "0.1.0"

View File

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

View File

@ -16,17 +16,11 @@ debug = []
[dependencies]
winit = { version = "0.20.0-alpha3", git = "https://github.com/hecrj/winit", rev = "709808eb4e69044705fcb214bcc30556db761405"}
log = "0.4"
futures = "0.3"
[dependencies.iced_native]
version = "0.1.0-alpha"
path = "../native"
[dependencies.iced_futures]
version = "0.1.0-alpha"
path = "../futures"
features = ["thread-pool"]
[dependencies.window_clipboard]
git = "https://github.com/hecrj/window_clipboard"
rev = "22c6dd6c04cd05d528029b50a30c56417cd4bebf"

View File

@ -1,10 +1,9 @@
use crate::{
conversion,
input::{keyboard, mouse},
window, Cache, Clipboard, Command, Debug, Element, Event, Mode,
MouseCursor, Proxy, Settings, Size, Subscription, UserInterface,
window, Cache, Clipboard, Command, Debug, Element, Event, Executor, Mode,
MouseCursor, Proxy, Runtime, Settings, Size, Subscription, UserInterface,
};
use iced_native::Runtime;
/// An interactive, native cross-platform application.
///
@ -20,6 +19,11 @@ pub trait Application: Sized {
/// [`Application`]: trait.Application.html
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.
///
/// [`Application`]: trait.Application.html
@ -110,14 +114,14 @@ pub trait Application: Sized {
debug.startup_started();
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 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();
runtime.spawn(init_command);

View File

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