zenoh/
lib.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#![cfg_attr(docsrs, feature(doc_cfg))]
16
17//! [Zenoh](https://zenoh.io) /zeno/ is a stack that unifies data in motion, data at
18//! rest, and computations. It elegantly blends traditional pub/sub with geo-distributed
19//! storage, queries, and computations, while retaining a level of time and space efficiency
20//! that is well beyond any of the mainstream stacks.
21//!
22//! # Components and concepts
23//!
24//! The main Zenoh components and concepts are described below.
25//!  
26//! ## Session
27//!
28//! The root element of the Zenoh API is the [session].
29//! A session is created by the [`open`] function, which takes a [config] as an argument.
30//! The [`Session`] holds the runtime object,
31//! which maintains the connection to the Zenoh network.
32//!
33//! The Zenoh protocol allows nodes to form a graph with an arbitrary topology, such as a mesh, a star, or a clique.
34//! There is a `mode` parameter in the [config] which specifies the role of the node in the topology: a peer, router or client.
35//! See [`WhatAmI`](crate::config::WhatAmI) for details.
36//!
37//! Zenoh supports two paradigms of communication: publish/subscribe and query/reply.
38//! The entities that perform the communication (e.g., publishers, subscribers, queriers, and queryables) are declared by the session object.
39//!
40//! ## Publish/Subscribe
41//!
42//! In the publish/subscribe paradigm, data is produced by [`Publisher`](crate::pubsub::Publisher)
43//! and consumed by [`Subscriber`](crate::pubsub::Subscriber). See the [pubsub] API for details.
44//!
45//! ## Query/Reply
46//!
47//! In the query/reply paradigm, data is made available by [`Queryable`](crate::query::Queryable)
48//! and requested by [`Querier`](crate::query::Querier) or directly via [`Session::get`](crate::Session::get) operations.
49//! More details are available in the [query] API.
50//!
51//! ## Key Expressions
52//!
53//! Data is associated with keys in the form of a slash-separated path, e.g., `robot/sensor/temp`.
54//! The requesting side uses [key expressions](crate::key_expr) to address the data of interest. Key expressions can
55//! contain wildcards, e.g., `robot/sensor/*` or `robot/**`.
56//!
57//! ## Data representation
58//!
59//! Data is received as [sample]s, which contain the payload and all metadata associated with the data.
60//! The raw byte payload object [`ZBytes`](crate::bytes), which provides mechanisms for zero-copy creation and access,
61//! is available in the [bytes] module.
62//! The [zenoh_ext](https://docs.rs/zenoh-ext/latest/zenoh_ext) crate also provides serialization and deserialization
63//! of basic types and structures for `ZBytes`.
64//!
65//! ## Other components
66//!
67//! Other important functionality of Zenoh includes:
68//! - [scouting] to discover Zenoh nodes in the network. Note that it's not necessary to explicitly
69//!   discover other nodes just to publish, subscribe, or query data.
70//! - Monitor [liveliness] to be notified when a specified resource appears or disappears in the network.
71//! - The [matching] API allows the active side of communication (publisher, querier) to know whether
72//!   there are any interested parties on the other side (subscriber, queryable), which allows saving bandwidth and CPU resources.
73//!
74//! ## Builders
75//!
76//! Zenoh extensively uses the builder pattern. For example, to create a publisher, you first create a
77//! [`PublisherBuilder`](crate::pubsub::PublisherBuilder)
78//! using the [`declare_publisher`](crate::session::Session::declare_publisher) method. The builder is
79//! resolved to the [`Publisher`](crate::pubsub::Publisher) instance by awaiting it in an async context
80//! or by calling the [`wait`](crate::Wait::wait) method in a synchronous context.
81//!
82//! ## Channels and callbacks
83//!
84//! There are two ways to get sequential data from Zenoh primitives (e.g., a series of
85//! [`Sample`](crate::sample::Sample)s from a [`Subscriber`](crate::pubsub::Subscriber)
86//! or [`Reply`](crate::query::Reply)s from a [`Query`](crate::query::Query)): by channel or by callback.
87//!
88//! In channel mode, methods like [`recv_async`](crate::handlers::fifo::FifoChannelHandler::recv_async)
89//! become available on the subscriber or query object (through Deref coercion to the corresponding channel
90//! handler type). By default, the [`FifoChannel`](crate::handlers::fifo::FifoChannel) is used.
91//!
92//! The builders provide methods [`with`](crate::pubsub::SubscriberBuilder::with) to assign an arbitrary channel instead of
93//! the default one, and [`callback`](crate::pubsub::SubscriberBuilder::callback) to assign a callback function.
94//!
95//! See more details in the [handlers] module documentation.
96//!
97//! # Usage examples
98//!
99//! Below are basic examples of using Zenoh. More examples are available in the documentation for each module and in
100//! [zenoh-examples](https://github.com/zenoh-io/zenoh/tree/main/examples).
101//!
102//! ## Publishing/Subscribing
103//! The example below shows how to publish and subscribe to data using Zenoh.
104//!
105//! Publishing data:
106//! ```no_run
107//! #[tokio::main]
108//! async fn main() {
109//!     let session = zenoh::open(zenoh::Config::default()).await.unwrap();
110//!     session.put("key/expression", "value").await.unwrap();
111//!     session.close().await.unwrap();
112//! }
113//! ```
114//!
115//! Subscribing to data:
116//! ```no_run
117//! use futures::prelude::*;
118//!
119//! #[tokio::main]
120//! async fn main() {
121//!     let session = zenoh::open(zenoh::Config::default()).await.unwrap();
122//!     let subscriber = session.declare_subscriber("key/expression").await.unwrap();
123//!     while let Ok(sample) = subscriber.recv_async().await {
124//!         println!("Received: {:?}", sample);
125//!     };
126//! }
127//! ```
128//!
129//! ## Query/Reply
130//!
131//! Declare a queryable:
132//! ```no_run
133//! #[tokio::main]
134//! async fn main() {
135//!     let session = zenoh::open(zenoh::Config::default()).await.unwrap();
136//!     let queryable = session.declare_queryable("key/expression").await.unwrap();
137//!     while let Ok(query) = queryable.recv_async().await {
138//!         let reply = query.reply("key/expression", "value").await.unwrap();
139//!     }
140//! }
141//! ```
142//!
143//! Request data:
144//! ```no_run
145//! use futures::prelude::*;
146//!
147//! #[tokio::main]
148//! async fn main() {
149//!     let session = zenoh::open(zenoh::Config::default()).await.unwrap();
150//!     let replies = session.get("key/expression").await.unwrap();
151//!     while let Ok(reply) = replies.recv_async().await {
152//!         println!(">> Received {:?}", reply.result());
153//!     }
154//! }
155//! ```
156//!
157//! # Features
158//! The following features are exposed by the crate:
159//! * `auth_pubkey`, `auth_usrpwd`
160//!
161//!   Enable authentication support, credentials are configurable in the [`Config`]
162//!
163//! * `internal`
164//!
165//!   Enable some internal APIs, usually necessary to expose some internal functionalities to other language bindings. These APIs are not supposed
166//!   to be called by users as they are close to implementation and can be changed at any moment
167//!
168//! * `plugins`
169//!
170//!   Enable the APIs related to plugin support in `zenohd`. These APIs are `internal` and `unstable` for now
171//!
172//! * `runtime_plugins`
173//!
174//!   Enable the dynamic plugins loading. Includes `plugins`. May be removed in future and combined with `plugins`
175//!
176//! * `shared-memory`
177//!
178//!   Enable shared-memory transport support and specific shared-memory related APIs
179//!
180//! * `stats`
181//!
182//!   Enable collection of statistical data. This data becomes available in "adminspace" (by key `@/<zenoh_id>/router/metrics`)
183//!
184//! * `tracing-instrument`
185//!
186//!   Developer feature - enable tracing of asynchronous tasks for debugging
187//!
188//! * `transport-compression`
189//!
190//!   Enable data-compression on the fly. If this feature is enabled, compression can be turned on or off in [`Config`]
191//!
192//! * `transport_multilink`
193//!
194//!   Enable multiple link connection for unicast transports. Maximum number of connections is configurable in [`Config`]
195//!
196//! * `transport_quic`, `transport_quic_datagram`, `transport_serial`, `transport_tcp`, `transport_tls`,
197//!   `transport_udp`, `transport_unixpipe`, `transport_unixsock-stream`, `transport_vsock`, `transport_ws`
198//!
199//!   Enable specific transports
200//!
201//! * `unstable`
202//!
203//!   Enable the unstable APIs which may change or disappear in future releases. The difference with `internal`
204//!   is that the `unstable` API may be stabilized, while `internal` is unstable by nature, because it reveals implementation details.
205//!
206//! The features enabled by default are:
207//!
208//! `auth_pubkey`, `auth_usrpwd`, `transport_compression`, `transport_multilink`,
209//! `transport_quic`, `transport_quic_datagram`, `transport_tcp`, `transport_tls`, `transport_udp`,
210//! `transport_unixsock-stream`, `transport_ws`.
211//!
212#[macro_use]
213extern crate zenoh_core;
214#[macro_use]
215extern crate zenoh_result;
216
217mod api;
218mod net;
219
220#[cfg(feature = "internal")]
221pub use api::admin::KE_ADV_PREFIX;
222#[cfg(feature = "internal")]
223pub use api::admin::KE_AT;
224#[cfg(feature = "internal")]
225pub use api::admin::KE_EMPTY;
226#[cfg(feature = "internal")]
227pub use api::admin::KE_PUB;
228#[cfg(feature = "internal")]
229pub use api::admin::KE_STAR;
230#[cfg(feature = "internal")]
231pub use api::admin::KE_STARSTAR;
232#[cfg(feature = "internal")]
233pub use api::admin::KE_SUB;
234
235lazy_static::lazy_static!(
236    static ref LONG_VERSION: String = format!("{} built with {}", GIT_VERSION, env!("RUSTC_VERSION"));
237);
238
239const GIT_COMMIT: &str = git_version::git_version!(
240    args = [
241        "--always",
242        "--dirty=-modified",
243        "--abbrev=40",
244        "--exclude=*"
245    ],
246    fallback = "release"
247);
248
249pub const GIT_VERSION: &str =
250    const_format::concatcp!("v", env!("CARGO_PKG_VERSION"), "-", GIT_COMMIT);
251
252#[doc(hidden)]
253pub const FEATURES: &str = zenoh_util::concat_enabled_features!(
254    prefix = "zenoh",
255    features = [
256        "auth_pubkey",
257        "auth_usrpwd",
258        "shared-memory",
259        "stats",
260        "transport_multilink",
261        "transport_quic",
262        "transport_serial",
263        "transport_unixpipe",
264        "transport_tcp",
265        "transport_tls",
266        "transport_udp",
267        "transport_unixsock-stream",
268        "transport_ws",
269        "transport_vsock",
270        "unstable",
271        "default"
272    ]
273);
274
275pub use zenoh_core::{Resolvable, Resolve, Wait};
276/// A Zenoh error.
277pub use zenoh_result::Error;
278/// A Zenoh result.
279pub use zenoh_result::ZResult as Result;
280#[doc(inline)]
281pub use zenoh_util::{init_log_from_env_or, try_init_log_from_env};
282
283#[doc(inline)]
284pub use crate::{
285    config::Config,
286    scouting::scout,
287    session::{open, Session},
288};
289
290/// # Key Expressions
291///
292/// [Key expressions](https://github.com/eclipse-zenoh/roadmap/blob/main/rfcs/ALL/Key%20Expressions.md) are Zenoh's address space.
293///
294/// In Zenoh, operations are performed on keys. To allow addressing multiple keys with a single operation, Zenoh uses Key Expressions (KEs).
295/// KEs are a small language that expresses sets of keys through a glob-like syntax.
296///
297/// These semantics can be a bit difficult to implement, so this module provides the following facilities:
298///
299/// # Storing Key Expressions
300/// This module provides three ways to store strings that have been validated to respect the KE syntax:
301/// - [`keyexpr`](crate::key_expr::keyexpr) is the equivalent of a [`str`],
302/// - [`OwnedKeyExpr`](crate::key_expr::OwnedKeyExpr) works like an [`std::sync::Arc<str>`],
303/// - [`KeyExpr`](crate::key_expr::KeyExpr) works like a [`std::borrow::Cow<str>`], but also stores some additional context internal to Zenoh to optimize
304///   routing and network usage.
305///
306/// The key expression object can be created using the [`KeyExpr::new`](crate::key_expr::KeyExpr::new) method,
307/// which validates the syntax of the provided string.
308/// The [`KeyExpr::from_str_unchecked`](crate::key_expr::KeyExpr::from_str_unchecked) method allows to
309/// accelerate the creation of key expressions when the user can guarantee that the provided string
310/// respects the KE syntax. There is also the
311/// [`Session::declare_keyexpr`](crate::session::Session::declare_keyexpr) method, which not only
312/// declares the key expression, but also informs the Zenoh network of its existence, which can
313/// accelerate routing.
314///
315/// All of these types implement [`Deref`](std::ops::Deref) to [`keyexpr`](crate::key_expr::keyexpr), which notably has methods to check whether a given key expression
316/// [`intersects`](crate::key_expr::keyexpr::intersects) with another, or whether it [`includes`](crate::key_expr::keyexpr::includes) another.
317///
318/// # Tying values to Key Expressions
319/// When storing values tied to Key Expressions, you might want something more specialized than a [`HashMap`](std::collections::HashMap) to respect
320/// Key Expression semantics with high performance.
321///
322/// Enter [`KeTrees`](crate::key_expr::keyexpr_tree). These are data structures built to store KE–value pairs in a manner that supports the set semantics of KEs.
323///
324/// # Building and parsing Key Expressions
325/// A common issue in REST APIs is assigning meaning to sections of the URL and respecting that API in a convenient manner.
326/// The same issue arises naturally when designing a KE space, and [`KeFormat`](crate::key_expr::format::KeFormat) was designed to help with this,
327/// both in constructing and parsing KEs that fit the formats you've defined.
328///
329/// [`kedefine`](crate::key_expr::format::kedefine) also lets you define formats at compile time, enabling a more performant—and, more importantly, safer and more convenient—use of said formats,
330/// as the [`keformat`](crate::key_expr::format::keformat) and [`kewrite`](crate::key_expr::format::kewrite) macros will tell you if you're attempting to set fields of the format that do not exist.
331///
332/// # Example
333/// ```no_run
334/// # #[tokio::main]
335/// # async fn main() {
336/// let sensor = zenoh::key_expr::KeyExpr::new("robot/sensor").unwrap();
337/// let sensor_temp = sensor.join("temp").unwrap();
338/// let sensors = sensor.join("**").unwrap();
339/// assert!(sensors.includes(&sensor_temp));
340/// # }
341/// ```
342pub mod key_expr {
343    #[zenoh_macros::unstable]
344    pub mod keyexpr_tree {
345        pub use zenoh_keyexpr::keyexpr_tree::{
346            impls::KeyedSetProvider,
347            support::{NonWild, UnknownWildness},
348            IKeyExprTree, IKeyExprTreeMut, KeBoxTree,
349        };
350    }
351    #[zenoh_macros::unstable]
352    pub use zenoh_keyexpr::SetIntersectionLevel;
353    pub use zenoh_keyexpr::{
354        canon::Canonize, keyexpr, nonwild_keyexpr, OwnedKeyExpr, OwnedNonWildKeyExpr,
355    };
356
357    pub use crate::api::key_expr::{KeyExpr, KeyExprUndeclaration};
358    // keyexpr format macro support
359    #[zenoh_macros::unstable]
360    pub mod format {
361        pub use zenoh_keyexpr::format::*;
362        pub use zenoh_macros::{ke, kedefine, keformat, kewrite};
363        pub mod macro_support {
364            pub use zenoh_keyexpr::format::macro_support::*;
365        }
366    }
367}
368
369/// # Zenoh [`Session`] and associated types
370///
371/// The [`Session`] is the main component of Zenoh. It holds the zenoh runtime object,
372/// which maintains the state of the connection of the node to the Zenoh network.
373///
374/// The session allows declaring other zenoh entities like publishers, subscribers, queriers, queryables, etc.
375/// and keeps them functioning. Closing the session will close all associated entities.
376///
377/// The session is cloneable so it's easy to share it between tasks and threads. Each clone of the
378/// session is an `Arc` to the internal session object, so cloning is cheap and fast.
379///
380/// A Zenoh session is instantiated using [`zenoh::open`](crate::open)
381/// with parameters specified in the [`Config`] object.
382pub mod session {
383    #[zenoh_macros::unstable]
384    pub use zenoh_config::wrappers::EntityGlobalId;
385    pub use zenoh_config::wrappers::ZenohId;
386    #[zenoh_macros::unstable]
387    pub use zenoh_protocol::core::EntityId;
388
389    #[zenoh_macros::internal]
390    pub use crate::api::builders::session::{init, InitBuilder};
391    pub use crate::api::{
392        builders::{
393            close::CloseBuilder,
394            info::{PeersZenohIdBuilder, RoutersZenohIdBuilder, ZenohIdBuilder},
395            publisher::{SessionDeleteBuilder, SessionPutBuilder},
396            query::SessionGetBuilder,
397            session::OpenBuilder,
398        },
399        info::SessionInfo,
400        session::{open, Session, SessionClosedError, Undeclarable},
401    };
402}
403
404/// # Sample primitives
405///
406/// The [`Sample`](crate::sample::Sample) structure is the data unit received
407/// by [`Subscriber`](crate::pubsub::Subscriber) or [`Querier`](crate::query::Querier)
408/// or [`Session::get`]. It contains the payload and all metadata associated with the data.
409///
410/// The module contains the definitions of the `Sample` itself, definitions of
411/// types of its fields, and builders to create the sample.
412///
413/// In practice, users do not need to create samples manually, as they are created
414/// by the Zenoh runtime when data is published or replied to a query. But sometimes
415/// it's useful to create samples, for example, for the simulation of data reception,
416/// so the [`SampleBuilder`](crate::sample::SampleBuilder) is provided.
417///
418/// The [`SampleFields`](crate::sample::SampleFields) structure contains `Sample`
419/// fields as public members, unlike the `Sample` itself where fields are private.
420/// This allows deconstructing a sample to fields without cloning, which is more efficient
421/// than using getter methods.
422pub mod sample {
423    #[zenoh_macros::unstable]
424    pub use crate::api::sample::{SourceInfo, SourceSn};
425    pub use crate::api::{
426        builders::sample::{
427            SampleBuilder, SampleBuilderAny, SampleBuilderDelete, SampleBuilderPut,
428        },
429        sample::{Locality, Sample, SampleFields, SampleKind},
430    };
431}
432
433/// # Payload primitives and encoding
434///
435/// The [`ZBytes`](crate::bytes::ZBytes) type is Zenoh's representation of raw byte data.
436/// It provides mechanisms for zero-copy creation and access (`From<Vec<u8>>` and
437/// [`ZBytes::slices`](crate::bytes::ZBytes::slices)), as well as methods for sequential
438/// reading/writing ([`ZBytes::reader`](crate::bytes::ZBytes::reader), [`ZBytes::writer`](crate::bytes::ZBytes::writer)).
439///
440/// The `zenoh-ext` crate provides serialization and deserialization of basic types and structures for `ZBytes` via
441/// [`z_serialize`](../../zenoh_ext/fn.z_serialize.html) and
442/// [`z_deserialize`](../../zenoh_ext/fn.z_deserialize.html).
443///
444/// The module also provides the [`Encoding`](crate::bytes::Encoding) enum to specify the encoding of the payload.
445///
446/// # Examples
447///
448/// ### Creating ZBytes
449/// ```
450/// # #[tokio::main]
451/// # async fn main() {
452/// let zbytes = zenoh::bytes::ZBytes::from("Hello, world!");
453/// # assert_eq!(zbytes.try_to_string().unwrap(), "Hello, world!");
454/// # }
455/// ```
456///
457/// ### Converting `ZBytes` to `String`
458/// ```
459/// # #[tokio::main]
460/// # async fn main() {
461/// # let zbytes = zenoh::bytes::ZBytes::from("Hello, world!");
462/// let s = zbytes.try_to_string().unwrap();
463/// assert_eq!(s, "Hello, world!");
464/// # }
465/// ```
466///
467/// ### Converting `ZBytes` to `Vec<u8>`
468/// ```
469/// # #[tokio::main]
470/// # async fn main() {
471/// # let zbytes = zenoh::bytes::ZBytes::from("Hello, world!");
472/// let vec = zbytes.to_bytes();
473/// assert_eq!(vec.as_ref(), b"Hello, world!");
474/// # }
475/// ```
476pub mod bytes {
477    pub use crate::api::{
478        bytes::{OptionZBytes, ZBytes, ZBytesReader, ZBytesSliceIterator, ZBytesWriter},
479        encoding::Encoding,
480    };
481}
482
483/// # Pub/sub primitives
484///
485/// This module provides the publish/subscribe API of Zenoh.
486///
487/// Data is published via the [`Publisher`](crate::pubsub::Publisher) which is declared by the
488/// [`Session::declare_publisher`](crate::Session::declare_publisher) method or directly
489/// from the session via the [`Session::put`](crate::Session::put) and
490/// [`Session::delete`](crate::Session::delete) methods.
491///
492/// [`Sample`](crate::sample::Sample) data is received by [`Subscriber`](crate::pubsub::Subscriber)s
493/// declared with [`Session::declare_subscriber`](crate::Session::declare_subscriber).
494///
495/// # Put and Delete operations
496///
497/// There are two operations in the publisher [`put`](crate::pubsub::Publisher::put) and
498/// [`delete`](crate::pubsub::Publisher::delete) (or in the session as mentioned above).
499///
500/// Publishing may express two different semantics:
501/// - producing a sequence of values
502/// - updating a single value associated with a key expression
503///
504/// In the second case, it's necessary to be able to declare that some key is no longer associated with any value. The
505/// [`delete`](crate::pubsub::Publisher::delete) operation is used for this.
506///
507/// On the receiving side, the subscriber distinguishes between the [`Put`](crate::sample::SampleKind::Put)
508/// and [`Delete`](crate::sample::SampleKind::Delete) operations
509/// by the [`kind`](crate::sample::Sample::kind) field of the [`Sample`](crate::sample::Sample) structure.
510///
511/// The delete operation allows the subscriber to work with a [`Queryable`](crate::query::Queryable)
512/// which caches the values associated with key expressions.
513///
514/// # Examples:
515/// ### Declaring a publisher and publishing data
516/// ```no_run
517/// # #[tokio::main]
518/// # async fn main() {
519/// # let session = zenoh::open(zenoh::Config::default()).await.unwrap();
520/// let publisher = session.declare_publisher("key/expression").await.unwrap();
521/// publisher.put("value").await.unwrap();
522/// # }
523/// ```
524///
525/// ### Declaring a subscriber and receiving data
526/// ```no_run
527/// # #[tokio::main]
528/// # async fn main() {
529/// # let session = zenoh::open(zenoh::Config::default()).await.unwrap();
530/// let subscriber = session.declare_subscriber("key/expression").await.unwrap();
531/// while let Ok(sample) = subscriber.recv_async().await {
532///     println!(">> Received {}", sample.payload().try_to_string().unwrap());
533/// }
534/// # }
535/// ```
536pub mod pubsub {
537    pub use crate::api::{
538        builders::{
539            publisher::{
540                PublicationBuilder, PublicationBuilderDelete, PublicationBuilderPut,
541                PublisherBuilder, PublisherDeleteBuilder, PublisherPutBuilder,
542            },
543            subscriber::SubscriberBuilder,
544        },
545        publisher::{Publisher, PublisherUndeclaration},
546        subscriber::{Subscriber, SubscriberUndeclaration},
547    };
548}
549
550/// # Query/reply primitives
551///
552/// This module provides the query/reply API of Zenoh.
553///
554/// A [`Queryable`](crate::query::Queryable) is declared by the
555/// [`Session::declare_queryable`](crate::Session::declare_queryable) method
556/// and serves queries [`Query`](crate::query::Query) using a callback
557/// or a channel (see [handlers] module documentation for details).
558///
559/// The [`Query`](crate::query::Query) has the methods [`reply`](crate::query::Query::reply)
560/// to reply with a data sample,
561/// and [`reply_err`](crate::query::Query::reply_err) to send an error reply.
562///
563/// The `reply` method sends a [`Sample`](crate::sample::Sample) with a [`kind`](crate::sample::Sample::kind)
564/// field set to [`Put`](crate::sample::SampleKind::Put).
565/// If it's necessary to reply with a [`Delete`](crate::sample::SampleKind::Delete) sample,
566/// the [`reply_del`](crate::query::Query::reply_del) method should be used.
567///
568/// Data is requested from queryables via the [`Session::get`](crate::Session::get) function or by
569/// a [`Querier`](crate::query::Querier) object. Each request returns
570/// zero or more [`Reply`](crate::query::Reply) structures, each one from each queryable
571/// that matches the request.
572/// The reply contains either a [`Sample`](crate::sample::Sample)
573/// or a [`ReplyError`](crate::query::ReplyError).
574///
575/// # Query parameters
576///
577/// The query/reply API allows specifying additional parameters for the request.
578/// These parameters are passed to the get operation using the [`Selector`](crate::query::Selector)
579/// syntax. The selector string has a syntax similar to a URL:
580/// it's a key expression followed by a question mark and the list of parameters in the format
581/// "name=value" separated by ';'.
582/// For example `key/expression?param1=value1;param2=value2`.
583///
584/// # Examples:
585/// ### Declaring a queryable
586///
587/// The example below shows a queryable that replies with temperature data for a given day.
588///
589/// ```no_run
590/// # #[tokio::main]
591/// # async fn main() {
592/// # let session = zenoh::open(zenoh::Config::default()).await.unwrap();
593/// # let temperature_data = std::collections::HashMap::<String, String>::new();
594/// let key_expr = "room/temperature/history";
595/// let queryable = session.declare_queryable(key_expr).await.unwrap();
596/// while let Ok(query) = queryable.recv_async().await {
597///     if let Some(day)= query.selector().parameters().get("day") {
598///         if let Some(value) = temperature_data.get(day) {
599///             query.reply(key_expr, value).await.unwrap();
600///         } else {
601///             query.reply_err("no data for this day").await.unwrap();
602///         }
603///     } else {
604///         query.reply_err("missing day parameter").await.unwrap();
605///     }
606/// }
607/// # }
608/// ```
609///
610/// ## Requesting data
611///
612/// The corresponding request for the above queryable requests the temperature for a given day.
613///
614/// ```no_run
615/// # #[tokio::main]
616/// # async fn main() {
617/// # let session = zenoh::open(zenoh::Config::default()).await.unwrap();
618/// let replies = session.get("room/temperature/history?day=2023-03-15").await.unwrap();
619/// while let Ok(reply) = replies.recv_async().await {
620///     match reply.result() {
621///         Ok(sample) => {
622///             println!(">> Temperature is {}", sample.payload().try_to_string().unwrap());
623///         }
624///         Err(err) => {
625///             println!(">> Error {}", err.payload().try_to_string().unwrap());
626///         }
627///     }
628/// # }
629/// # }
630/// ```
631pub mod query {
632    pub use zenoh_protocol::core::Parameters;
633    #[zenoh_macros::unstable]
634    pub use zenoh_util::time_range::{TimeBound, TimeExpr, TimeRange};
635
636    #[zenoh_macros::internal]
637    pub use crate::api::queryable::ReplySample;
638    pub use crate::api::{
639        builders::{
640            querier::{QuerierBuilder, QuerierGetBuilder},
641            queryable::QueryableBuilder,
642            reply::{ReplyBuilder, ReplyBuilderDelete, ReplyBuilderPut, ReplyErrBuilder},
643        },
644        querier::{Querier, QuerierUndeclaration},
645        query::{ConsolidationMode, QueryConsolidation, QueryTarget, Reply, ReplyError},
646        queryable::{Query, Queryable, QueryableUndeclaration},
647        selector::Selector,
648    };
649    #[zenoh_macros::unstable]
650    pub use crate::api::{query::ReplyKeyExpr, selector::ZenohParameters};
651}
652
653/// # Matching primitives
654///
655/// The matching API allows the active side of communication (publisher, querier) to know
656/// whether there are any interested parties on the other side (subscriber, queryable), which
657/// can save bandwidth and CPU resources.
658///
659/// A [`MatchingListener`](crate::matching::MatchingListener) can be declared via the
660/// [`Publisher::matching_listener`](crate::pubsub::Publisher::matching_listener) or
661/// [`Querier::matching_listener`](crate::query::Querier::matching_listener) methods.
662///
663/// The matching listener behaves like a subscriber, but instead of producing data samples it
664/// yields [`MatchingStatus`](crate::matching::MatchingStatus) instances whenever the matching
665/// status changes, i.e., when the first matching subscriber or queryable appears, or when the
666/// last one disappears.
667///
668/// # Example
669/// ```no_run
670/// # #[tokio::main]
671/// # async fn main() {
672/// # let session = zenoh::open(zenoh::Config::default()).await.unwrap();
673/// let publisher = session.declare_publisher("key/expression").await.unwrap();
674/// let mut listener = publisher.matching_listener().await.unwrap();
675/// while let Ok(status) = listener.recv_async().await {
676///     if status.matching() {
677///         println!(">> Publisher has at least one matching subscriber");
678///     } else {
679///         println!(">> Publisher has no matching subscribers");
680///     }
681/// }
682/// # }
683/// ```
684pub mod matching {
685    pub use crate::api::{
686        builders::matching_listener::MatchingListenerBuilder,
687        matching::{MatchingListener, MatchingListenerUndeclaration, MatchingStatus},
688    };
689}
690
691/// # Callback handler trait.
692///
693/// Zenoh allows two ways to get sequential data from Zenoh primitives, like
694/// [`Subscriber`](crate::pubsub::Subscriber) or [`Query`](crate::query::Query)
695///
696/// 1. **Callback functions**: the user provides a callback function that is called with each
697///    incoming sample.
698///
699/// 2. **Channels**: the user provides a channel that buffers incoming samples, and the user
700///    retrieves samples from the channel when needed.
701///
702/// # ⚠️ Important Note
703///
704/// > **Warning**: The callback function is called in the context of the Zenoh runtime.
705/// > Calling zenoh network operations from the callback (e.g., making queries)
706/// > may lead to deadlocks and other unexpected behaviors.
707/// >
708/// > The Rust type system is not used to prevent calling zenoh network operations
709/// > from the callback for two reasons:
710/// > - this would be too restrictive for multithreaded scenarios
711/// > - this may change in future releases in any direction: immediate crash or allowing
712/// >  this behavior.
713///
714/// Below are the details of how channels work in Zenoh.
715///
716/// Under the hood, the sequential data from a primitive is always passed to a callback function.
717/// However, to simplify using channels, Zenoh provides the
718/// [`IntoHandler`](crate::handlers::IntoHandler) trait,
719/// which returns a pair: a callback which pushes data to the channel and a "handler"
720/// which allows retrieving data from the channel.
721///
722/// The method [`with`](crate::pubsub::SubscriberBuilder::with) accepts any type that
723/// implements the `IntoHandler` trait and extracts the callback and handler from it.
724/// The Zenoh object calls the callback with each incoming sample.
725///
726/// The handler is also stored in the Zenoh object. It's completely opaque to the Zenoh object;
727/// it's just made available to the user via the [`handler`](crate::pubsub::Subscriber::handler) method
728/// or by dereferencing, allowing the user to call the handler's methods directly on the
729/// `Subscriber` or `Query` object.
730/// This is syntactic sugar that allows the user not to care about the separate channel object.
731///
732/// The example of using channels is shown below.
733///
734/// ```no_run
735/// # #[tokio::main]
736/// # async fn main() {
737/// # let session = zenoh::open(zenoh::Config::default()).await.unwrap();
738/// let subscriber = session.declare_subscriber("key/expression")
739///    .with(zenoh::handlers::RingChannel::new(10))
740///   .await.unwrap();
741/// while let Ok(sample) = subscriber.recv_async().await {
742///    println!("Received: {:?}", sample);
743/// }
744/// # }
745/// ```
746///
747/// Note that this code is equivalent to the following one, where the channel
748/// and the callback are created explicitly.
749///
750/// ```no_run
751/// # #[tokio::main]
752/// # async fn main() {
753/// # let session = zenoh::open(zenoh::Config::default()).await.unwrap();
754/// use zenoh::handlers::IntoHandler;
755/// let (callback, mut ring_channel_handler)
756///    = zenoh::handlers::RingChannel::new(10).into_handler();
757/// let subscriber = session.declare_subscriber("key/expression")
758///    .with((callback, ())) // or simply .callback(callback)
759///   .await.unwrap();
760/// while let Ok(sample) = ring_channel_handler.recv_async().await {
761///    println!("Received: {:?}", sample);
762/// }
763/// # }
764/// ```
765///
766/// Obviously, the callback can also be defined manually, without using a channel, and passed
767/// to the [`callback`](crate::pubsub::SubscriberBuilder::callback) method.
768/// In this case, the handler type is `()`, and no additional methods, like `recv_async`, are available on the
769/// subscriber object.
770///
771/// ```no_run
772/// # #[tokio::main]
773/// # async fn main() {
774/// # let session = zenoh::open(zenoh::Config::default()).await.unwrap();
775/// let subscriber = session.declare_subscriber("key/expression")
776///    .callback(|sample| {
777///        println!("Received: {:?}", sample);
778///    }).await.unwrap();
779/// # }
780/// ```
781///
782pub mod handlers {
783    #[zenoh_macros::internal]
784    pub use crate::api::handlers::locked;
785    #[zenoh_macros::internal]
786    pub use crate::api::handlers::CallbackParameter;
787    pub use crate::api::handlers::{
788        Callback, CallbackDrop, DefaultHandler, FifoChannel, FifoChannelHandler, IntoHandler,
789        RingChannel, RingChannelHandler,
790    };
791    /// The module contains helper types and traits necessary to work with FIFO channels
792    pub mod fifo {
793        pub use crate::api::handlers::{
794            Drain, FifoChannel, FifoChannelHandler, IntoIter, Iter, RecvFut, RecvStream, TryIter,
795        };
796    }
797}
798
799/// # Quality of service primitives
800///
801/// This module provides types and enums to configure the quality of service (QoS) of Zenoh
802/// operations, such as reliability and congestion control.
803/// These parameters can be set via the corresponding builder methods, e.g.,
804/// [`reliability`](crate::pubsub::PublisherBuilder::reliability),
805/// [`priority`](crate::pubsub::PublisherBuilder::priority) or
806/// [`congestion_control`](crate::pubsub::PublisherBuilder::congestion_control).
807///
808/// # Example
809///
810/// ```no_run
811/// # #[tokio::main]
812/// # async fn main() {
813/// # let session = zenoh::open(zenoh::Config::default()).await.unwrap();
814/// let publisher = session.declare_publisher("key/expression")
815///   .reliability(zenoh::qos::Reliability::Reliable)
816///   .priority(zenoh::qos::Priority::InteractiveHigh)
817///   .congestion_control(zenoh::qos::CongestionControl::Block)
818///   .await.unwrap();
819/// # }
820///
821pub mod qos {
822    pub use zenoh_protocol::core::CongestionControl;
823    #[zenoh_macros::unstable]
824    pub use zenoh_protocol::core::Reliability;
825
826    pub use crate::api::publisher::Priority;
827}
828
829/// # Scouting primitives
830///
831/// Scouting is the process of discovering Zenoh nodes in the network.
832/// The scouting process depends on the transport layer and the Zenoh configuration.
833///
834/// See more details at <https://zenoh.io/docs/getting-started/deployment/#scouting>.
835///
836/// # Example
837/// ```no_run
838/// # #[tokio::main]
839/// # async fn main() {
840/// use zenoh::config::WhatAmI;
841/// let scout = zenoh::scout(WhatAmI::Peer | WhatAmI::Router, zenoh::Config::default()).await.unwrap();
842/// while let Ok(hello) = scout.recv_async().await {
843///     println!("Discovered node: {}", hello);
844/// }
845/// # }
846/// ```
847pub mod scouting {
848    pub use zenoh_config::wrappers::Hello;
849
850    pub use crate::api::{
851        builders::scouting::ScoutBuilder,
852        scouting::{scout, Scout},
853    };
854}
855
856/// # Liveliness primitives
857///
858/// Sometimes it's necessary to know whether a Zenoh node is available on the network.
859/// It's possible to achieve this by declaring special publishers and queryables, but this task is
860/// not straightforward, so a dedicated API is provided.
861///
862/// The [liveliness](Session::liveliness) API allows a node to declare a
863/// [LivelinessToken](liveliness::LivelinessToken)
864/// with a key expression assigned to it by [declare_token](liveliness::Liveliness::declare_token).
865/// Other nodes can use the liveliness API to query this
866/// key expression or subscribe to it to be notified when the token appears or disappears on the network
867/// using the corresponding functions [get](liveliness::Liveliness::get) and
868/// [declare_subscriber](liveliness::Liveliness::declare_subscriber).
869///
870/// # Examples
871/// ### Declaring a token
872/// ```no_run
873/// # #[tokio::main]
874/// # async fn main() {
875///
876/// let session = zenoh::open(zenoh::Config::default()).await.unwrap();
877/// let liveliness = session
878///     .liveliness()
879///     .declare_token("key/expression")
880///     .await
881///     .unwrap();
882/// # }
883/// ```
884///
885/// ### Querying tokens
886/// ```no_run
887/// # #[tokio::main]
888/// # async fn main() {
889///
890/// let session = zenoh::open(zenoh::Config::default()).await.unwrap();
891/// let replies = session.liveliness().get("key/**").await.unwrap();
892/// while let Ok(reply) = replies.recv_async().await {
893///     if let Ok(sample) = reply.result() {
894///         println!(">> Liveliness token {}", sample.key_expr());
895///     }
896/// }
897/// # }
898/// ```
899///
900/// ### Subscribing to liveliness changes
901/// ```no_run
902/// # #[tokio::main]
903/// # async fn main() {
904/// use zenoh::sample::SampleKind;
905///
906/// let session = zenoh::open(zenoh::Config::default()).await.unwrap();
907/// let subscriber = session.liveliness().declare_subscriber("key/**").await.unwrap();
908/// while let Ok(sample) = subscriber.recv_async().await {
909///     match sample.kind() {
910///         SampleKind::Put => println!("New liveliness: {}", sample.key_expr()),
911///         SampleKind::Delete => println!("Lost liveliness: {}", sample.key_expr()),
912///     }
913/// }
914/// # }
915/// ```
916pub mod liveliness {
917    pub use crate::api::{
918        builders::liveliness::{
919            LivelinessGetBuilder, LivelinessSubscriberBuilder, LivelinessTokenBuilder,
920        },
921        liveliness::{Liveliness, LivelinessToken, LivelinessTokenUndeclaration},
922    };
923}
924
925/// Timestamp support
926///
927/// Each [`Sample`](crate::sample::Sample) has an optional [`Timestamp`](crate::time::Timestamp) associated with it.
928/// The timestamp can be set using the
929/// [`PublicationBuilder::timestamp`](crate::pubsub::PublicationBuilder::timestamp) method when performing a
930/// [`put`](crate::pubsub::Publisher::put) operation or by
931/// [`ReplyBuilder::timestamp`](crate::query::ReplyBuilder::timestamp) when replying to a query with
932/// [`reply`](crate::query::Query::reply).
933///
934/// The timestamp consists of the time value itself and a unique
935/// [clock](https://docs.rs/uhlc/latest/uhlc/) identifier. Each
936/// [`Session`] has its own clock. The [`new_timestamp`](crate::session::Session::new_timestamp)
937/// method can be used to create a new timestamp with the session's identifier.
938///
939/// # Examples
940/// Sending a value with a timestamp
941/// ```no_run
942/// # #[tokio::main]
943/// # async fn main() {
944/// # use zenoh::time::Timestamp;
945/// # let session = zenoh::open(zenoh::Config::default()).await.unwrap();
946/// # let publisher = session.declare_publisher("key/expression").await.unwrap();
947/// let timestamp = session.new_timestamp();
948/// publisher.put("value").timestamp(timestamp).await.unwrap();
949/// # }
950/// ```
951///
952/// Receiving a value with a timestamp
953/// ```no_run
954/// # #[tokio::main]
955/// # async fn main() {
956/// # let session = zenoh::open(zenoh::Config::default()).await.unwrap();
957/// # let subscriber = session.declare_subscriber("key/expression").await.unwrap();
958/// while let Ok(sample) = subscriber.recv_async().await {
959///     if let Some(timestamp) = sample.timestamp() {
960///         println!("Received value with timestamp: {}", timestamp.to_string_rfc3339_lossy());
961///     }
962/// }
963/// # }
964/// ```
965pub mod time {
966    pub use zenoh_protocol::core::{Timestamp, TimestampId, NTP64};
967}
968
969/// # Configuration to pass to [`open`] and [`scout`] functions and associated constants.
970///
971/// The [`Config`] object contains all parameters necessary to configure
972/// a Zenoh session or the scouting process. Usually a configuration file is stored in the json or
973/// yaml format and loaded using the [`Config::from_file`](crate::config::Config::from_file) method.
974/// It's also possible to read or
975/// modify individual elements of the `Config` with the
976/// [`Config::insert_json5`](crate::config::Config::insert_json5)
977/// and [`Config::get_json`](crate::config::Config::get_json) methods.
978///
979/// An example configuration file is available in the [`Config`] documentation section
980/// and in the Zenoh repository as
981/// [DEFAULT_CONFIG.json5](https://github.com/eclipse-zenoh/zenoh/blob/release/1.0.0/DEFAULT_CONFIG.json5)
982///
983/// # Example
984/// ```no_run
985/// # #[tokio::main]
986/// # async fn main() {
987/// use zenoh::config::Config;
988/// use serde_json::json;
989/// let mut config = Config::from_file("path/to/config.json5").unwrap();
990/// config.insert_json5("scouting/multicast/enabled", &json!(false).to_string()).unwrap();
991/// let session = zenoh::open(config).await.unwrap();
992/// # }
993pub mod config {
994    pub use zenoh_config::{EndPoint, Locator, WhatAmI, WhatAmIMatcher, ZenohId};
995
996    pub use crate::api::config::Config;
997    #[zenoh_macros::unstable]
998    pub use crate::api::config::Notifier;
999}
1000
1001#[cfg(all(
1002    feature = "plugins",
1003    not(all(feature = "unstable", feature = "internal"))
1004))]
1005compile_error!(
1006    "Plugin support is internal and unstable. The `unstable` and `internal` features must be enabled to use `plugins`."
1007);
1008
1009#[zenoh_macros::internal]
1010pub mod internal {
1011    #[zenoh_macros::unstable]
1012    pub mod builders {
1013        pub mod close {
1014            pub use crate::api::builders::close::{BackgroundCloseBuilder, NolocalJoinHandle};
1015        }
1016    }
1017    pub mod traits {
1018        pub use crate::api::builders::sample::{
1019            EncodingBuilderTrait, QoSBuilderTrait, SampleBuilderTrait, TimestampBuilderTrait,
1020        };
1021    }
1022    pub use zenoh_core::{
1023        zasync_executor_init, zasynclock, zerror, zlock, zread, ztimeout, zwrite, ResolveFuture,
1024    };
1025    pub use zenoh_result::bail;
1026    pub use zenoh_sync::Condition;
1027    pub use zenoh_task::{TaskController, TerminatableTask};
1028    pub use zenoh_util::{
1029        zenoh_home, LibLoader, Timed, TimedEvent, TimedHandle, Timer, ZENOH_HOME_ENV_VAR,
1030    };
1031
1032    /// A collection of useful buffers used by Zenoh internally and exposed to the user to facilitate
1033    /// reading and writing data.
1034    pub mod buffers {
1035        pub use zenoh_buffers::{
1036            buffer::{Buffer, SplitBuffer},
1037            reader::{
1038                AdvanceableReader, BacktrackableReader, DidntRead, DidntSiphon, HasReader, Reader,
1039                SiphonableReader,
1040            },
1041            writer::{BacktrackableWriter, DidntWrite, HasWriter, Writer},
1042            ZBuf, ZBufReader, ZSlice, ZSliceBuffer,
1043        };
1044    }
1045    /// Initialize a Session with an existing Runtime.
1046    /// This operation is used by the plugins to share the same Runtime as the router.
1047    #[zenoh_macros::internal]
1048    pub mod runtime {
1049        pub use zenoh_runtime::ZRuntime;
1050
1051        pub use crate::net::runtime::{AdminSpace, DynamicRuntime, Runtime, RuntimeBuilder};
1052    }
1053    /// Plugins support
1054    #[cfg(feature = "plugins")]
1055    pub mod plugins {
1056        pub use crate::api::plugins::{
1057            PluginsManager, Response, RunningPlugin, RunningPluginTrait, ZenohPlugin, PLUGIN_PREFIX,
1058        };
1059    }
1060
1061    pub use zenoh_result::ErrNo;
1062}
1063
1064/// Shared memory.
1065#[zenoh_macros::unstable]
1066#[cfg(feature = "shared-memory")]
1067pub mod shm {
1068    pub use zenoh_shm::api::{
1069        buffer::{
1070            traits::{
1071                BufferRelayoutError, OwnedShmBuf, ResideInShm, ShmBuf, ShmBufIntoImmut, ShmBufMut,
1072                ShmBufUnsafeMut,
1073            },
1074            typed::Typed,
1075            zshm::{zshm, ZShm},
1076            zshmmut::{zshmmut, ZShmMut},
1077        },
1078        cleanup::cleanup_orphaned_shm_segments,
1079        client::{shm_client::ShmClient, shm_segment::ShmSegment},
1080        client_storage::{ShmClientStorage, GLOBAL_CLIENT_STORAGE},
1081        common::{
1082            types::{ChunkID, ProtocolID, PtrInSegment, SegmentID},
1083            with_id::WithProtocolID,
1084        },
1085        protocol_implementations::posix::{
1086            posix_shm_client::PosixShmClient, posix_shm_provider_backend::*,
1087            posix_shm_provider_backend_binary_heap::*, posix_shm_provider_backend_buddy::*,
1088            posix_shm_provider_backend_talc::*,
1089        },
1090        provider::{
1091            chunk::{AllocatedChunk, ChunkDescriptor},
1092            memory_layout::{MemoryLayout, TypedLayout},
1093            shm_provider::{
1094                AllocBuilder, AllocPolicy, AsyncAllocPolicy, BlockOn, ConstBool, ConstPolicy,
1095                ConstUsize, Deallocate, Defragment, GarbageCollect, JustAlloc, PolicyValue,
1096                PrecomputedLayout, SafePolicy, ShmProvider, ShmProviderBuilder,
1097            },
1098            shm_provider_backend::ShmProviderBackend,
1099            types::{
1100                AllocAlignment, ChunkAllocResult, ZAllocError, ZLayoutAllocError, ZLayoutError,
1101            },
1102        },
1103    };
1104
1105    pub use crate::net::runtime::ShmProviderState;
1106}
1107
1108/// Functionality for interrupting queries.
1109#[zenoh_macros::unstable]
1110pub mod cancellation {
1111    pub use crate::api::cancellation::CancellationToken;
1112    #[cfg(feature = "internal")]
1113    pub use crate::api::cancellation::SyncGroupNotifier;
1114}
1115#[cfg(test)]
1116mod tests;