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}