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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
//! Contains the [`Command`] interface used in the [`handler`] module by the
//! [`EventHandler`] trait.
//!
//! [`handler`]: crate::handler
//! [`EventHandler`]: crate::handler::EventHandler

use std::fmt::Debug;

use futures::{
    future,
    future::{Future, FutureExt},
};

pub type BoxFuture<T> = future::BoxFuture<'static, T>;

/// This struct contains code adapted from the [`Command`](https://github.com/iced-rs/iced/blob/0.3/futures/src/command.rs) struct written in the [iced](https://github.com/iced-rs/iced) library. It is currently identical to the aforementioned struct, however modifications will be made to fit our needs with time.
///
/// Kudos to Hecrj for his awesome system- I don't know where I'd be without it
pub struct Command<T>
where
    T: std::fmt::Debug + Send,
{
    to_be_performed: Vec<BoxFuture<T>>,
}

impl<T> Command<T>
where
    T: std::fmt::Debug + Send,
{
    /// Creates an empty [`Command`] that does not contain any futures.
    pub fn none() -> Self {
        Self {
            to_be_performed: Vec::new(),
        }
    }

    /// Creates a [`Command`] that executes the given future when run.
    pub fn perform<A: Debug + Send>(
        future: impl Future<Output = T> + Send + 'static,
        f: impl Fn(T) -> A + Send + 'static,
    ) -> Command<A> {
        Command {
            to_be_performed: vec![Box::pin(future.map(f))],
        }
    }

    /// Creates a [`Command`] that executes each future at once when run.
    pub fn perform_multiple(futures: impl IntoIterator<Item = Command<T>>) -> Self {
        Self {
            to_be_performed: futures
                .into_iter()
                .flat_map(|command| command.to_be_performed)
                .collect(),
        }
    }

    pub fn is_empty(&self) -> bool {
        self.to_be_performed.len() == 0
    }

    /// Transforms the result of a [`Command`].
    #[allow(clippy::redundant_closure)] // Known bug with Clippy
    pub fn map<A: Debug + Send>(mut self, f: impl Fn(T) -> A + 'static + Send + Sync) -> Command<A>
    where
        T: 'static,
    {
        let f = std::sync::Arc::new(f);

        Command {
            to_be_performed: self
                .to_be_performed
                .drain(..)
                .map(|future| {
                    let f = f.clone();

                    Box::pin(future.map(move |result| f(result))) as BoxFuture<A>
                })
                .collect(),
        }
    }

    /// Drops the current [`Command`] instance and returns its futures.
    pub fn into_futures(self) -> Vec<BoxFuture<T>> {
        self.to_be_performed
    }
}

impl<T, A> From<A> for Command<T>
where
    A: Future<Output = T> + Send + 'static,
    T: Debug + Send,
{
    fn from(future: A) -> Self {
        Self {
            to_be_performed: vec![future.boxed()],
        }
    }
}