Skip to content

Commit

Permalink
Converge Command types from iced_futures and iced_native
Browse files Browse the repository at this point in the history
  • Loading branch information
hecrj committed Mar 5, 2023
1 parent 43414bb commit 8af69be
Show file tree
Hide file tree
Showing 9 changed files with 161 additions and 266 deletions.
116 changes: 115 additions & 1 deletion core/src/widget/operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::widget::Id;

use std::any::Any;
use std::fmt;
use std::rc::Rc;

/// A piece of logic that can traverse the widget tree of an application in
/// order to query or update some widget state.
Expand Down Expand Up @@ -68,9 +69,122 @@ where
}
}

/// Maps the output of an [`Operation`] using the given function.
pub fn map<A, B>(
operation: Box<dyn Operation<A>>,
f: impl Fn(A) -> B + 'static,
) -> impl Operation<B>
where
A: 'static,
B: 'static,
{
#[allow(missing_debug_implementations)]
struct Map<A, B> {
operation: Box<dyn Operation<A>>,
f: Rc<dyn Fn(A) -> B>,
}

impl<A, B> Operation<B> for Map<A, B>
where
A: 'static,
B: 'static,
{
fn container(
&mut self,
id: Option<&Id>,
operate_on_children: &mut dyn FnMut(&mut dyn Operation<B>),
) {
struct MapRef<'a, A> {
operation: &'a mut dyn Operation<A>,
}

impl<'a, A, B> Operation<B> for MapRef<'a, A> {
fn container(
&mut self,
id: Option<&Id>,
operate_on_children: &mut dyn FnMut(&mut dyn Operation<B>),
) {
let Self { operation, .. } = self;

operation.container(id, &mut |operation| {
operate_on_children(&mut MapRef { operation });
});
}

fn scrollable(
&mut self,
state: &mut dyn Scrollable,
id: Option<&Id>,
) {
self.operation.scrollable(state, id);
}

fn focusable(
&mut self,
state: &mut dyn Focusable,
id: Option<&Id>,
) {
self.operation.focusable(state, id);
}

fn text_input(
&mut self,
state: &mut dyn TextInput,
id: Option<&Id>,
) {
self.operation.text_input(state, id);
}

fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) {
self.operation.custom(state, id);
}
}

let Self { operation, .. } = self;

MapRef {
operation: operation.as_mut(),
}
.container(id, operate_on_children);
}

fn focusable(&mut self, state: &mut dyn Focusable, id: Option<&Id>) {
self.operation.focusable(state, id);
}

fn scrollable(&mut self, state: &mut dyn Scrollable, id: Option<&Id>) {
self.operation.scrollable(state, id);
}

fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) {
self.operation.text_input(state, id);
}

fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) {
self.operation.custom(state, id);
}

fn finish(&self) -> Outcome<B> {
match self.operation.finish() {
Outcome::None => Outcome::None,
Outcome::Some(output) => Outcome::Some((self.f)(output)),
Outcome::Chain(next) => Outcome::Chain(Box::new(Map {
operation: next,
f: self.f.clone(),
})),
}
}
}

Map {
operation,
f: Rc::new(f),
}
}

/// Produces an [`Operation`] that applies the given [`Operation`] to the
/// children of a container with the given [`Id`].
pub fn scoped<T: 'static>(
pub fn scope<T: 'static>(
target: Id,
operation: impl Operation<T> + 'static,
) -> impl Operation<T> {
Expand Down
70 changes: 0 additions & 70 deletions futures/src/command.rs

This file was deleted.

2 changes: 0 additions & 2 deletions futures/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,13 @@
pub use futures;
pub use iced_core as core;

mod command;
mod maybe_send;
mod runtime;

pub mod backend;
pub mod executor;
pub mod subscription;

pub use command::Command;
pub use executor::Executor;
pub use maybe_send::MaybeSend;
pub use platform::*;
Expand Down
59 changes: 40 additions & 19 deletions native/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,39 @@ mod action;

pub use action::Action;

use crate::widget;

use iced_futures::MaybeSend;
use crate::core::widget;
use crate::futures::MaybeSend;

use std::fmt;
use std::future::Future;

/// A set of asynchronous actions to be performed by some runtime.
#[must_use = "`Command` must be returned to runtime to take effect"]
pub struct Command<T>(iced_futures::Command<Action<T>>);
pub struct Command<T>(Internal<Action<T>>);

#[derive(Debug)]
enum Internal<T> {
None,
Single(T),
Batch(Vec<T>),
}

impl<T> Command<T> {
/// Creates an empty [`Command`].
///
/// In other words, a [`Command`] that does nothing.
pub const fn none() -> Self {
Self(iced_futures::Command::none())
Self(Internal::None)
}

/// Creates a [`Command`] that performs a single [`Action`].
pub const fn single(action: Action<T>) -> Self {
Self(iced_futures::Command::single(action))
Self(Internal::Single(action))
}

/// Creates a [`Command`] that performs a [`widget::Operation`].
pub fn widget(
operation: impl iced_core::widget::Operation<T> + 'static,
) -> Self {
Self(iced_futures::Command::single(Action::Widget(
widget::Action::new(operation),
)))
pub fn widget(operation: impl widget::Operation<T> + 'static) -> Self {
Self::single(Action::Widget(Box::new(operation)))
}

/// Creates a [`Command`] that performs the action of the given future.
Expand All @@ -51,9 +53,17 @@ impl<T> Command<T> {
///
/// Once this command is run, all the commands will be executed at once.
pub fn batch(commands: impl IntoIterator<Item = Command<T>>) -> Self {
Self(iced_futures::Command::batch(
commands.into_iter().map(|Command(command)| command),
))
let mut batch = Vec::new();

for Command(command) in commands {
match command {
Internal::None => {}
Internal::Single(command) => batch.push(command),
Internal::Batch(commands) => batch.extend(commands),
}
}

Self(Internal::Batch(batch))
}

/// Applies a transformation to the result of a [`Command`].
Expand All @@ -65,16 +75,27 @@ impl<T> Command<T> {
T: 'static,
A: 'static,
{
let Command(command) = self;

Command(command.map(move |action| action.map(f.clone())))
match self.0 {
Internal::None => Command::none(),
Internal::Single(action) => Command::single(action.map(f)),
Internal::Batch(batch) => Command(Internal::Batch(
batch
.into_iter()
.map(|action| action.map(f.clone()))
.collect(),
)),
}
}

/// Returns all of the actions of the [`Command`].
pub fn actions(self) -> Vec<Action<T>> {
let Command(command) = self;

command.actions()
match command {
Internal::None => Vec::new(),
Internal::Single(action) => vec![action],
Internal::Batch(batch) => batch,
}
}
}

Expand Down
8 changes: 5 additions & 3 deletions native/src/command/action.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::clipboard;
use crate::core::widget;
use crate::font;
use crate::system;
use crate::widget;
use crate::window;

use iced_futures::MaybeSend;
Expand All @@ -28,7 +28,7 @@ pub enum Action<T> {
System(system::Action<T>),

/// Run a widget action.
Widget(widget::Action<T>),
Widget(Box<dyn widget::Operation<T>>),

/// Load a font from its bytes.
LoadFont {
Expand Down Expand Up @@ -59,7 +59,9 @@ impl<T> Action<T> {
Self::Clipboard(action) => Action::Clipboard(action.map(f)),
Self::Window(window) => Action::Window(window.map(f)),
Self::System(system) => Action::System(system.map(f)),
Self::Widget(widget) => Action::Widget(widget.map(f)),
Self::Widget(operation) => {
Action::Widget(Box::new(widget::operation::map(operation, f)))
}
Self::LoadFont { bytes, tagger } => Action::LoadFont {
bytes,
tagger: Box::new(move |result| f(tagger(result))),
Expand Down
1 change: 0 additions & 1 deletion native/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ pub mod keyboard;
pub mod program;
pub mod system;
pub mod user_interface;
pub mod widget;
pub mod window;

// We disable debug capabilities on release builds unless the `debug` feature
Expand Down
16 changes: 0 additions & 16 deletions native/src/widget.rs

This file was deleted.

Loading

0 comments on commit 8af69be

Please sign in to comment.