rsiot/components/cmp_external_fn_process/mod.rs
1//! Тестирование документации:
2//!
3//! ```bash
4//! cargo test components::cmp_external_fn_process --features="executor" --target="x86_64-unknown-linux-gnu";
5//! cargo test --doc components::cmp_external_fn_process --features="executor" --target="x86_64-unknown-linux-gnu";
6//!
7//! cargo test components::cmp_external_fn_process --features="executor, single-thread" --target="x86_64-unknown-linux-gnu";
8//! cargo test --doc components::cmp_external_fn_process --features="executor, single-thread" --target="x86_64-unknown-linux-gnu";
9//! ```
10
11use async_trait::async_trait;
12
13#[cfg(feature = "single-thread")]
14pub use futures::future::LocalBoxFuture;
15
16#[cfg(not(feature = "single-thread"))]
17pub use futures::future::BoxFuture;
18
19use crate::{
20 executor::{CmpInOut, CmpResult, Component, ComponentError, IComponentProcess},
21 message::*,
22};
23
24#[cfg(feature = "single-thread")]
25type FnProcess<TMsg> = Box<dyn Fn(CmpInOut<TMsg>) -> LocalBoxFuture<'static, CmpResult>>;
26
27#[cfg(not(feature = "single-thread"))]
28type FnProcess<TMsg> = Box<dyn Fn(CmpInOut<TMsg>) -> BoxFuture<'static, CmpResult> + Send + Sync>;
29
30/// Настройки cmp_external_fn_process
31pub struct Config<TMsg>
32where
33 TMsg: MsgDataBound,
34{
35 /// Внешняя функция для выполнения
36 ///
37 /// Выполняемую асинхронную функцию `fn_external` необходимо обернуть в функцию.
38 ///
39 /// # Пример
40 ///
41 /// ```rust
42 /// use std::time::Duration;
43 ///
44 /// use futures::future::LocalBoxFuture;
45 /// use tokio::time::sleep;
46 /// use tracing::info;
47 ///
48 /// use rsiot::{
49 /// components::cmp_external_fn_process,
50 /// executor::{CmpInOut, ComponentResult},
51 /// message::{example_message::*, *},
52 /// };
53 ///
54 /// fn fn_process_wrapper<TMsg>(
55 /// in_out: CmpInOut<TMsg>,
56 /// ) -> LocalBoxFuture<'static, ComponentResult>
57 /// where
58 /// TMsg: MsgDataBound + 'static,
59 /// {
60 /// Box::pin(async { fn_process(in_out).await })
61 /// }
62 /// async fn fn_process<TMsg>(_in_out: CmpInOut<TMsg>) -> ComponentResult {
63 /// loop {
64 /// info!("External fn process");
65 /// sleep(Duration::from_secs(2)).await;
66 /// }
67 /// }
68 ///
69 /// let _config = cmp_external_fn_process::Config {
70 /// fn_process: Box::new(fn_process_wrapper::<Custom>),
71 /// };
72 /// # // insert-end
73 /// ```
74 #[cfg(feature = "single-thread")]
75 pub fn_process: FnProcess<TMsg>,
76
77 /// Внешняя функция для выполнения
78 ///
79 /// Выполняемую асинхронную функцию `fn_external` необходимо обернуть в функцию.
80 ///
81 /// # Пример
82 ///
83 /// ```rust
84 /// # // insert-start test multi_thread
85 /// use std::time::Duration;
86 ///
87 /// use futures::future::BoxFuture;
88 /// use tokio::time::sleep;
89 /// use tracing::info;
90 ///
91 /// use rsiot::{
92 /// components::cmp_external_fn_process,
93 /// executor::{CmpInOut, ComponentResult},
94 /// message::{example_message::*, *},
95 /// };
96 ///
97 /// fn fn_process_wrapper<TMsg>(in_out: CmpInOut<TMsg>) -> BoxFuture<'static, ComponentResult>
98 /// where
99 /// TMsg: MsgDataBound + 'static,
100 /// {
101 /// Box::pin(async { fn_process(in_out).await })
102 /// }
103 ///
104 /// async fn fn_process<TMsg>(_in_out: CmpInOut<TMsg>) -> ComponentResult {
105 /// loop {
106 /// info!("External fn process");
107 /// sleep(Duration::from_secs(2)).await;
108 /// }
109 /// }
110 ///
111 /// let _config = cmp_external_fn_process::Config {
112 /// fn_process: Box::new(fn_process_wrapper::<Custom>),
113 /// };
114 /// # // insert-end
115 /// ```
116 #[cfg(not(feature = "single-thread"))]
117 pub fn_process: FnProcess<TMsg>,
118}
119
120#[cfg_attr(not(feature = "single-thread"), async_trait)]
121#[cfg_attr(feature = "single-thread", async_trait(?Send))]
122#[async_trait(?Send)]
123impl<TMsg> IComponentProcess<Config<TMsg>, TMsg> for Component<Config<TMsg>, TMsg>
124where
125 TMsg: MsgDataBound,
126{
127 async fn process(
128 &self,
129 config: Config<TMsg>,
130 in_out: CmpInOut<TMsg>,
131 ) -> Result<(), ComponentError> {
132 (config.fn_process)(
133 in_out.clone_with_new_id("cmp_extrenal_fn_process", AuthPermissions::FullAccess),
134 )
135 .await
136 }
137}
138
139/// Компонент cmp_external_fn_process
140pub type Cmp<TMsg> = Component<Config<TMsg>, TMsg>;
141
142#[cfg(test)]
143mod tests {
144
145 #[cfg(feature = "single-thread")]
146 #[cfg(not(target_arch = "wasm32"))]
147 #[test]
148 fn single_thread() {
149 use std::time::Duration;
150
151 use futures::future::LocalBoxFuture;
152
153 #[cfg(target_arch = "wasm32")]
154 use gloo::timers::future::sleep;
155 #[cfg(not(target_arch = "wasm32"))]
156 use tokio::time::sleep;
157
158 use tracing::info;
159
160 use crate::{
161 components::cmp_external_fn_process,
162 executor::{CmpInOut, CmpResult},
163 message::{example_message::*, *},
164 };
165
166 fn fn_process_wrapper<TMsg>(in_out: CmpInOut<TMsg>) -> LocalBoxFuture<'static, CmpResult>
167 where
168 TMsg: MsgDataBound + 'static,
169 {
170 Box::pin(async { fn_process(in_out).await })
171 }
172 async fn fn_process<TMsg>(_in_out: CmpInOut<TMsg>) -> CmpResult
173 where
174 TMsg: MsgDataBound,
175 {
176 loop {
177 info!("External fn process");
178 sleep(Duration::from_secs(2)).await;
179 }
180 }
181
182 let _config = cmp_external_fn_process::Config {
183 fn_process: Box::new(fn_process_wrapper::<Custom>),
184 };
185 }
186
187 #[cfg(not(feature = "single-thread"))]
188 #[test]
189 fn multi_thread() {
190 use std::time::Duration;
191
192 use futures::future::BoxFuture;
193 use tokio::time::sleep;
194 use tracing::info;
195
196 use crate::{
197 components::cmp_external_fn_process,
198 executor::{CmpInOut, CmpResult},
199 message::{example_message::*, *},
200 };
201
202 fn fn_process_wrapper<TMsg>(in_out: CmpInOut<TMsg>) -> BoxFuture<'static, CmpResult>
203 where
204 TMsg: MsgDataBound + 'static,
205 {
206 Box::pin(async { fn_process(in_out).await })
207 }
208
209 async fn fn_process<TMsg>(_in_out: CmpInOut<TMsg>) -> CmpResult
210 where
211 TMsg: MsgDataBound + 'static,
212 {
213 loop {
214 info!("External fn process");
215 sleep(Duration::from_secs(2)).await;
216 }
217 }
218
219 let _config = cmp_external_fn_process::Config {
220 fn_process: Box::new(fn_process_wrapper::<Custom>),
221 };
222 }
223}