zenoh/api/builders/
scouting.rs

1//
2// Copyright (c) 2024 ZettaScale Technology
3//
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7// which is available at https://www.apache.org/licenses/LICENSE-2.0.
8//
9// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10//
11// Contributors:
12//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>
13//
14
15use std::{
16    future::{IntoFuture, Ready},
17    sync::Arc,
18};
19
20use zenoh_config::wrappers::Hello;
21use zenoh_core::{Resolvable, Wait};
22use zenoh_protocol::core::WhatAmIMatcher;
23use zenoh_result::ZResult;
24
25use crate::api::{
26    handlers::{locked, Callback, DefaultHandler, IntoHandler},
27    scouting::{Scout, _scout},
28};
29
30/// A builder for initializing a [`Scout`].
31///
32/// # Examples
33/// ```no_run
34/// # #[tokio::main]
35/// # async fn main() {
36/// use zenoh::config::WhatAmI;
37///
38/// let receiver = zenoh::scout(WhatAmI::Peer | WhatAmI::Router, zenoh::Config::default())
39///     .await
40///     .unwrap();
41/// while let Ok(hello) = receiver.recv_async().await {
42///     println!("{}", hello);
43/// }
44/// # }
45/// ```
46#[must_use = "Resolvables do nothing unless you resolve them using `.await` or `zenoh::Wait::wait`"]
47#[derive(Debug)]
48pub struct ScoutBuilder<Handler> {
49    pub(crate) what: WhatAmIMatcher,
50    pub(crate) config: ZResult<crate::config::Config>,
51    pub(crate) handler: Handler,
52}
53
54impl ScoutBuilder<DefaultHandler> {
55    /// Receive the [`Hello`] messages from this scout with a callback.
56    ///
57    /// # Examples
58    /// ```
59    /// # #[tokio::main]
60    /// # async fn main() {
61    /// use zenoh::config::WhatAmI;
62    ///
63    /// let scout = zenoh::scout(WhatAmI::Peer | WhatAmI::Router, zenoh::Config::default())
64    ///     .callback(|hello| { println!("{}", hello); })
65    ///     .await
66    ///     .unwrap();
67    /// # }
68    /// ```
69    #[inline]
70    pub fn callback<F>(self, callback: F) -> ScoutBuilder<Callback<Hello>>
71    where
72        F: Fn(Hello) + Send + Sync + 'static,
73    {
74        self.with(Callback::new(Arc::new(callback)))
75    }
76
77    /// Receive the [`Hello`] messages from this scout with a mutable callback.
78    ///
79    /// Using this guarantees that your callback will never be called concurrently.
80    /// If your callback is also accepted by the [`callback`](ScoutBuilder::callback) method, we suggest you use it instead of `callback_mut`.
81    ///
82    /// # Examples
83    /// ```
84    /// # #[tokio::main]
85    /// # async fn main() {
86    /// use zenoh::config::WhatAmI;
87    ///
88    /// let mut n = 0;
89    /// let scout = zenoh::scout(WhatAmI::Peer | WhatAmI::Router, zenoh::Config::default())
90    ///     .callback_mut(move |_hello| { n += 1; })
91    ///     .await
92    ///     .unwrap();
93    /// # }
94    /// ```
95    #[inline]
96    pub fn callback_mut<F>(self, callback: F) -> ScoutBuilder<Callback<Hello>>
97    where
98        F: FnMut(Hello) + Send + Sync + 'static,
99    {
100        self.callback(locked(callback))
101    }
102
103    /// Receive the [`Hello`] messages from this scout with a [`Handler`](crate::handlers::IntoHandler).
104    ///
105    /// # Examples
106    /// ```no_run
107    /// # #[tokio::main]
108    /// # async fn main() {
109    /// use zenoh::config::WhatAmI;
110    ///
111    /// let receiver = zenoh::scout(WhatAmI::Peer | WhatAmI::Router, zenoh::Config::default())
112    ///     .with(flume::bounded(32))
113    ///     .await
114    ///     .unwrap();
115    /// while let Ok(hello) = receiver.recv_async().await {
116    ///     println!("{}", hello);
117    /// }
118    /// # }
119    /// ```
120    #[inline]
121    pub fn with<Handler>(self, handler: Handler) -> ScoutBuilder<Handler>
122    where
123        Handler: IntoHandler<Hello>,
124    {
125        let ScoutBuilder {
126            what,
127            config,
128            handler: _,
129        } = self;
130        ScoutBuilder {
131            what,
132            config,
133            handler,
134        }
135    }
136}
137
138impl<Handler> Resolvable for ScoutBuilder<Handler>
139where
140    Handler: IntoHandler<Hello> + Send,
141    Handler::Handler: Send,
142{
143    type To = ZResult<Scout<Handler::Handler>>;
144}
145
146impl<Handler> Wait for ScoutBuilder<Handler>
147where
148    Handler: IntoHandler<Hello> + Send,
149    Handler::Handler: Send,
150{
151    fn wait(self) -> <Self as Resolvable>::To {
152        let (callback, receiver) = self.handler.into_handler();
153        _scout(self.what, self.config?, callback).map(|scout| Scout { scout, receiver })
154    }
155}
156
157impl<Handler> IntoFuture for ScoutBuilder<Handler>
158where
159    Handler: IntoHandler<Hello> + Send,
160    Handler::Handler: Send,
161{
162    type Output = <Self as Resolvable>::To;
163    type IntoFuture = Ready<<Self as Resolvable>::To>;
164
165    fn into_future(self) -> Self::IntoFuture {
166        std::future::ready(self.wait())
167    }
168}