summaryrefslogtreecommitdiffstats
path: root/native/src/widget/action.rs
blob: 766e902b7066b31ab45fc63e242d60f2afc6f076 (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
78
79
80
81
82
83
84
85
86
87
88
use crate::widget::operation::{self, Operation};
use crate::widget::Id;

use iced_futures::MaybeSend;

/// An operation to be performed on the widget tree.
#[allow(missing_debug_implementations)]
pub struct Action<T>(Box<dyn Operation<T>>);

impl<T> Action<T> {
    /// Creates a new [`Action`] with the given [`Operation`].
    pub fn new(operation: impl Operation<T> + 'static) -> Self {
        Self(Box::new(operation))
    }

    /// Maps the output of an [`Action`] using the given function.
    pub fn map<A>(
        self,
        f: impl Fn(T) -> A + 'static + MaybeSend + Sync,
    ) -> Action<A>
    where
        T: 'static,
        A: 'static,
    {
        Action(Box::new(Map {
            operation: self.0,
            f: Box::new(f),
        }))
    }

    /// Consumes the [`Action`] and returns the internal [`Operation`].
    pub fn into_operation(self) -> Box<dyn Operation<T>> {
        self.0
    }
}

#[allow(missing_debug_implementations)]
struct Map<A, B> {
    operation: Box<dyn Operation<A>>,
    f: Box<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, B> {
            operation: &'a mut dyn Operation<A>,
            f: &'a dyn Fn(A) -> B,
        }

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

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

        let Self { operation, f } = self;

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

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