zenoh_core/
macros.rs

1//
2// Copyright (c) 2023 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
15// This macro performs a standard lock on Mutex<T>
16// For performance reasons, it first performs a try_lock() and,
17// if it fails, it falls back on lock().unwrap()
18#[macro_export]
19macro_rules! zlock {
20    ($var:expr) => {
21        $var.lock().unwrap()
22    };
23}
24
25// This macro performs a standard read on RwLock<T>
26// For performance reasons, it first performs a try_read() and,
27// if it fails, it falls back on read()
28#[macro_export]
29macro_rules! zread {
30    ($var:expr) => {
31        $var.read().unwrap()
32    };
33}
34
35// This macro performs a standard write on RwLock<T>
36// For performance reasons, it first performs a try_write() and,
37// if it fails, it falls back on write()
38#[macro_export]
39macro_rules! zwrite {
40    ($var:expr) => {
41        $var.write().unwrap()
42    };
43}
44
45// This macro performs an async lock on Mutex<T>
46#[macro_export]
47macro_rules! zasynclock {
48    ($var:expr) => {
49        $var.lock().await
50    };
51}
52
53// This macro performs an async read on RwLock<T>
54// For performance reasons, it first performs a try_read() and,
55// if it fails, it falls back on read().await
56#[macro_export]
57macro_rules! zasyncread {
58    ($var:expr) => {
59        if let Ok(g) = $var.try_read() {
60            g
61        } else {
62            $var.read().await
63        }
64    };
65}
66
67// This macro performs an async write on RwLock<T>
68// For performance reasons, it first performs a try_write() and,
69// if it fails, it falls back on write().await
70#[macro_export]
71macro_rules! zasyncwrite {
72    ($var:expr) => {
73        if let Ok(g) = $var.try_write() {
74            g
75        } else {
76            $var.write().await
77        }
78    };
79}
80
81// This macro returns &T from RwLock<Option<T>>
82// This macro assumes that Option is always Some(T)
83#[macro_export]
84macro_rules! zasyncopt {
85    ($var:expr) => {
86        zasyncread!($var).as_ref().unwrap()
87    };
88}
89
90// This macro performs an async send on Channel<T>
91// For performance reasons, it first performs a try_send() and,
92// if it fails, it falls back on send().await
93#[macro_export]
94macro_rules! zasyncsend {
95    ($ch:expr, $var:expr) => {
96        if $ch.try_send($var).is_err() {
97            $ch.send($var).await;
98        }
99    };
100}
101
102// This macro performs an async recv on Channel<T>
103// For performance reasons, it first performs a try_recv() and,
104// if it fails, it falls back on recv().await
105#[macro_export]
106macro_rules! zasyncrecv {
107    ($ch:expr) => {
108        if let Ok(v) = $ch.try_recv() {
109            Ok(v)
110        } else {
111            $ch.recv().await
112        }
113    };
114}
115
116// This macro allows to define some compile time configurable static constants
117#[macro_export]
118macro_rules! zconfigurable {
119    ($(#[$attr:meta])* static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
120        $(#[$attr])* $crate::lazy_static!(static ref $N : $T = match option_env!(stringify!($N)) {
121            Some(value) => {value.parse().unwrap()}
122            None => {$e}
123        };) ;
124        $crate::zconfigurable!($($t)*);
125    };
126    ($(#[$attr:meta])* pub static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
127        $(#[$attr])* $crate::lazy_static!(pub static ref $N : $T = match option_env!(stringify!($N)) {
128            Some(value) => {value.parse().unwrap()}
129            None => {$e}
130        };) ;
131        $crate::zconfigurable!($($t)*);
132    };
133    ($(#[$attr:meta])* pub ($($vis:tt)+) static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
134        $(#[$attr])* $crate::lazy_static!(pub ($($vis)+) static ref $N : $T = match option_env!(stringify!($N)) {
135            Some(value) => {value.parse().unwrap()}
136            None => {$e}
137        };) ;
138        $crate::zconfigurable!($($t)*);
139    };
140    () => ()
141}
142
143// This macro is a shorthand for the conversion to u64
144// This macro requires to previously import the following:
145//   use std::convert::TryFrom;
146#[macro_export]
147macro_rules! to_u64 {
148    ($val:expr) => {
149        u64::try_from($val).unwrap_or_else(|_| {
150            panic!(
151                "Can not encode {} as u64 (max u64 value: {})",
152                $val,
153                u64::MAX
154            )
155        })
156    };
157}
158
159// This macro allows to spawn the right amount of threads in the
160// async_std executor
161#[macro_export]
162macro_rules! zasync_executor_init {
163    () => {
164        use async_global_executor;
165
166        // Zenoh requires at least 4 threads to run
167        const ASYNC_STD_THREAD_COUNT_MIN: usize = 4;
168
169        let count = async_global_executor::spawn_more_threads(ASYNC_STD_THREAD_COUNT_MIN)
170            .await
171            .unwrap();
172
173        tracing::trace!(
174            "Spawned {} additional threads in the async global executor",
175            count
176        );
177    };
178}
179
180// This macro allows to parse a string to the target type
181#[macro_export]
182macro_rules! zparse {
183    ($str:expr) => {
184        $str.parse().map_err(|_| {
185            let e = zenoh_result::zerror!(
186                "Failed to read configuration: {} is not a valid value",
187                $str
188            );
189            tracing::warn!("{}", e);
190            e
191        })
192    };
193}
194
195// This macro allows to parse a string to the target type
196// No faili, but log the error and use default
197#[macro_export]
198macro_rules! zparse_default {
199    ($str:expr, $default:expr) => {
200        match $str.parse() {
201            Ok(value) => value,
202            Err(_) => {
203                let e = zenoh_result::zerror!(
204                    "Failed to read configuration: {} is not a valid value",
205                    $str
206                );
207                tracing::warn!("{}", e);
208                $default
209            }
210        }
211    };
212}
213
214// This macro allows to do conditional compilation
215#[macro_export]
216macro_rules! zcondfeat {
217    ($feature:literal, $yes:expr, $not:expr) => {{
218        {
219            #[cfg(feature = $feature)]
220            {
221                $yes
222            }
223
224            #[cfg(not(feature = $feature))]
225            {
226                $not
227            }
228        }
229    }};
230}
231
232// This macro allows to timeout a feature
233#[macro_export]
234macro_rules! ztimeout {
235    ($f:expr) => {
236        tokio::time::timeout(TIMEOUT, ::core::future::IntoFuture::into_future($f))
237            .await
238            .unwrap()
239    };
240}