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}