mediator_sys/mediator/asynchronous/contextaware/
builder.rs

1use async_std::sync::Mutex;
2
3use crate::mediator::{
4    asynchronous::{
5        basic::basic::BasicAsyncMediator,
6        contextaware::{
7            contextaware::CxAwareAsyncMediator, interface::CxAwareMediatorBuilderInterface,
8        },
9    },
10    builder::{TryBuilderFlow, TryBuilderInternal},
11    listener::Listener,
12    synchronous::basic::{basic::BasicMediator, interface::BasicMediatorBuilderInterface},
13};
14use std::{fmt::Debug, sync::mpsc::channel};
15
16/// The [`CxAwareAsyncBuilder`] helps you to create a [`CxAwareAsyncMediator`].
17///
18/// The [`CxAwareAsyncBuilder`] is part of the builder pattern.
19/// It has three functionalities. The first one is adding a [`Listener`] via
20/// [`CxAwareAsyncBuilder::add_listener()`].
21/// Secondly, a dependency `Dep` can be added via [`CxAwareAsyncBuilder::add_dependency()`].
22/// This must be done in order to receive a [`CxAwareAsyncMediator`] from [`TryBuilderFlow::build()`].
23/// The third functionality is the mandatory [`TryBuilderFlow::build()`], which returns
24/// a [`Result`] of type [`Result<CxAwareAsyncMediator<Dep, Ev>, Self::Error>`].
25///
26pub struct CxAwareAsyncBuilder<Dep, Ev>
27where
28    Dep: Debug,
29    Ev: Debug,
30{
31    mediator: BasicMediator<Ev>,
32    dep: Option<Dep>,
33}
34
35impl<Dep, Ev> TryBuilderInternal<CxAwareAsyncMediator<Dep, Ev>, CxAwareAsyncBuilder<Dep, Ev>>
36    for CxAwareAsyncMediator<Dep, Ev>
37where
38    Dep: Debug,
39    Ev: Debug,
40{
41    /// Creates a [`CxAwareAsyncBuilder`] with the goal of producing a [`CxAwareAsyncMediator`].
42    ///
43    fn builder() -> CxAwareAsyncBuilder<Dep, Ev> {
44        CxAwareAsyncBuilder::<Dep, Ev> {
45            mediator: BasicMediator::<Ev> {
46                channel: channel(),
47                listener: vec![],
48            },
49            dep: None,
50        }
51    }
52}
53
54impl<M, Dep, Ev> BasicMediatorBuilderInterface<M, Ev> for CxAwareAsyncBuilder<Dep, Ev>
55where
56    Dep: Debug,
57    Ev: Debug,
58{
59    /// Adds a user-defined listener to the [`CxAwareAsyncBuilder`].
60    ///
61    /// To be able to supply a closure that implements [`Listener`],
62    /// it must satisfy [`Send`] and `'static` bounds.
63    ///
64    /// Also it must be a `Fn(Ev)` with a return type of `()`
65    /// where `Ev` is the user-defined event type
66    /// that must be [`Clone`] and [`Debug`].
67    ///
68    fn add_listener<F>(mut self, f: F) -> Self
69    where
70        F: Listener<Ev>,
71    {
72        self.mediator.listener.push(Box::new(f));
73        self
74    }
75}
76
77impl<M, Dep, Ev> CxAwareMediatorBuilderInterface<M, Dep, Ev> for CxAwareAsyncBuilder<Dep, Ev>
78where
79    Dep: Debug,
80    Ev: Debug,
81{
82    /// Adds a user-defined dependency of type `Dep` to the [`CxAwareAsyncBuilder`].
83    ///
84    /// The dependency will act as a context and become available in [`super::CxAwareAsyncRequestHandler::handle()`].
85    ///
86    fn add_dependency(mut self, dep: Dep) -> Self
87    where
88        Ev: Debug,
89    {
90        self.dep = Some(dep);
91        self
92    }
93}
94
95impl<Dep, Ev> CxAwareAsyncBuilder<Dep, Ev>
96where
97    Dep: Debug,
98    Ev: Debug,
99{
100    /// Adds a user-defined listener to the [`CxAwareAsyncBuilder`].
101    ///
102    /// The supplied type must be a [`Listener`].
103    /// As such, it must implement [`Send`] and `Fn(Ev)`,
104    /// besides being `'static`.
105    ///
106    /// As a side note, here, `Ev` is the user-defined event type
107    /// that must be [`Clone`] and [`Debug`].
108    ///
109    /// Note: The following example will add a [`Listener`] to the builder,
110    /// but the result of `.build()` here will be an `Err` value.
111    /// This is because in order to receive a valid [`CxAwareAsyncMediator`]
112    /// you need to add a dependency. See [`CxAwareAsyncBuilder::add_dependency()`].
113    ///
114    /// # Examples
115    ///
116    /// Basic usage:
117    ///
118    /// ```
119    /// use mediator_sys::asynchronous::contextaware::*;
120    /// use std::sync::Arc;
121    ///
122    /// #[derive(Debug, Clone)]
123    /// enum MyEvent {
124    ///     One,
125    ///     Two
126    /// }
127    ///
128    /// #[derive(Debug, Default)]
129    /// struct MyContext(Arc<u32>);
130    ///
131    /// let mediator = CxAwareAsyncMediator::<MyContext, MyEvent>::builder()
132    ///     .add_listener(|ev| {
133    ///         /* Your listening logic */
134    ///     })
135    ///     .build();
136    ///
137    pub fn add_listener<F>(self, f: F) -> Self
138    where
139        F: Listener<Ev>,
140    {
141        <Self as BasicMediatorBuilderInterface<CxAwareAsyncMediator<Dep, Ev>, Ev>>::add_listener(
142            self, f,
143        )
144    }
145
146    /// Adds a user-defined dependency of type `Dep` to the [`CxAwareAsyncBuilder`].
147    ///
148    /// The dependency will act as a context and become available in [`super::CxAwareAsyncRequestHandler::handle()`].
149    ///
150    /// # Examples
151    ///
152    /// Basic usage:
153    ///
154    /// ```
155    /// use mediator_sys::asynchronous::contextaware::*;
156    /// use std::sync::Arc;
157    ///
158    /// #[derive(Debug, Clone)]
159    /// enum MyEvent {
160    ///     One,
161    ///     Two
162    /// }
163    ///
164    /// #[derive(Debug, Default)]
165    /// struct MyContext(Arc<u32>);
166    ///
167    /// let mediator = CxAwareAsyncMediator::<MyContext, MyEvent>::builder()
168    ///     .add_dependency(MyContext::default())
169    ///     .build();
170    ///
171    pub fn add_dependency(self, dep: Dep) -> Self {
172        <Self as CxAwareMediatorBuilderInterface<CxAwareAsyncMediator<Dep, Ev>, Dep, Ev>>::add_dependency(self, dep)
173    }
174}
175
176#[derive(Debug)]
177pub struct NoCxAvailable;
178
179impl<Dep, Ev> TryBuilderFlow<CxAwareAsyncMediator<Dep, Ev>> for CxAwareAsyncBuilder<Dep, Ev>
180where
181    Dep: Debug,
182    Ev: Debug,
183{
184    type Error = NoCxAvailable;
185    /// Builds the [`CxAwareAsyncMediator`] and returns it.
186    ///
187    /// Because [`CxAwareAsyncMediator`] implements [`TryBuilderInternal`],
188    /// which in turn means, that the [`CxAwareAsyncBuilder`] implements [`TryBuilderFlow`]
189    /// this method will return a [`Result<CxAwareAsyncMediator<Dep, Ev>, Self::Error>`] as stated by the return type.
190    /// Note that here `Self::Error` is of type [`NoCxAvailable`], which means that no dependecy was added in
191    /// the process of building.
192    ///
193    fn build(self) -> Result<CxAwareAsyncMediator<Dep, Ev>, Self::Error> {
194        Ok(CxAwareAsyncMediator {
195            basic: BasicAsyncMediator {
196                basic: Mutex::new(self.mediator),
197            },
198            dep: Mutex::new(self.dep.ok_or(NoCxAvailable)?),
199        })
200    }
201}