diff options
| author | 2023-09-10 00:34:21 +0200 | |
|---|---|---|
| committer | 2023-09-10 00:34:21 +0200 | |
| commit | b8e5693a3089d728b4f8d4b3b0b7197202ebd732 (patch) | |
| tree | 79a9f84f9920525657fbe03d53ce33bab09053d7 /futures/src | |
| parent | 956512338905bac0b156fdaf16fe3c3e07e97a84 (diff) | |
| parent | a3489e4af960388e9f73988b88df361022a654a4 (diff) | |
| download | iced-b8e5693a3089d728b4f8d4b3b0b7197202ebd732.tar.gz iced-b8e5693a3089d728b4f8d4b3b0b7197202ebd732.tar.bz2 iced-b8e5693a3089d728b4f8d4b3b0b7197202ebd732.zip | |
Merge branch 'master' into explicit-text-caching
Diffstat (limited to 'futures/src')
| -rw-r--r-- | futures/src/event.rs | 59 | ||||
| -rw-r--r-- | futures/src/keyboard.rs | 61 | ||||
| -rw-r--r-- | futures/src/lib.rs | 7 | ||||
| -rw-r--r-- | futures/src/runtime.rs | 5 | ||||
| -rw-r--r-- | futures/src/subscription.rs | 97 | ||||
| -rw-r--r-- | futures/src/subscription/tracker.rs | 3 | 
6 files changed, 152 insertions, 80 deletions
| diff --git a/futures/src/event.rs b/futures/src/event.rs new file mode 100644 index 00000000..214d2d40 --- /dev/null +++ b/futures/src/event.rs @@ -0,0 +1,59 @@ +//! Listen to runtime events. +use crate::core::event::{self, Event}; +use crate::core::window; +use crate::subscription::{self, Subscription}; +use crate::MaybeSend; + +/// Returns a [`Subscription`] to all the ignored runtime events. +/// +/// This subscription will notify your application of any [`Event`] that was +/// not captured by any widget. +pub fn listen() -> Subscription<Event> { +    listen_with(|event, status| match status { +        event::Status::Ignored => Some(event), +        event::Status::Captured => None, +    }) +} + +/// Creates a [`Subscription`] that listens and filters all the runtime events +/// with the provided function, producing messages accordingly. +/// +/// This subscription will call the provided function for every [`Event`] +/// handled by the runtime. If the function: +/// +/// - Returns `None`, the [`Event`] will be discarded. +/// - Returns `Some` message, the `Message` will be produced. +pub fn listen_with<Message>( +    f: fn(Event, event::Status) -> Option<Message>, +) -> Subscription<Message> +where +    Message: 'static + MaybeSend, +{ +    #[derive(Hash)] +    struct EventsWith; + +    subscription::filter_map( +        (EventsWith, f), +        move |event, status| match event { +            Event::Window(window::Event::RedrawRequested(_)) => None, +            _ => f(event, status), +        }, +    ) +} + +/// Creates a [`Subscription`] that produces a message for every runtime event, +/// including the redraw request events. +/// +/// **Warning:** This [`Subscription`], if unfiltered, may produce messages in +/// an infinite loop. +pub fn listen_raw<Message>( +    f: fn(Event, event::Status) -> Option<Message>, +) -> Subscription<Message> +where +    Message: 'static + MaybeSend, +{ +    #[derive(Hash)] +    struct RawEvents; + +    subscription::filter_map((RawEvents, f), f) +} diff --git a/futures/src/keyboard.rs b/futures/src/keyboard.rs new file mode 100644 index 00000000..af68e1f2 --- /dev/null +++ b/futures/src/keyboard.rs @@ -0,0 +1,61 @@ +//! Listen to keyboard events. +use crate::core; +use crate::core::keyboard::{Event, KeyCode, Modifiers}; +use crate::subscription::{self, Subscription}; +use crate::MaybeSend; + +/// Listens to keyboard key presses and calls the given function +/// map them into actual messages. +/// +/// If the function returns `None`, the key press will be simply +/// ignored. +pub fn on_key_press<Message>( +    f: fn(KeyCode, Modifiers) -> Option<Message>, +) -> Subscription<Message> +where +    Message: MaybeSend + 'static, +{ +    #[derive(Hash)] +    struct OnKeyPress; + +    subscription::filter_map((OnKeyPress, f), move |event, status| { +        match (event, status) { +            ( +                core::Event::Keyboard(Event::KeyPressed { +                    key_code, +                    modifiers, +                }), +                core::event::Status::Ignored, +            ) => f(key_code, modifiers), +            _ => None, +        } +    }) +} + +/// Listens to keyboard key releases and calls the given function +/// map them into actual messages. +/// +/// If the function returns `None`, the key release will be simply +/// ignored. +pub fn on_key_release<Message>( +    f: fn(KeyCode, Modifiers) -> Option<Message>, +) -> Subscription<Message> +where +    Message: MaybeSend + 'static, +{ +    #[derive(Hash)] +    struct OnKeyRelease; + +    subscription::filter_map((OnKeyRelease, f), move |event, status| { +        match (event, status) { +            ( +                core::Event::Keyboard(Event::KeyReleased { +                    key_code, +                    modifiers, +                }), +                core::event::Status::Ignored, +            ) => f(key_code, modifiers), +            _ => None, +        } +    }) +} diff --git a/futures/src/lib.rs b/futures/src/lib.rs index 34d81e1e..abc46176 100644 --- a/futures/src/lib.rs +++ b/futures/src/lib.rs @@ -4,6 +4,7 @@  #![doc(      html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg"  )] +#![forbid(unsafe_code, rust_2018_idioms)]  #![deny(      missing_debug_implementations,      missing_docs, @@ -12,9 +13,9 @@      clippy::from_over_into,      clippy::needless_borrow,      clippy::new_without_default, -    clippy::useless_conversion +    clippy::useless_conversion, +    rustdoc::broken_intra_doc_links  )] -#![forbid(unsafe_code, rust_2018_idioms)]  #![allow(clippy::inherent_to_string, clippy::type_complexity)]  #![cfg_attr(docsrs, feature(doc_auto_cfg))]  pub use futures; @@ -24,7 +25,9 @@ mod maybe_send;  mod runtime;  pub mod backend; +pub mod event;  pub mod executor; +pub mod keyboard;  pub mod subscription;  pub use executor::Executor; diff --git a/futures/src/runtime.rs b/futures/src/runtime.rs index 2241a494..16111b36 100644 --- a/futures/src/runtime.rs +++ b/futures/src/runtime.rs @@ -9,9 +9,9 @@ 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! +/// `Command` or [`Subscription`] and get notified of the results!  /// -/// [`Command`]: crate::Command +/// [`Subscription`]: crate::Subscription  #[derive(Debug)]  pub struct Runtime<Executor, Sender, Message> {      executor: Executor, @@ -75,6 +75,7 @@ where      /// [`Tracker::update`] to learn more about this!      ///      /// [`Tracker::update`]: subscription::Tracker::update +    /// [`Subscription`]: crate::Subscription      pub fn track(          &mut self,          recipes: impl IntoIterator< diff --git a/futures/src/subscription.rs b/futures/src/subscription.rs index 8f78ce3a..d40125e3 100644 --- a/futures/src/subscription.rs +++ b/futures/src/subscription.rs @@ -4,7 +4,6 @@ mod tracker;  pub use tracker::Tracker;  use crate::core::event::{self, Event}; -use crate::core::window;  use crate::core::Hasher;  use crate::futures::{Future, Stream};  use crate::{BoxStream, MaybeSend}; @@ -20,16 +19,14 @@ pub type EventStream = BoxStream<(Event, event::Status)>;  /// A request to listen to external events.  /// -/// Besides performing async actions on demand with [`Command`], most +/// Besides performing async actions on demand with `Command`, most  /// applications also need to listen to external events passively.  /// -/// A [`Subscription`] is normally provided to some runtime, like a [`Command`], +/// A [`Subscription`] is normally provided to some runtime, like a `Command`,  /// and it will generate events as long as the user keeps requesting it.  ///  /// For instance, you can use a [`Subscription`] to listen to a WebSocket  /// connection, keyboard presses, mouse events, time ticks, etc. -/// -/// [`Command`]: crate::Command  #[must_use = "`Subscription` must be returned to runtime to take effect"]  pub struct Subscription<Message> {      recipes: Vec<Box<dyn Recipe<Output = Message>>>, @@ -215,77 +212,6 @@ where      }  } -/// Returns a [`Subscription`] to all the ignored runtime events. -/// -/// This subscription will notify your application of any [`Event`] that was -/// not captured by any widget. -pub fn events() -> Subscription<Event> { -    events_with(|event, status| match status { -        event::Status::Ignored => Some(event), -        event::Status::Captured => None, -    }) -} - -/// Returns a [`Subscription`] that filters all the runtime events with the -/// provided function, producing messages accordingly. -/// -/// This subscription will call the provided function for every [`Event`] -/// handled by the runtime. If the function: -/// -/// - Returns `None`, the [`Event`] will be discarded. -/// - Returns `Some` message, the `Message` will be produced. -pub fn events_with<Message>( -    f: fn(Event, event::Status) -> Option<Message>, -) -> Subscription<Message> -where -    Message: 'static + MaybeSend, -{ -    #[derive(Hash)] -    struct EventsWith; - -    Subscription::from_recipe(Runner { -        id: (EventsWith, f), -        spawn: move |events| { -            use futures::future; -            use futures::stream::StreamExt; - -            events.filter_map(move |(event, status)| { -                future::ready(match event { -                    Event::Window(window::Event::RedrawRequested(_)) => None, -                    _ => f(event, status), -                }) -            }) -        }, -    }) -} - -/// Returns a [`Subscription`] that produces a message for every runtime event, -/// including the redraw request events. -/// -/// **Warning:** This [`Subscription`], if unfiltered, may produce messages in -/// an infinite loop. -pub fn raw_events<Message>( -    f: fn(Event, event::Status) -> Option<Message>, -) -> Subscription<Message> -where -    Message: 'static + MaybeSend, -{ -    #[derive(Hash)] -    struct RawEvents; - -    Subscription::from_recipe(Runner { -        id: (RawEvents, f), -        spawn: move |events| { -            use futures::future; -            use futures::stream::StreamExt; - -            events.filter_map(move |(event, status)| { -                future::ready(f(event, status)) -            }) -        }, -    }) -} -  /// Returns a [`Subscription`] that will call the given function to create and  /// asynchronously run the given [`Stream`].  pub fn run<S, Message>(builder: fn() -> S) -> Subscription<Message> @@ -338,6 +264,25 @@ where      )  } +pub(crate) fn filter_map<I, F, Message>(id: I, f: F) -> Subscription<Message> +where +    I: Hash + 'static, +    F: Fn(Event, event::Status) -> Option<Message> + MaybeSend + 'static, +    Message: 'static + MaybeSend, +{ +    Subscription::from_recipe(Runner { +        id, +        spawn: |events| { +            use futures::future; +            use futures::stream::StreamExt; + +            events.filter_map(move |(event, status)| { +                future::ready(f(event, status)) +            }) +        }, +    }) +} +  /// Creates a [`Subscription`] that publishes the events sent from a [`Future`]  /// to an [`mpsc::Sender`] with the given bounds.  /// diff --git a/futures/src/subscription/tracker.rs b/futures/src/subscription/tracker.rs index ae71cd25..3a83da09 100644 --- a/futures/src/subscription/tracker.rs +++ b/futures/src/subscription/tracker.rs @@ -14,6 +14,8 @@ use std::hash::Hasher as _;  /// 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. +/// +/// [`Subscription`]: crate::Subscription  #[derive(Debug, Default)]  pub struct Tracker {      subscriptions: HashMap<u64, Execution>, @@ -51,6 +53,7 @@ impl Tracker {      /// the [`Tracker`] changes.      ///      /// [`Recipe`]: crate::subscription::Recipe +    /// [`Subscription`]: crate::Subscription      pub fn update<Message, Receiver>(          &mut self,          recipes: impl Iterator<Item = Box<dyn Recipe<Output = Message>>>, | 
