summaryrefslogtreecommitdiffstats
path: root/web/src/command.rs
blob: ff6965c16eb1647e0584278fde432e33dcea60c4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
mod action;

pub use action::Action;

#[cfg(target_arch = "wasm32")]
use std::future::Future;

/// A set of asynchronous actions to be performed by some runtime.
pub enum Command<T> {
    None,
    Single(Action<T>),
    Batch(Vec<Action<T>>),
}

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

    /// Creates a [`Command`] that performs the action of the given future.
    #[cfg(target_arch = "wasm32")]
    pub fn perform<A>(
        future: impl Future<Output = T> + 'static,
        f: impl Fn(T) -> A + 'static + Send,
    ) -> Command<A> {
        use iced_futures::futures::FutureExt;

        Command::Single(Action::Future(Box::pin(future.map(f))))
    }

    /// Applies a transformation to the result of a [`Command`].
    #[cfg(target_arch = "wasm32")]
    pub fn map<A>(self, f: impl Fn(T) -> A + 'static + Clone) -> Command<A>
    where
        T: 'static,
    {
        match self {
            Self::None => Command::None,
            Self::Single(action) => Command::Single(action.map(f)),
            Self::Batch(batch) => Command::Batch(
                batch
                    .into_iter()
                    .map(|action| action.map(f.clone()))
                    .collect(),
            ),
        }
    }

    /// Creates a [`Command`] that performs the actions of all the given
    /// commands.
    ///
    /// Once this command is run, all the commands will be executed at once.
    pub fn batch(commands: impl IntoIterator<Item = Command<T>>) -> Self {
        let mut batch = Vec::new();

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

        Self::Batch(batch)
    }

    pub fn actions(self) -> Vec<Action<T>> {
        match self {
            Self::None => Vec::new(),
            Self::Single(action) => vec![action],
            Self::Batch(batch) => batch,
        }
    }
}