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
use std::ops::DerefMut;

use crate::Effects;

/// `Reducer`s are responsible for updating a `Store`’s state in response to its `Action`s.
pub trait Reducer {
    /// All of the possible actions that can be used to modify state.
    type Action;

    /// Both unit tests and command line applications often need to return their `Store`’s final
    /// state. Therefore `Store`’s [`into_inner`] method shuts down the `Store` and converts its
    /// `Reducer` into its `Output` type.
    ///
    /// Using a separate `Output` type, rather than returning the `Reducer` itself, allows the
    /// `Store`s to support `Reducer` types that are not [`Send`].
    ///  
    /// - `Reducer`s that do not need to support [`into_inner`] should use declare
    ///   `type Output = Self;` as it is a simple, recognizable default.
    /// - A `Reducer` that _is_ `Send` can also default to `type Output = Self;`.
    /// - Otherwise, the `Reducer` will need to declare an `Output` type that _is_ `Send` and
    ///   that can be crated [`From`] the `Reducer`’s state.
    ///
    /// ```rust
    /// # use std::rc::Rc;
    /// # use std::cell::Cell;
    /// # use composable::{Effects, Reducer, Store};
    /// # #[derive(Default)]
    /// struct State {
    ///     n: Rc<Cell<usize>>, // Rc<Cell<…>> is not Send
    /// };
    ///
    /// enum Action { /* … */ }
    ///
    /// impl Reducer for State {
    ///     type Action = Action;
    ///     type Output = usize; // but the usize itself _is_
    ///
    ///     fn reduce(&mut self, action: Self::Action, send: impl Effects<Self::Action>) { /**/ }
    /// }
    ///
    /// impl From<State> for usize {
    ///     fn from(value: State) -> Self {
    ///         Cell::into_inner(Rc::into_inner(value.n).unwrap_or_default())
    ///     }
    /// }
    /// # let store = Store::<State>::default();
    /// ```
    ///
    /// [`into_inner`]: crate::Store::into_inner
    ///
    /// In short, you can use `type Output = Self;` until the compiler says that you can’t.
    type Output;

    /// Updates the `Reducer`’s state in response to the action received.
    ///
    /// Additional `Action`s that need to be performed as a side-effect of an `Action` should be
    /// [invoked][`crate::effects::Effects`] on `effects`.
    #[doc = include_str!("README.md")]
    fn reduce(&mut self, action: Self::Action, send: impl Effects<Self::Action>);
}

impl<T: Reducer> Reducer for Box<T> {
    type Action = T::Action;

    type Output = T::Output;

    fn reduce(&mut self, action: Self::Action, send: impl Effects<Self::Action>) {
        self.deref_mut().reduce(action, send)
    }
}

impl<T: Reducer> Reducer for Option<T> {
    type Action = T::Action;

    type Output = Option<T::Output>;

    fn reduce(&mut self, action: Self::Action, send: impl Effects<Self::Action>) {
        if let Some(state) = self {
            state.reduce(action, send)
        }
    }
}