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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
use async_std::sync::Mutex;

use crate::mediator::{
    asynchronous::{
        basic::basic::BasicAsyncMediator,
        contextaware::{
            contextaware::CxAwareAsyncMediator, interface::CxAwareMediatorBuilderInterface,
        },
    },
    builder::{TryBuilderFlow, TryBuilderInternal},
    listener::Listener,
    synchronous::basic::{basic::BasicMediator, interface::BasicMediatorBuilderInterface},
};
use std::{fmt::Debug, sync::mpsc::channel};

/// The [`CxAwareAsyncBuilder`] helps you to create a [`CxAwareAsyncMediator`].
///
/// The [`CxAwareAsyncBuilder`] is part of the builder pattern.
/// It has three functionalities. The first one is adding a [`Listener`] via
/// [`CxAwareAsyncBuilder::add_listener()`].
/// Secondly, a dependency `Dep` can be added via [`CxAwareAsyncBuilder::add_dependency()`].
/// This must be done in order to receive a [`CxAwareAsyncMediator`] from [`TryBuilderFlow::build()`].
/// The third functionality is the mandatory [`TryBuilderFlow::build()`], which returns
/// a [`Result`] of type [`Result<CxAwareAsyncMediator<Dep, Ev>, Self::Error>`].
///
pub struct CxAwareAsyncBuilder<Dep, Ev>
where
    Dep: Debug,
    Ev: Debug,
{
    mediator: BasicMediator<Ev>,
    dep: Option<Dep>,
}

impl<Dep, Ev> TryBuilderInternal<CxAwareAsyncMediator<Dep, Ev>, CxAwareAsyncBuilder<Dep, Ev>>
    for CxAwareAsyncMediator<Dep, Ev>
where
    Dep: Debug,
    Ev: Debug,
{
    /// Creates a [`CxAwareAsyncBuilder`] with the goal of producing a [`CxAwareAsyncMediator`].
    ///
    fn builder() -> CxAwareAsyncBuilder<Dep, Ev> {
        CxAwareAsyncBuilder::<Dep, Ev> {
            mediator: BasicMediator::<Ev> {
                channel: channel(),
                listener: vec![],
            },
            dep: None,
        }
    }
}

impl<M, Dep, Ev> BasicMediatorBuilderInterface<M, Ev> for CxAwareAsyncBuilder<Dep, Ev>
where
    Dep: Debug,
    Ev: Debug,
{
    /// Adds a user-defined listener to the [`CxAwareAsyncBuilder`].
    ///
    /// To be able to supply a closure that implements [`Listener`],
    /// it must satisfy [`Send`] and `'static` bounds.
    ///
    /// Also it must be a `Fn(Ev)` with a return type of `()`
    /// where `Ev` is the user-defined event type
    /// that must be [`Clone`] and [`Debug`].
    ///
    fn add_listener<F>(mut self, f: F) -> Self
    where
        F: Listener<Ev>,
    {
        self.mediator.listener.push(Box::new(f));
        self
    }
}

impl<M, Dep, Ev> CxAwareMediatorBuilderInterface<M, Dep, Ev> for CxAwareAsyncBuilder<Dep, Ev>
where
    Dep: Debug,
    Ev: Debug,
{
    /// Adds a user-defined dependency of type `Dep` to the [`CxAwareAsyncBuilder`].
    ///
    /// The dependency will act as a context and become available in [`super::CxAwareAsyncRequestHandler::handle()`].
    ///
    fn add_dependency(mut self, dep: Dep) -> Self
    where
        Ev: Debug,
    {
        self.dep = Some(dep);
        self
    }
}

impl<Dep, Ev> CxAwareAsyncBuilder<Dep, Ev>
where
    Dep: Debug,
    Ev: Debug,
{
    /// Adds a user-defined listener to the [`CxAwareAsyncBuilder`].
    ///
    /// The supplied type must be a [`Listener`].
    /// As such, it must implement [`Send`] and `Fn(Ev)`,
    /// besides being `'static`.
    ///
    /// As a side note, here, `Ev` is the user-defined event type
    /// that must be [`Clone`] and [`Debug`].
    ///
    /// Note: The following example will add a [`Listener`] to the builder,
    /// but the result of `.build()` here will be an `Err` value.
    /// This is because in order to receive a valid [`CxAwareAsyncMediator`]
    /// you need to add a dependency. See [`CxAwareAsyncBuilder::add_dependency()`].
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use mediator_sys::asynchronous::contextaware::*;
    /// use std::sync::Arc;
    ///
    /// #[derive(Debug, Clone)]
    /// enum MyEvent {
    ///     One,
    ///     Two
    /// }
    ///
    /// #[derive(Debug, Default)]
    /// struct MyContext(Arc<u32>);
    ///
    /// let mediator = CxAwareAsyncMediator::<MyContext, MyEvent>::builder()
    ///     .add_listener(|ev| {
    ///         /* Your listening logic */
    ///     })
    ///     .build();
    ///
    pub fn add_listener<F>(self, f: F) -> Self
    where
        F: Listener<Ev>,
    {
        <Self as BasicMediatorBuilderInterface<CxAwareAsyncMediator<Dep, Ev>, Ev>>::add_listener(
            self, f,
        )
    }

    /// Adds a user-defined dependency of type `Dep` to the [`CxAwareAsyncBuilder`].
    ///
    /// The dependency will act as a context and become available in [`super::CxAwareAsyncRequestHandler::handle()`].
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use mediator_sys::asynchronous::contextaware::*;
    /// use std::sync::Arc;
    ///
    /// #[derive(Debug, Clone)]
    /// enum MyEvent {
    ///     One,
    ///     Two
    /// }
    ///
    /// #[derive(Debug, Default)]
    /// struct MyContext(Arc<u32>);
    ///
    /// let mediator = CxAwareAsyncMediator::<MyContext, MyEvent>::builder()
    ///     .add_dependency(MyContext::default())
    ///     .build();
    ///
    pub fn add_dependency(self, dep: Dep) -> Self {
        <Self as CxAwareMediatorBuilderInterface<CxAwareAsyncMediator<Dep, Ev>, Dep, Ev>>::add_dependency(self, dep)
    }
}

#[derive(Debug)]
pub struct NoCxAvailable;

impl<Dep, Ev> TryBuilderFlow<CxAwareAsyncMediator<Dep, Ev>> for CxAwareAsyncBuilder<Dep, Ev>
where
    Dep: Debug,
    Ev: Debug,
{
    type Error = NoCxAvailable;
    /// Builds the [`CxAwareAsyncMediator`] and returns it.
    ///
    /// Because [`CxAwareAsyncMediator`] implements [`TryBuilderInternal`],
    /// which in turn means, that the [`CxAwareAsyncBuilder`] implements [`TryBuilderFlow`]
    /// this method will return a [`Result<CxAwareAsyncMediator<Dep, Ev>, Self::Error>`] as stated by the return type.
    /// Note that here `Self::Error` is of type [`NoCxAvailable`], which means that no dependecy was added in
    /// the process of building.
    ///
    fn build(self) -> Result<CxAwareAsyncMediator<Dep, Ev>, Self::Error> {
        Ok(CxAwareAsyncMediator {
            basic: BasicAsyncMediator {
                basic: Mutex::new(self.mediator),
            },
            dep: Mutex::new(self.dep.ok_or(NoCxAvailable)?),
        })
    }
}