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}