From dd1fb459350f9746d79616eb33aa3e71c34c5e3d Mon Sep 17 00:00:00 2001 From: Luca Cominardi Date: Thu, 12 Sep 2024 10:28:26 +0200 Subject: [PATCH] feat!: make session an arc-like object (#1364) * feat!: bind callback subscriber/queryable to session lifetime To determine if the entity is callback-only, the only elegant way I've found is the rule "handler is ZST means callback-only". Unless users starts writing fancy implementations, it should be correct 100% of the time. Session entities now uses weak references, except publishers because it would impact performances. Weak references also solves the issue of mass undeclarations before closing the session (when the session is an `Arc`), except for publishers. `Undeclarable` trait has been refactored a little bit to better match its use in the code. * fix: fix example * fix: fix example * fix: add missing comment about ZST trick * Update zenoh/src/api/key_expr.rs Co-authored-by: Luca Cominardi * fix: formatting * fix: don't use `Weak` when undeclared on drop * feat!: make session an arc-like object The refactoring is quite deep, so this is the first (dirty) iteration which passes the tests. * fix: use weak everywhere! * fix: fix doc * feat: use pseudo-weak session with the same perf than arc * fix: fix resource cleanup * Fix typo * fix: align `MatchingListener` undeclaration on drop behavior * refactor: add comments about `WeakSession` * refactor: add comment for `Session` and `Session::close` (#1369) * refactor: add comment for `Session` and `Session::close` * Update zenoh/src/api/session.rs Co-authored-by: Luca Cominardi * Update zenoh/src/api/session.rs Co-authored-by: Luca Cominardi * Update zenoh/src/api/session.rs Co-authored-by: Luca Cominardi * fix: don't run `Session::close` example * fix: fix `Session` example * fix: fix `Session` doc --------- Co-authored-by: Luca Cominardi * feat: use builder method instead of handler type for undeclaration on drop (#1377) * refactor: add comment for `Session` and `Session::close` * Update zenoh/src/api/session.rs Co-authored-by: Luca Cominardi * Update zenoh/src/api/session.rs Co-authored-by: Luca Cominardi * Update zenoh/src/api/session.rs Co-authored-by: Luca Cominardi * fix: don't run `Session::close` example * fix: fix `Session` example * fix: fix `Session` doc * feat: use builder method instead of handler type for undeclaration on drop --------- Co-authored-by: Luca Cominardi * chore: merge main into dev/arcsession (#1378) * Fix bug with QueryTarget ALL_COMPLETE in clients and peers (#1358) * Fix bug with QueryTarget ALL_COMPLETE in clients and peers * Fix BEST_MATCHING queryable selection * Properly fix Query targeting in non writer side filtering situations * Improve fix * Update zenoh/src/net/routing/hat/linkstate_peer/queries.rs Co-authored-by: Joseph Perez * Update zenoh/src/net/routing/hat/p2p_peer/queries.rs Co-authored-by: Joseph Perez * Update zenoh/src/net/routing/hat/router/queries.rs Co-authored-by: Joseph Perez * Update zenoh/src/net/routing/hat/client/queries.rs Co-authored-by: Joseph Perez * Remove non used ordered-float dependency --------- Co-authored-by: Luca Cominardi Co-authored-by: Joseph Perez * fix: publisher should not be clonable (#1370) * made builder traits internal (#1376) * scaffolding macro added * builder traits made internal * doc corrected * cargo fmt * typo fix * typo fix * Fix bugs querying liveliness tokens (#1374) * Fix bug in liveliness get in client * Fix bug treating token interests replies from routers in peers * Peers propagate current token interests to remote peers with unfinalize initial declarations push * Don't register current interests declaration replies * Add comments * Add comments * Add comments --------- Co-authored-by: OlivierHecart Co-authored-by: Luca Cominardi Co-authored-by: Michael Ilyin * Revert "chore: merge main into dev/arcsession (#1378)" (#1379) This reverts commit f3f540320e211c8f720d3e660ac50af261df7bdf. * fix: various fixes * fix: various fixes (2) * chore: merge branch 'main' into 'dev/arcsession' (#1384) * feat(zenoh_id): exposing into slice & try from slice Allowing users to create a ZenohId from a slice, using TryFrom, and also allowing users to convert a ZenohId into a [u8; 16]. * Add LivlinessSubscriber history option (#1355) * Close #1357 * feat(zenoh_id): replacing from slice with function --------- Co-authored-by: Darius Maitia Co-authored-by: OlivierHecart Co-authored-by: Luca Cominardi * refactor: use `IntoHandler` associated const for undeclaration on drop * refactor: remove prelude * fix: fix config example * fix: fix zenoh-ext examples * fix: fix plugins examples * fix: fix merge * Fix shm test * Fix clippy warnings * refactor: use builder method for undeclaration on drop * fix: remove useless lifetimes * fix: add missing unstable flag * feat: add tuple implementation for IntoHandler --------- Co-authored-by: Joseph Perez Co-authored-by: OlivierHecart Co-authored-by: Michael Ilyin Co-authored-by: Darius Maitia --- .../src/pub_sub/bin/z_pub_sub.rs | 2 +- .../src/queryable_get/bin/z_queryable_get.rs | 1 - commons/zenoh-config/src/lib.rs | 84 +- examples/examples/z_alloc_shm.rs | 3 +- examples/examples/z_bytes_shm.rs | 2 +- examples/examples/z_forward.rs | 2 +- examples/examples/z_get_liveliness.rs | 2 +- examples/examples/z_info.rs | 2 +- examples/examples/z_liveliness.rs | 2 +- examples/examples/z_ping.rs | 2 +- examples/examples/z_ping_shm.rs | 1 - examples/examples/z_pong.rs | 4 +- examples/examples/z_pub.rs | 2 +- examples/examples/z_pub_shm.rs | 3 +- examples/examples/z_pub_shm_thr.rs | 1 - examples/examples/z_pub_thr.rs | 2 +- examples/examples/z_pull.rs | 2 +- examples/examples/z_queryable.rs | 2 +- examples/examples/z_queryable_shm.rs | 1 - examples/examples/z_storage.rs | 1 - examples/examples/z_sub.rs | 2 +- examples/examples/z_sub_liveliness.rs | 2 +- examples/examples/z_sub_shm.rs | 2 +- examples/examples/z_sub_thr.rs | 6 +- examples/src/lib.rs | 2 +- plugins/zenoh-backend-example/src/lib.rs | 2 +- plugins/zenoh-backend-traits/src/lib.rs | 16 +- plugins/zenoh-plugin-example/src/lib.rs | 3 +- .../zenoh-plugin-rest/examples/z_serve_sse.rs | 4 +- plugins/zenoh-plugin-rest/src/lib.rs | 4 +- .../src/replica/align_queryable.rs | 4 +- .../src/replica/mod.rs | 2 +- .../src/replica/storage.rs | 2 +- .../tests/operations.rs | 3 +- .../tests/wildcard.rs | 3 +- zenoh-ext/examples/examples/z_query_sub.rs | 2 +- zenoh-ext/src/group.rs | 3 +- zenoh-ext/src/publication_cache.rs | 25 +- zenoh-ext/src/querying_subscriber.rs | 162 +-- zenoh-ext/src/session_ext.rs | 60 +- zenoh-ext/src/subscriber_ext.rs | 15 +- zenoh-ext/tests/liveliness.rs | 9 +- zenoh/src/api/admin.rs | 26 +- zenoh/src/api/builders/publisher.rs | 80 +- zenoh/src/api/handlers/callback.rs | 20 + zenoh/src/api/info.rs | 38 +- zenoh/src/api/key_expr.rs | 21 +- zenoh/src/api/liveliness.rs | 193 ++-- zenoh/src/api/publisher.rs | 436 ++----- zenoh/src/api/query.rs | 37 +- zenoh/src/api/queryable.rs | 284 ++--- zenoh/src/api/scouting.rs | 29 +- zenoh/src/api/session.rs | 1015 +++++++---------- zenoh/src/api/subscriber.rs | 277 +++-- zenoh/src/lib.rs | 11 +- zenoh/src/net/routing/dispatcher/resource.rs | 1 + zenoh/src/net/runtime/adminspace.rs | 5 +- zenoh/src/net/runtime/mod.rs | 11 +- zenoh/src/prelude.rs | 22 +- zenoh/tests/acl.rs | 1 - zenoh/tests/attachments.rs | 3 +- zenoh/tests/authentication.rs | 1 - zenoh/tests/bytes.rs | 2 +- zenoh/tests/connection_retry.rs | 6 +- zenoh/tests/events.rs | 1 - zenoh/tests/handler.rs | 2 +- zenoh/tests/interceptors.rs | 3 +- zenoh/tests/liveliness.rs | 12 +- zenoh/tests/matching.rs | 2 +- zenoh/tests/qos.rs | 1 - zenoh/tests/routing.rs | 7 +- zenoh/tests/session.rs | 4 +- zenoh/tests/shm.rs | 3 +- zenoh/tests/unicity.rs | 1 - zenohd/src/main.rs | 2 +- 75 files changed, 1286 insertions(+), 1725 deletions(-) diff --git a/ci/valgrind-check/src/pub_sub/bin/z_pub_sub.rs b/ci/valgrind-check/src/pub_sub/bin/z_pub_sub.rs index f3b1dd0efe..ad96d0b2b0 100644 --- a/ci/valgrind-check/src/pub_sub/bin/z_pub_sub.rs +++ b/ci/valgrind-check/src/pub_sub/bin/z_pub_sub.rs @@ -13,7 +13,7 @@ // use std::time::Duration; -use zenoh::{config::Config, key_expr::KeyExpr, prelude::*}; +use zenoh::{config::Config, key_expr::KeyExpr}; #[tokio::main] async fn main() { diff --git a/ci/valgrind-check/src/queryable_get/bin/z_queryable_get.rs b/ci/valgrind-check/src/queryable_get/bin/z_queryable_get.rs index 8ea7be201b..e82ecba477 100644 --- a/ci/valgrind-check/src/queryable_get/bin/z_queryable_get.rs +++ b/ci/valgrind-check/src/queryable_get/bin/z_queryable_get.rs @@ -16,7 +16,6 @@ use std::{convert::TryFrom, time::Duration}; use zenoh::{ config::Config, key_expr::KeyExpr, - prelude::*, query::{QueryTarget, Selector}, }; diff --git a/commons/zenoh-config/src/lib.rs b/commons/zenoh-config/src/lib.rs index 2d9ba0beee..b57c62edde 100644 --- a/commons/zenoh-config/src/lib.rs +++ b/commons/zenoh-config/src/lib.rs @@ -224,9 +224,8 @@ pub fn client, T: Into>(peers: I) -> Config #[test] fn config_keys() { - use validated_struct::ValidatedMap; let c = Config::default(); - dbg!(c.keys()); + dbg!(Vec::from_iter(c.keys())); } validated_struct::validator! { @@ -659,6 +658,40 @@ fn config_deser() { } impl Config { + pub fn insert<'d, D: serde::Deserializer<'d>>( + &mut self, + key: &str, + value: D, + ) -> Result<(), validated_struct::InsertionError> + where + validated_struct::InsertionError: From, + { + ::insert(self, key, value) + } + + pub fn get( + &self, + key: &str, + ) -> Result<::Accessor, GetError> { + ::get(self, key) + } + + pub fn get_json(&self, key: &str) -> Result { + ::get_json(self, key) + } + + pub fn insert_json5( + &mut self, + key: &str, + value: &str, + ) -> Result<(), validated_struct::InsertionError> { + ::insert_json5(self, key, value) + } + + pub fn keys(&self) -> impl Iterator { + ::keys(self).into_iter() + } + pub fn set_plugin_validator(&mut self, validator: Weak) { self.plugins.validator = validator; } @@ -778,7 +811,6 @@ impl std::fmt::Display for Config { #[test] fn config_from_json() { - use validated_struct::ValidatedMap; let from_str = serde_json::Deserializer::from_str; let mut config = Config::from_deserializer(&mut from_str(r#"{}"#)).unwrap(); config @@ -944,6 +976,52 @@ where self.lock().keys() } } +impl Notifier +where + T: for<'a> ValidatedMapAssociatedTypes<'a, Accessor = &'a dyn Any>, +{ + pub fn insert<'d, D: serde::Deserializer<'d>>( + &self, + key: &str, + value: D, + ) -> Result<(), validated_struct::InsertionError> + where + validated_struct::InsertionError: From, + { + self.lock().insert(key, value)?; + self.notify(key); + Ok(()) + } + + pub fn get( + &self, + key: &str, + ) -> Result<::Accessor, GetError> { + let guard = zlock!(self.inner.inner); + // SAFETY: MutexGuard pins the mutex behind which the value is held. + let subref = guard.get(key.as_ref())? as *const _; + Ok(GetGuard { + _guard: guard, + subref, + }) + } + + pub fn get_json(&self, key: &str) -> Result { + self.lock().get_json(key) + } + + pub fn insert_json5( + &self, + key: &str, + value: &str, + ) -> Result<(), validated_struct::InsertionError> { + self.insert(key, &mut json5::Deserializer::from_str(value)?) + } + + pub fn keys(&self) -> impl Iterator { + self.lock().keys().into_iter() + } +} pub struct GetGuard<'a, T> { _guard: MutexGuard<'a, T>, diff --git a/examples/examples/z_alloc_shm.rs b/examples/examples/z_alloc_shm.rs index 1f2f544a25..09ea264f03 100644 --- a/examples/examples/z_alloc_shm.rs +++ b/examples/examples/z_alloc_shm.rs @@ -12,7 +12,6 @@ // ZettaScale Zenoh Team, // use zenoh::{ - prelude::*, shm::{ AllocAlignment, BlockOn, Deallocate, Defragment, GarbageCollect, PosixShmProviderBackend, ShmProviderBuilder, POSIX_PROTOCOL_ID, @@ -27,7 +26,7 @@ async fn main() { run().await.unwrap() } -async fn run() -> ZResult<()> { +async fn run() -> zenoh::Result<()> { // create an SHM backend... // NOTE: For extended PosixShmProviderBackend API please check z_posix_shm_provider.rs let backend = PosixShmProviderBackend::builder() diff --git a/examples/examples/z_bytes_shm.rs b/examples/examples/z_bytes_shm.rs index 6ae69407d0..1db1680be7 100644 --- a/examples/examples/z_bytes_shm.rs +++ b/examples/examples/z_bytes_shm.rs @@ -13,11 +13,11 @@ // use zenoh::{ bytes::ZBytes, - prelude::*, shm::{ zshm, zshmmut, PosixShmProviderBackend, ShmProviderBuilder, ZShm, ZShmMut, POSIX_PROTOCOL_ID, }, + Wait, }; fn main() { diff --git a/examples/examples/z_forward.rs b/examples/examples/z_forward.rs index 8654a8f420..e1925a5477 100644 --- a/examples/examples/z_forward.rs +++ b/examples/examples/z_forward.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // use clap::Parser; -use zenoh::{key_expr::KeyExpr, prelude::*, Config}; +use zenoh::{key_expr::KeyExpr, Config}; use zenoh_examples::CommonArgs; use zenoh_ext::SubscriberForward; diff --git a/examples/examples/z_get_liveliness.rs b/examples/examples/z_get_liveliness.rs index f057d81ba2..b0c4006e13 100644 --- a/examples/examples/z_get_liveliness.rs +++ b/examples/examples/z_get_liveliness.rs @@ -14,7 +14,7 @@ use std::time::Duration; use clap::Parser; -use zenoh::{key_expr::KeyExpr, prelude::*, Config}; +use zenoh::{key_expr::KeyExpr, Config}; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/examples/examples/z_info.rs b/examples/examples/z_info.rs index d7859b5de2..3cd6669dae 100644 --- a/examples/examples/z_info.rs +++ b/examples/examples/z_info.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // use clap::Parser; -use zenoh::{prelude::*, session::ZenohId}; +use zenoh::session::ZenohId; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/examples/examples/z_liveliness.rs b/examples/examples/z_liveliness.rs index 2f102d1f93..8e86ef05c4 100644 --- a/examples/examples/z_liveliness.rs +++ b/examples/examples/z_liveliness.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // use clap::Parser; -use zenoh::{key_expr::KeyExpr, prelude::*, Config}; +use zenoh::{key_expr::KeyExpr, Config}; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/examples/examples/z_ping.rs b/examples/examples/z_ping.rs index cd40945ad8..9f715ea153 100644 --- a/examples/examples/z_ping.rs +++ b/examples/examples/z_ping.rs @@ -14,7 +14,7 @@ use std::time::{Duration, Instant}; use clap::Parser; -use zenoh::{bytes::ZBytes, key_expr::keyexpr, prelude::*, qos::CongestionControl, Config}; +use zenoh::{bytes::ZBytes, key_expr::keyexpr, qos::CongestionControl, Config, Wait}; use zenoh_examples::CommonArgs; fn main() { diff --git a/examples/examples/z_ping_shm.rs b/examples/examples/z_ping_shm.rs index 3f0434e905..969bd6cbb5 100644 --- a/examples/examples/z_ping_shm.rs +++ b/examples/examples/z_ping_shm.rs @@ -17,7 +17,6 @@ use clap::Parser; use zenoh::{ bytes::ZBytes, key_expr::keyexpr, - prelude::*, qos::CongestionControl, shm::{PosixShmProviderBackend, ShmProviderBuilder, POSIX_PROTOCOL_ID}, Config, Wait, diff --git a/examples/examples/z_pong.rs b/examples/examples/z_pong.rs index 2867d7cea6..4199968f5d 100644 --- a/examples/examples/z_pong.rs +++ b/examples/examples/z_pong.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // use clap::Parser; -use zenoh::{key_expr::keyexpr, prelude::*, qos::CongestionControl, Config}; +use zenoh::{key_expr::keyexpr, qos::CongestionControl, Config, Wait}; use zenoh_examples::CommonArgs; fn main() { @@ -21,7 +21,7 @@ fn main() { let (config, express) = parse_args(); - let session = zenoh::open(config).wait().unwrap().into_arc(); + let session = zenoh::open(config).wait().unwrap(); // The key expression to read the data from let key_expr_ping = keyexpr::new("test/ping").unwrap(); diff --git a/examples/examples/z_pub.rs b/examples/examples/z_pub.rs index cc97a99971..4472aa9f6a 100644 --- a/examples/examples/z_pub.rs +++ b/examples/examples/z_pub.rs @@ -14,7 +14,7 @@ use std::time::Duration; use clap::Parser; -use zenoh::{bytes::Encoding, key_expr::KeyExpr, prelude::*, Config}; +use zenoh::{bytes::Encoding, key_expr::KeyExpr, Config}; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/examples/examples/z_pub_shm.rs b/examples/examples/z_pub_shm.rs index 9c6311f59d..fb1900b1d7 100644 --- a/examples/examples/z_pub_shm.rs +++ b/examples/examples/z_pub_shm.rs @@ -14,7 +14,6 @@ use clap::Parser; use zenoh::{ key_expr::KeyExpr, - prelude::*, shm::{ BlockOn, GarbageCollect, PosixShmProviderBackend, ShmProviderBuilder, POSIX_PROTOCOL_ID, }, @@ -25,7 +24,7 @@ use zenoh_examples::CommonArgs; const N: usize = 10; #[tokio::main] -async fn main() -> Result<(), ZError> { +async fn main() -> zenoh::Result<()> { // Initiate logging zenoh::init_log_from_env_or("error"); diff --git a/examples/examples/z_pub_shm_thr.rs b/examples/examples/z_pub_shm_thr.rs index 699b6df341..539127fb8a 100644 --- a/examples/examples/z_pub_shm_thr.rs +++ b/examples/examples/z_pub_shm_thr.rs @@ -14,7 +14,6 @@ use clap::Parser; use zenoh::{ bytes::ZBytes, - prelude::*, qos::CongestionControl, shm::{PosixShmProviderBackend, ShmProviderBuilder, POSIX_PROTOCOL_ID}, Config, Wait, diff --git a/examples/examples/z_pub_thr.rs b/examples/examples/z_pub_thr.rs index 9014f78763..dc18715e2a 100644 --- a/examples/examples/z_pub_thr.rs +++ b/examples/examples/z_pub_thr.rs @@ -17,8 +17,8 @@ use std::convert::TryInto; use clap::Parser; use zenoh::{ bytes::ZBytes, - prelude::*, qos::{CongestionControl, Priority}, + Wait, }; use zenoh_examples::CommonArgs; diff --git a/examples/examples/z_pull.rs b/examples/examples/z_pull.rs index e04e1a6b32..c677b545b8 100644 --- a/examples/examples/z_pull.rs +++ b/examples/examples/z_pull.rs @@ -14,7 +14,7 @@ use std::time::Duration; use clap::Parser; -use zenoh::{handlers::RingChannel, key_expr::KeyExpr, prelude::*, Config}; +use zenoh::{handlers::RingChannel, key_expr::KeyExpr, Config}; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/examples/examples/z_queryable.rs b/examples/examples/z_queryable.rs index 7ea3b7b5a1..b3b5ca9bf0 100644 --- a/examples/examples/z_queryable.rs +++ b/examples/examples/z_queryable.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // use clap::Parser; -use zenoh::{key_expr::KeyExpr, prelude::*, Config}; +use zenoh::{key_expr::KeyExpr, Config}; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/examples/examples/z_queryable_shm.rs b/examples/examples/z_queryable_shm.rs index a515671197..db00ddb118 100644 --- a/examples/examples/z_queryable_shm.rs +++ b/examples/examples/z_queryable_shm.rs @@ -15,7 +15,6 @@ use clap::Parser; use zenoh::{ bytes::ZBytes, key_expr::KeyExpr, - prelude::*, shm::{ zshm, BlockOn, GarbageCollect, PosixShmProviderBackend, ShmProviderBuilder, POSIX_PROTOCOL_ID, diff --git a/examples/examples/z_storage.rs b/examples/examples/z_storage.rs index 2cce1640b7..9f6f50b16f 100644 --- a/examples/examples/z_storage.rs +++ b/examples/examples/z_storage.rs @@ -19,7 +19,6 @@ use clap::Parser; use futures::select; use zenoh::{ key_expr::{keyexpr, KeyExpr}, - prelude::*, sample::{Sample, SampleKind}, Config, }; diff --git a/examples/examples/z_sub.rs b/examples/examples/z_sub.rs index 8f48dee25c..26fc768737 100644 --- a/examples/examples/z_sub.rs +++ b/examples/examples/z_sub.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // use clap::Parser; -use zenoh::{key_expr::KeyExpr, prelude::*, Config}; +use zenoh::{key_expr::KeyExpr, Config}; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/examples/examples/z_sub_liveliness.rs b/examples/examples/z_sub_liveliness.rs index be729e34d1..79c0cd5b1a 100644 --- a/examples/examples/z_sub_liveliness.rs +++ b/examples/examples/z_sub_liveliness.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // use clap::Parser; -use zenoh::{key_expr::KeyExpr, prelude::*, sample::SampleKind, Config}; +use zenoh::{key_expr::KeyExpr, sample::SampleKind, Config}; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/examples/examples/z_sub_shm.rs b/examples/examples/z_sub_shm.rs index 215268501d..a4660485dc 100644 --- a/examples/examples/z_sub_shm.rs +++ b/examples/examples/z_sub_shm.rs @@ -14,7 +14,7 @@ use clap::Parser; #[cfg(all(feature = "shared-memory", feature = "unstable"))] use zenoh::shm::zshm; -use zenoh::{bytes::ZBytes, config::Config, key_expr::KeyExpr, prelude::*}; +use zenoh::{bytes::ZBytes, config::Config, key_expr::KeyExpr}; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/examples/examples/z_sub_thr.rs b/examples/examples/z_sub_thr.rs index 7098a52134..bbc4541cd1 100644 --- a/examples/examples/z_sub_thr.rs +++ b/examples/examples/z_sub_thr.rs @@ -14,7 +14,7 @@ use std::time::Instant; use clap::Parser; -use zenoh::{prelude::*, Config}; +use zenoh::{Config, Wait}; use zenoh_examples::CommonArgs; struct Stats { @@ -87,9 +87,7 @@ fn main() { } }) .wait() - .unwrap() - // Make the subscriber run in background, until the session is closed. - .background(); + .unwrap(); println!("Press CTRL-C to quit..."); std::thread::park(); diff --git a/examples/src/lib.rs b/examples/src/lib.rs index bb6b025b2b..20409b4f85 100644 --- a/examples/src/lib.rs +++ b/examples/src/lib.rs @@ -3,7 +3,7 @@ //! Check ../README.md for usage. //! -use zenoh::config::{Config, ValidatedMap}; +use zenoh::config::Config; #[derive(clap::ValueEnum, Clone, Copy, PartialEq, Eq, Hash, Debug)] pub enum Wai { diff --git a/plugins/zenoh-backend-example/src/lib.rs b/plugins/zenoh-backend-example/src/lib.rs index b9e670b799..4899bed6b0 100644 --- a/plugins/zenoh-backend-example/src/lib.rs +++ b/plugins/zenoh-backend-example/src/lib.rs @@ -15,7 +15,7 @@ use std::collections::{hash_map::Entry, HashMap}; use async_trait::async_trait; use tokio::sync::RwLock; -use zenoh::{internal::Value, key_expr::OwnedKeyExpr, prelude::*, time::Timestamp}; +use zenoh::{internal::Value, key_expr::OwnedKeyExpr, time::Timestamp, Result as ZResult}; use zenoh_backend_traits::{ config::{StorageConfig, VolumeConfig}, Capability, History, Persistence, Storage, StorageInsertionResult, StoredData, Volume, diff --git a/plugins/zenoh-backend-traits/src/lib.rs b/plugins/zenoh-backend-traits/src/lib.rs index a75d934050..cd2238dc6a 100644 --- a/plugins/zenoh-backend-traits/src/lib.rs +++ b/plugins/zenoh-backend-traits/src/lib.rs @@ -29,12 +29,12 @@ //! ``` //! use std::sync::Arc; //! use async_trait::async_trait; -//! use zenoh::{key_expr::OwnedKeyExpr, prelude::*, time::Timestamp, internal::Value}; +//! use zenoh::{key_expr::OwnedKeyExpr, time::Timestamp, internal::Value}; //! use zenoh_backend_traits::*; //! use zenoh_backend_traits::config::*; //! //! #[no_mangle] -//! pub fn create_volume(config: VolumeConfig) -> ZResult> { +//! pub fn create_volume(config: VolumeConfig) -> zenoh::Result> { //! Ok(Box::new(MyVolumeType { config })) //! } //! @@ -62,7 +62,7 @@ //! } //! } //! -//! async fn create_storage(&self, properties: StorageConfig) -> ZResult> { +//! async fn create_storage(&self, properties: StorageConfig) -> zenoh::Result> { //! // The properties are the ones passed via a PUT in the admin space for Storage creation. //! Ok(Box::new(MyStorage::new(properties).await?)) //! } @@ -74,7 +74,7 @@ //! } //! //! impl MyStorage { -//! async fn new(config: StorageConfig) -> ZResult { +//! async fn new(config: StorageConfig) -> zenoh::Result { //! Ok(MyStorage { config }) //! } //! } @@ -88,7 +88,7 @@ //! self.config.to_json_value() //! } //! -//! async fn put(&mut self, key: Option, value: Value, timestamp: Timestamp) -> ZResult { +//! async fn put(&mut self, key: Option, value: Value, timestamp: Timestamp) -> zenoh::Result { //! // the key will be None if it exactly matched with the strip_prefix //! // create a storage specific special structure to store it //! // Store the data with timestamp @@ -99,14 +99,14 @@ //! // return Ok(StorageInsertionResult::Outdated); //! } //! -//! async fn delete(&mut self, key: Option, timestamp: Timestamp) -> ZResult { +//! async fn delete(&mut self, key: Option, timestamp: Timestamp) -> zenoh::Result { //! // @TODO: //! // delete the actual entry from storage //! return Ok(StorageInsertionResult::Deleted); //! } //! //! // When receiving a GET operation -//! async fn get(&mut self, key_expr: Option, parameters: &str) -> ZResult> { +//! async fn get(&mut self, key_expr: Option, parameters: &str) -> zenoh::Result> { //! // @TODO: //! // get the data associated with key_expr and return it //! // NOTE: in case parameters is not empty something smarter should be done with returned data... @@ -114,7 +114,7 @@ //! } //! //! // To get all entries in the datastore -//! async fn get_all_entries(&self) -> ZResult, Timestamp)>> { +//! async fn get_all_entries(&self) -> zenoh::Result, Timestamp)>> { //! // @TODO: get the list of (key, timestamp) in the datastore //! Ok(Vec::new()) //! } diff --git a/plugins/zenoh-plugin-example/src/lib.rs b/plugins/zenoh-plugin-example/src/lib.rs index aa943c12e3..9fc53c1c80 100644 --- a/plugins/zenoh-plugin-example/src/lib.rs +++ b/plugins/zenoh-plugin-example/src/lib.rs @@ -34,9 +34,8 @@ use zenoh::{ zlock, }, key_expr::{keyexpr, KeyExpr}, - prelude::ZResult, sample::Sample, - session::SessionDeclarations, + Result as ZResult, }; use zenoh_plugin_trait::{plugin_long_version, plugin_version, Plugin, PluginControl}; diff --git a/plugins/zenoh-plugin-rest/examples/z_serve_sse.rs b/plugins/zenoh-plugin-rest/examples/z_serve_sse.rs index 849800de73..fd81ff279f 100644 --- a/plugins/zenoh-plugin-rest/examples/z_serve_sse.rs +++ b/plugins/zenoh-plugin-rest/examples/z_serve_sse.rs @@ -14,9 +14,7 @@ use std::time::Duration; use clap::{arg, Command}; -use zenoh::{ - config::Config, key_expr::keyexpr, qos::CongestionControl, session::SessionDeclarations, -}; +use zenoh::{config::Config, key_expr::keyexpr, qos::CongestionControl}; const HTML: &str = r#"
diff --git a/plugins/zenoh-plugin-rest/src/lib.rs b/plugins/zenoh-plugin-rest/src/lib.rs index f0d1cc65f0..90dd6002df 100644 --- a/plugins/zenoh-plugin-rest/src/lib.rs +++ b/plugins/zenoh-plugin-rest/src/lib.rs @@ -44,10 +44,10 @@ use zenoh::{ zerror, }, key_expr::{keyexpr, KeyExpr}, - prelude::*, query::{Parameters, QueryConsolidation, Reply, Selector, ZenohParameters}, sample::{Sample, SampleKind}, - session::{Session, SessionDeclarations}, + session::Session, + Result as ZResult, }; use zenoh_plugin_trait::{plugin_long_version, plugin_version, Plugin, PluginControl}; diff --git a/plugins/zenoh-plugin-storage-manager/src/replica/align_queryable.rs b/plugins/zenoh-plugin-storage-manager/src/replica/align_queryable.rs index 737ce79144..1baad55db6 100644 --- a/plugins/zenoh-plugin-storage-manager/src/replica/align_queryable.rs +++ b/plugins/zenoh-plugin-storage-manager/src/replica/align_queryable.rs @@ -21,8 +21,8 @@ use std::{ }; use zenoh::{ - internal::Value, key_expr::OwnedKeyExpr, prelude::*, query::Parameters, sample::Sample, - time::Timestamp, Session, + internal::Value, key_expr::OwnedKeyExpr, query::Parameters, sample::Sample, time::Timestamp, + Session, }; use super::{digest::*, Snapshotter}; diff --git a/plugins/zenoh-plugin-storage-manager/src/replica/mod.rs b/plugins/zenoh-plugin-storage-manager/src/replica/mod.rs index 4766914e21..a9302cd8cf 100644 --- a/plugins/zenoh-plugin-storage-manager/src/replica/mod.rs +++ b/plugins/zenoh-plugin-storage-manager/src/replica/mod.rs @@ -24,7 +24,7 @@ use std::{ use flume::{Receiver, Sender}; use futures::{pin_mut, select, FutureExt}; use tokio::{sync::RwLock, time::interval}; -use zenoh::{key_expr::keyexpr, prelude::*}; +use zenoh::key_expr::keyexpr; use zenoh_backend_traits::config::{ReplicaConfig, StorageConfig}; use crate::{backends_mgt::StoreIntercept, storages_mgt::StorageMessage}; diff --git a/plugins/zenoh-plugin-storage-manager/src/replica/storage.rs b/plugins/zenoh-plugin-storage-manager/src/replica/storage.rs index 956cd57f8d..6fafe04abd 100644 --- a/plugins/zenoh-plugin-storage-manager/src/replica/storage.rs +++ b/plugins/zenoh-plugin-storage-manager/src/replica/storage.rs @@ -35,7 +35,7 @@ use zenoh::{ }, query::{ConsolidationMode, QueryTarget}, sample::{Sample, SampleBuilder, SampleKind}, - session::{Session, SessionDeclarations}, + session::Session, time::{Timestamp, NTP64}, }; use zenoh_backend_traits::{ diff --git a/plugins/zenoh-plugin-storage-manager/tests/operations.rs b/plugins/zenoh-plugin-storage-manager/tests/operations.rs index 483b87e223..c3ddf67d2e 100644 --- a/plugins/zenoh-plugin-storage-manager/tests/operations.rs +++ b/plugins/zenoh-plugin-storage-manager/tests/operations.rs @@ -20,8 +20,7 @@ use std::{borrow::Cow, str::FromStr, thread::sleep}; use tokio::runtime::Runtime; use zenoh::{ - internal::zasync_executor_init, prelude::*, query::Reply, sample::Sample, time::Timestamp, - Config, Session, + internal::zasync_executor_init, query::Reply, sample::Sample, time::Timestamp, Config, Session, }; use zenoh_plugin_trait::Plugin; diff --git a/plugins/zenoh-plugin-storage-manager/tests/wildcard.rs b/plugins/zenoh-plugin-storage-manager/tests/wildcard.rs index 6a6e36b2fd..b4c7ddd8f2 100644 --- a/plugins/zenoh-plugin-storage-manager/tests/wildcard.rs +++ b/plugins/zenoh-plugin-storage-manager/tests/wildcard.rs @@ -21,8 +21,7 @@ use std::{borrow::Cow, str::FromStr, thread::sleep}; // use std::collections::HashMap; use tokio::runtime::Runtime; use zenoh::{ - internal::zasync_executor_init, prelude::*, query::Reply, sample::Sample, time::Timestamp, - Config, Session, + internal::zasync_executor_init, query::Reply, sample::Sample, time::Timestamp, Config, Session, }; use zenoh_plugin_trait::Plugin; diff --git a/zenoh-ext/examples/examples/z_query_sub.rs b/zenoh-ext/examples/examples/z_query_sub.rs index 0931d289fe..0d01cb20c7 100644 --- a/zenoh-ext/examples/examples/z_query_sub.rs +++ b/zenoh-ext/examples/examples/z_query_sub.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // use clap::{arg, Parser}; -use zenoh::{config::Config, prelude::*, query::ReplyKeyExpr}; +use zenoh::{config::Config, query::ReplyKeyExpr}; use zenoh_ext::*; use zenoh_ext_examples::CommonArgs; diff --git a/zenoh-ext/src/group.rs b/zenoh-ext/src/group.rs index f8de27d662..c842c9eed6 100644 --- a/zenoh-ext/src/group.rs +++ b/zenoh-ext/src/group.rs @@ -29,10 +29,9 @@ use zenoh::{ bytes::ZBytesReader, internal::{bail, Condition, TaskController}, key_expr::{keyexpr, KeyExpr, OwnedKeyExpr}, - prelude::*, pubsub::Publisher, qos::Priority, - Session, + Error as ZError, Result as ZResult, Session, }; const GROUP_PREFIX: &str = "zenoh/ext/net/group"; diff --git a/zenoh-ext/src/publication_cache.rs b/zenoh-ext/src/publication_cache.rs index 9c1536c2a1..af548a3b6c 100644 --- a/zenoh-ext/src/publication_cache.rs +++ b/zenoh-ext/src/publication_cache.rs @@ -25,14 +25,13 @@ use zenoh::{ pubsub::FlumeSubscriber, query::{Query, Queryable, ZenohParameters}, sample::{Locality, Sample}, - session::{SessionDeclarations, SessionRef}, - Error, Resolvable, Resolve, Result as ZResult, + Error, Resolvable, Resolve, Result as ZResult, Session, }; /// The builder of PublicationCache, allowing to configure it. #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] pub struct PublicationCacheBuilder<'a, 'b, 'c> { - session: SessionRef<'a>, + session: &'a Session, pub_key_expr: ZResult>, queryable_prefix: Option>>, queryable_origin: Option, @@ -43,7 +42,7 @@ pub struct PublicationCacheBuilder<'a, 'b, 'c> { impl<'a, 'b, 'c> PublicationCacheBuilder<'a, 'b, 'c> { pub(crate) fn new( - session: SessionRef<'a>, + session: &'a Session, pub_key_expr: ZResult>, ) -> PublicationCacheBuilder<'a, 'b, 'c> { PublicationCacheBuilder { @@ -95,8 +94,8 @@ impl<'a, 'b, 'c> PublicationCacheBuilder<'a, 'b, 'c> { } } -impl<'a> Resolvable for PublicationCacheBuilder<'a, '_, '_> { - type To = ZResult>; +impl Resolvable for PublicationCacheBuilder<'_, '_, '_> { + type To = ZResult; } impl Wait for PublicationCacheBuilder<'_, '_, '_> { @@ -105,7 +104,7 @@ impl Wait for PublicationCacheBuilder<'_, '_, '_> { } } -impl<'a> IntoFuture for PublicationCacheBuilder<'a, '_, '_> { +impl IntoFuture for PublicationCacheBuilder<'_, '_, '_> { type Output = ::To; type IntoFuture = Ready<::To>; @@ -114,14 +113,14 @@ impl<'a> IntoFuture for PublicationCacheBuilder<'a, '_, '_> { } } -pub struct PublicationCache<'a> { - local_sub: FlumeSubscriber<'a>, - _queryable: Queryable<'a, flume::Receiver>, +pub struct PublicationCache { + local_sub: FlumeSubscriber, + _queryable: Queryable>, task: TerminatableTask, } -impl<'a> PublicationCache<'a> { - fn new(conf: PublicationCacheBuilder<'a, '_, '_>) -> ZResult> { +impl PublicationCache { + fn new(conf: PublicationCacheBuilder<'_, '_, '_>) -> ZResult { let key_expr = conf.pub_key_expr?; // the queryable_prefix (optional), and the key_expr for PublicationCache's queryable ("[]/") let (queryable_prefix, queryable_key_expr): (Option, KeyExpr) = @@ -258,7 +257,7 @@ impl<'a> PublicationCache<'a> { /// Undeclare this [`PublicationCache`]`. #[inline] - pub fn undeclare(self) -> impl Resolve> + 'a { + pub fn undeclare(self) -> impl Resolve> { ResolveFuture::new(async move { let PublicationCache { _queryable, diff --git a/zenoh-ext/src/querying_subscriber.rs b/zenoh-ext/src/querying_subscriber.rs index 813d2963db..9796109510 100644 --- a/zenoh-ext/src/querying_subscriber.rs +++ b/zenoh-ext/src/querying_subscriber.rs @@ -30,9 +30,8 @@ use zenoh::{ pubsub::Subscriber, query::{QueryConsolidation, QueryTarget, ReplyKeyExpr, Selector}, sample::{Locality, Sample, SampleBuilder}, - session::{SessionDeclarations, SessionRef}, time::Timestamp, - Error, Resolvable, Resolve, Result as ZResult, + Error, Resolvable, Resolve, Result as ZResult, Session, }; use crate::ExtractSample; @@ -40,7 +39,7 @@ use crate::ExtractSample; /// The builder of [`FetchingSubscriber`], allowing to configure it. #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] pub struct QueryingSubscriberBuilder<'a, 'b, KeySpace, Handler> { - pub(crate) session: SessionRef<'a>, + pub(crate) session: &'a Session, pub(crate) key_expr: ZResult>, pub(crate) key_space: KeySpace, pub(crate) origin: Locality, @@ -50,10 +49,17 @@ pub struct QueryingSubscriberBuilder<'a, 'b, KeySpace, Handler> { pub(crate) query_accept_replies: ReplyKeyExpr, pub(crate) query_timeout: Duration, pub(crate) handler: Handler, + pub(crate) undeclare_on_drop: bool, } impl<'a, 'b, KeySpace> QueryingSubscriberBuilder<'a, 'b, KeySpace, DefaultHandler> { /// Add callback to [`FetchingSubscriber`]. + /// + /// Subscriber will not be undeclared when dropped, with the callback running + /// in background until the session is closed. + /// + /// It is in fact just a convenient shortcut for + /// `.with(my_callback).undeclare_on_drop(false)`. #[inline] pub fn callback( self, @@ -62,37 +68,17 @@ impl<'a, 'b, KeySpace> QueryingSubscriberBuilder<'a, 'b, KeySpace, DefaultHandle where Callback: Fn(Sample) + Send + Sync + 'static, { - let QueryingSubscriberBuilder { - session, - key_expr, - key_space, - origin, - query_selector, - query_target, - query_consolidation, - query_accept_replies, - query_timeout, - handler: _, - } = self; - QueryingSubscriberBuilder { - session, - key_expr, - key_space, - origin, - query_selector, - query_target, - query_consolidation, - query_accept_replies, - query_timeout, - handler: callback, - } + self.with(callback).undeclare_on_drop(false) } /// Add callback to [`FetchingSubscriber`]. /// /// Using this guarantees that your callback will never be called concurrently. /// If your callback is also accepted by the [`callback`](QueryingSubscriberBuilder::callback) - /// method, we suggest you use it instead of `callback_mut` + /// method, we suggest you use it instead of `callback_mut`. + /// + /// Subscriber will not be undeclared when dropped, with the callback running + /// in background until the session is closed. #[inline] pub fn callback_mut( self, @@ -124,6 +110,7 @@ impl<'a, 'b, KeySpace> QueryingSubscriberBuilder<'a, 'b, KeySpace, DefaultHandle query_accept_replies, query_timeout, handler: _, + undeclare_on_drop, } = self; QueryingSubscriberBuilder { session, @@ -136,11 +123,12 @@ impl<'a, 'b, KeySpace> QueryingSubscriberBuilder<'a, 'b, KeySpace, DefaultHandle query_accept_replies, query_timeout, handler, + undeclare_on_drop, } } } -impl<'a, 'b, Handler> QueryingSubscriberBuilder<'a, 'b, crate::UserSpace, Handler> { +impl<'b, Handler> QueryingSubscriberBuilder<'_, 'b, crate::UserSpace, Handler> { /// Change the subscription reliability. #[cfg(feature = "unstable")] #[deprecated( @@ -219,21 +207,33 @@ impl<'a, 'b, Handler> QueryingSubscriberBuilder<'a, 'b, crate::UserSpace, Handle } } -impl<'a, 'b, KeySpace, Handler> QueryingSubscriberBuilder<'a, 'b, KeySpace, Handler> { +impl QueryingSubscriberBuilder<'_, '_, KeySpace, Handler> { /// Change the timeout to be used for queries. #[inline] pub fn query_timeout(mut self, query_timeout: Duration) -> Self { self.query_timeout = query_timeout; self } + + /// Set whether the subscriber will be undeclared when dropped. + /// + /// The method is usually used in combination with a callback like in + /// [`callback`](Self::callback) method, or a channel sender. + /// Be careful when using it, as subscribers not undeclared will consume + /// resources until the session is closed. + #[inline] + pub fn undeclare_on_drop(mut self, undeclare_on_drop: bool) -> Self { + self.undeclare_on_drop = undeclare_on_drop; + self + } } -impl<'a, KeySpace, Handler> Resolvable for QueryingSubscriberBuilder<'a, '_, KeySpace, Handler> +impl Resolvable for QueryingSubscriberBuilder<'_, '_, KeySpace, Handler> where Handler: IntoHandler<'static, Sample>, Handler::Handler: Send, { - type To = ZResult>; + type To = ZResult>; } impl Wait for QueryingSubscriberBuilder<'_, '_, KeySpace, Handler> @@ -278,13 +278,14 @@ where .wait(), }, handler: self.handler, + undeclare_on_drop: self.undeclare_on_drop, phantom: std::marker::PhantomData, } .wait() } } -impl<'a, KeySpace, Handler> IntoFuture for QueryingSubscriberBuilder<'a, '_, KeySpace, Handler> +impl IntoFuture for QueryingSubscriberBuilder<'_, '_, KeySpace, Handler> where KeySpace: Into + Clone, Handler: IntoHandler<'static, Sample> + Send, @@ -370,12 +371,13 @@ pub struct FetchingSubscriberBuilder< > where TryIntoSample: ExtractSample, { - pub(crate) session: SessionRef<'a>, + pub(crate) session: &'a Session, pub(crate) key_expr: ZResult>, pub(crate) key_space: KeySpace, pub(crate) origin: Locality, pub(crate) fetch: Fetch, pub(crate) handler: Handler, + pub(crate) undeclare_on_drop: bool, pub(crate) phantom: std::marker::PhantomData, } @@ -400,6 +402,7 @@ where origin: self.origin, fetch: self.fetch, handler: self.handler, + undeclare_on_drop: self.undeclare_on_drop, phantom: std::marker::PhantomData, } } @@ -416,6 +419,12 @@ where TryIntoSample: ExtractSample, { /// Add callback to [`FetchingSubscriber`]. + /// + /// Subscriber will not be undeclared when dropped, with the callback running + /// in background until the session is closed. + /// + /// It is in fact just a convenient shortcut for + /// `.with(my_callback).undeclare_on_drop(false)`. #[inline] pub fn callback( self, @@ -424,31 +433,17 @@ where where Callback: Fn(Sample) + Send + Sync + 'static, { - let FetchingSubscriberBuilder { - session, - key_expr, - key_space, - origin, - fetch, - handler: _, - phantom, - } = self; - FetchingSubscriberBuilder { - session, - key_expr, - key_space, - origin, - fetch, - handler: callback, - phantom, - } + self.with(callback).undeclare_on_drop(false) } /// Add callback to [`FetchingSubscriber`]. /// /// Using this guarantees that your callback will never be called concurrently. /// If your callback is also accepted by the [`callback`](FetchingSubscriberBuilder::callback) - /// method, we suggest you use it instead of `callback_mut` + /// method, we suggest you use it instead of `callback_mut`. + /// + /// Subscriber will not be undeclared when dropped, with the callback running + /// in background until the session is closed. #[inline] pub fn callback_mut( self, @@ -483,6 +478,7 @@ where origin, fetch, handler: _, + undeclare_on_drop, phantom, } = self; FetchingSubscriberBuilder { @@ -492,18 +488,17 @@ where origin, fetch, handler, + undeclare_on_drop, phantom, } } } impl< - 'a, - 'b, Handler, Fetch: FnOnce(Box) -> ZResult<()>, TryIntoSample, - > FetchingSubscriberBuilder<'a, 'b, crate::UserSpace, Handler, Fetch, TryIntoSample> + > FetchingSubscriberBuilder<'_, '_, crate::UserSpace, Handler, Fetch, TryIntoSample> where TryIntoSample: ExtractSample, { @@ -551,18 +546,39 @@ where } impl< - 'a, KeySpace, Handler, Fetch: FnOnce(Box) -> ZResult<()>, TryIntoSample, - > Resolvable for FetchingSubscriberBuilder<'a, '_, KeySpace, Handler, Fetch, TryIntoSample> + > FetchingSubscriberBuilder<'_, '_, KeySpace, Handler, Fetch, TryIntoSample> +where + TryIntoSample: ExtractSample, +{ + /// Set whether the subscriber will be undeclared when dropped. + /// + /// The method is usually used in combination with a callback like in + /// [`callback`](Self::callback) method, or a channel sender. + /// Be careful when using it, as subscribers not undeclared will consume + /// resources until the session is closed. + #[inline] + pub fn undeclare_on_drop(mut self, undeclare_on_drop: bool) -> Self { + self.undeclare_on_drop = undeclare_on_drop; + self + } +} + +impl< + KeySpace, + Handler, + Fetch: FnOnce(Box) -> ZResult<()>, + TryIntoSample, + > Resolvable for FetchingSubscriberBuilder<'_, '_, KeySpace, Handler, Fetch, TryIntoSample> where Handler: IntoHandler<'static, Sample>, Handler::Handler: Send, TryIntoSample: ExtractSample, { - type To = ZResult>; + type To = ZResult>; } impl< @@ -583,12 +599,11 @@ where } impl< - 'a, KeySpace, Handler, Fetch: FnOnce(Box) -> ZResult<()> + Send + Sync, TryIntoSample, - > IntoFuture for FetchingSubscriberBuilder<'a, '_, KeySpace, Handler, Fetch, TryIntoSample> + > IntoFuture for FetchingSubscriberBuilder<'_, '_, KeySpace, Handler, Fetch, TryIntoSample> where KeySpace: Into, Handler: IntoHandler<'static, Sample> + Send, @@ -615,7 +630,7 @@ where /// ```no_run /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; +/// use zenoh::Wait; /// use zenoh_ext::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); @@ -634,28 +649,29 @@ where /// } /// # } /// ``` -pub struct FetchingSubscriber<'a, Handler> { - subscriber: Subscriber<'a, ()>, +pub struct FetchingSubscriber { + subscriber: Subscriber<()>, callback: Arc, state: Arc>, handler: Handler, } -impl std::ops::Deref for FetchingSubscriber<'_, Handler> { +impl std::ops::Deref for FetchingSubscriber { type Target = Handler; fn deref(&self) -> &Self::Target { &self.handler } } -impl std::ops::DerefMut for FetchingSubscriber<'_, Handler> { +impl std::ops::DerefMut for FetchingSubscriber { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.handler } } -impl<'a, Handler> FetchingSubscriber<'a, Handler> { +impl FetchingSubscriber { fn new< + 'a, KeySpace, InputHandler, Fetch: FnOnce(Box) -> ZResult<()> + Send + Sync, @@ -711,14 +727,16 @@ impl<'a, Handler> FetchingSubscriber<'a, Handler> { crate::KeySpace::User => conf .session .declare_subscriber(&key_expr) - .callback(sub_callback) + .with(sub_callback) + .undeclare_on_drop(conf.undeclare_on_drop) .allowed_origin(conf.origin) .wait()?, crate::KeySpace::Liveliness => conf .session .liveliness() .declare_subscriber(&key_expr) - .callback(sub_callback) + .with(sub_callback) + .undeclare_on_drop(conf.undeclare_on_drop) .wait()?, }; @@ -737,7 +755,7 @@ impl<'a, Handler> FetchingSubscriber<'a, Handler> { /// Undeclare this [`FetchingSubscriber`]`. #[inline] - pub fn undeclare(self) -> impl Resolve> + 'a { + pub fn undeclare(self) -> impl Resolve> { self.subscriber.undeclare() } @@ -756,7 +774,7 @@ impl<'a, Handler> FetchingSubscriber<'a, Handler> { /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; + /// use zenoh::Wait; /// use zenoh_ext::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); @@ -834,7 +852,7 @@ impl Drop for RepliesHandler { /// ```no_run /// # #[tokio::main] /// # async fn main() { -/// # use zenoh::prelude::*; +/// # use zenoh::Wait; /// # use zenoh_ext::*; /// # /// # let session = zenoh::open(zenoh::config::peer()).await.unwrap(); diff --git a/zenoh-ext/src/session_ext.rs b/zenoh-ext/src/session_ext.rs index 606f00743b..7c68f88ddb 100644 --- a/zenoh-ext/src/session_ext.rs +++ b/zenoh-ext/src/session_ext.rs @@ -11,65 +11,23 @@ // Contributors: // ZettaScale Zenoh Team, // -use std::{convert::TryInto, sync::Arc}; -use zenoh::{ - key_expr::KeyExpr, - session::{Session, SessionRef}, - Error, -}; +use zenoh::{key_expr::KeyExpr, session::Session, Error}; use super::PublicationCacheBuilder; /// Some extensions to the [`zenoh::Session`](zenoh::Session) pub trait SessionExt<'s, 'a> { - fn declare_publication_cache<'b, 'c, TryIntoKeyExpr>( - &'s self, - pub_key_expr: TryIntoKeyExpr, - ) -> PublicationCacheBuilder<'a, 'b, 'c> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into; -} - -impl<'s, 'a> SessionExt<'s, 'a> for SessionRef<'a> { - fn declare_publication_cache<'b, 'c, TryIntoKeyExpr>( - &'s self, - pub_key_expr: TryIntoKeyExpr, - ) -> PublicationCacheBuilder<'a, 'b, 'c> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into, - { - PublicationCacheBuilder::new(self.clone(), pub_key_expr.try_into().map_err(Into::into)) - } -} - -impl<'a> SessionExt<'a, 'a> for Session { - fn declare_publication_cache<'b, 'c, TryIntoKeyExpr>( - &'a self, - pub_key_expr: TryIntoKeyExpr, - ) -> PublicationCacheBuilder<'a, 'b, 'c> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into, - { - SessionRef::Borrow(self).declare_publication_cache(pub_key_expr) - } -} - -impl<'s> SessionExt<'s, 'static> for Arc { /// Examples: /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// use zenoh::config::ModeDependentValue::Unique; /// use zenoh_ext::SessionExt; /// /// let mut config = zenoh::config::default(); /// config.timestamping.set_enabled(Some(Unique(true))); - /// let session = zenoh::open(config).await.unwrap().into_arc(); + /// let session = zenoh::open(config).await.unwrap(); /// let publication_cache = session.declare_publication_cache("key/expression").await.unwrap(); /// tokio::task::spawn(async move { /// publication_cache.key_expr(); @@ -79,11 +37,21 @@ impl<'s> SessionExt<'s, 'static> for Arc { fn declare_publication_cache<'b, 'c, TryIntoKeyExpr>( &'s self, pub_key_expr: TryIntoKeyExpr, - ) -> PublicationCacheBuilder<'static, 'b, 'c> + ) -> PublicationCacheBuilder<'a, 'b, 'c> + where + TryIntoKeyExpr: TryInto>, + >>::Error: Into; +} + +impl<'a> SessionExt<'a, 'a> for Session { + fn declare_publication_cache<'b, 'c, TryIntoKeyExpr>( + &'a self, + pub_key_expr: TryIntoKeyExpr, + ) -> PublicationCacheBuilder<'a, 'b, 'c> where TryIntoKeyExpr: TryInto>, >>::Error: Into, { - SessionRef::Shared(self.clone()).declare_publication_cache(pub_key_expr) + PublicationCacheBuilder::new(self, pub_key_expr.try_into().map_err(Into::into)) } } diff --git a/zenoh-ext/src/subscriber_ext.rs b/zenoh-ext/src/subscriber_ext.rs index cfd810185a..a48c4fe500 100644 --- a/zenoh-ext/src/subscriber_ext.rs +++ b/zenoh-ext/src/subscriber_ext.rs @@ -32,7 +32,7 @@ pub trait SubscriberForward<'a, S> { type Output; fn forward(&'a mut self, sink: S) -> Self::Output; } -impl<'a, S> SubscriberForward<'a, S> for Subscriber<'_, flume::Receiver> +impl<'a, S> SubscriberForward<'a, S> for Subscriber> where S: futures::sink::Sink, { @@ -60,7 +60,7 @@ pub trait SubscriberBuilderExt<'a, 'b, Handler> { /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; + /// use zenoh::Wait; /// use zenoh_ext::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); @@ -104,7 +104,6 @@ pub trait SubscriberBuilderExt<'a, 'b, Handler> { /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// use zenoh_ext::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); @@ -138,7 +137,7 @@ impl<'a, 'b, Handler> SubscriberBuilderExt<'a, 'b, Handler> for SubscriberBuilde /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; + /// use zenoh::Wait; /// use zenoh_ext::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); @@ -174,6 +173,7 @@ impl<'a, 'b, Handler> SubscriberBuilderExt<'a, 'b, Handler> for SubscriberBuilde origin: self.origin, fetch, handler: self.handler, + undeclare_on_drop: true, phantom: std::marker::PhantomData, } } @@ -193,7 +193,6 @@ impl<'a, 'b, Handler> SubscriberBuilderExt<'a, 'b, Handler> for SubscriberBuilde /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// use zenoh_ext::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); @@ -221,6 +220,7 @@ impl<'a, 'b, Handler> SubscriberBuilderExt<'a, 'b, Handler> for SubscriberBuilde query_consolidation: QueryConsolidation::from(zenoh::query::ConsolidationMode::None), query_accept_replies: ReplyKeyExpr::default(), query_timeout: Duration::from_secs(10), + undeclare_on_drop: true, handler: self.handler, } } @@ -246,7 +246,7 @@ impl<'a, 'b, Handler> SubscriberBuilderExt<'a, 'b, Handler> /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; + /// use zenoh::Wait; /// use zenoh_ext::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); @@ -284,6 +284,7 @@ impl<'a, 'b, Handler> SubscriberBuilderExt<'a, 'b, Handler> origin: Locality::default(), fetch, handler: self.handler, + undeclare_on_drop: true, phantom: std::marker::PhantomData, } } @@ -304,7 +305,6 @@ impl<'a, 'b, Handler> SubscriberBuilderExt<'a, 'b, Handler> /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// use zenoh_ext::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); @@ -330,6 +330,7 @@ impl<'a, 'b, Handler> SubscriberBuilderExt<'a, 'b, Handler> query_consolidation: QueryConsolidation::DEFAULT, query_accept_replies: ReplyKeyExpr::MatchingQuery, query_timeout: Duration::from_secs(10), + undeclare_on_drop: true, handler: self.handler, } } diff --git a/zenoh-ext/tests/liveliness.rs b/zenoh-ext/tests/liveliness.rs index b1c231006d..d211505c4c 100644 --- a/zenoh-ext/tests/liveliness.rs +++ b/zenoh-ext/tests/liveliness.rs @@ -15,13 +15,14 @@ use zenoh::{ config::{self, EndPoint, WhatAmI}, sample::SampleKind, + Wait, }; #[tokio::test(flavor = "multi_thread", worker_threads = 4)] async fn test_liveliness_querying_subscriber_clique() { use std::time::Duration; - use zenoh::{internal::ztimeout, prelude::*}; + use zenoh::internal::ztimeout; use zenoh_ext::SubscriberBuilderExt; const TIMEOUT: Duration = Duration::from_secs(60); @@ -99,7 +100,7 @@ async fn test_liveliness_querying_subscriber_clique() { async fn test_liveliness_querying_subscriber_brokered() { use std::time::Duration; - use zenoh::{internal::ztimeout, prelude::*}; + use zenoh::internal::ztimeout; use zenoh_ext::SubscriberBuilderExt; const TIMEOUT: Duration = Duration::from_secs(60); @@ -205,7 +206,7 @@ async fn test_liveliness_querying_subscriber_brokered() { async fn test_liveliness_fetching_subscriber_clique() { use std::time::Duration; - use zenoh::{internal::ztimeout, prelude::*}; + use zenoh::internal::ztimeout; use zenoh_ext::SubscriberBuilderExt; const TIMEOUT: Duration = Duration::from_secs(60); @@ -287,7 +288,7 @@ async fn test_liveliness_fetching_subscriber_clique() { async fn test_liveliness_fetching_subscriber_brokered() { use std::time::Duration; - use zenoh::{internal::ztimeout, prelude::*}; + use zenoh::internal::ztimeout; use zenoh_ext::SubscriberBuilderExt; const TIMEOUT: Duration = Duration::from_secs(60); diff --git a/zenoh/src/api/admin.rs b/zenoh/src/api/admin.rs index 8c20a275c1..060bb78c43 100644 --- a/zenoh/src/api/admin.rs +++ b/zenoh/src/api/admin.rs @@ -32,9 +32,9 @@ use super::{ key_expr::KeyExpr, queryable::Query, sample::{DataInfo, Locality, SampleKind}, - session::Session, subscriber::SubscriberKind, }; +use crate::api::session::WeakSession; lazy_static::lazy_static!( static ref KE_STARSTAR: &'static keyexpr = unsafe { keyexpr::from_str_unchecked("**") }; @@ -44,10 +44,10 @@ lazy_static::lazy_static!( static ref KE_LINK: &'static keyexpr = unsafe { keyexpr::from_str_unchecked("link") }; ); -pub(crate) fn init(session: &Session) { - if let Ok(own_zid) = keyexpr::new(&session.zid().to_string()) { +pub(crate) fn init(session: WeakSession) { + if let Ok(own_zid) = keyexpr::new(&session.runtime.zid().to_string()) { let admin_key = KeyExpr::from(*KE_PREFIX / own_zid / *KE_SESSION / *KE_STARSTAR) - .to_wire(session) + .to_wire(&session) .to_owned(); let _admin_qabl = session.declare_queryable_inner( @@ -56,13 +56,13 @@ pub(crate) fn init(session: &Session) { Locality::SessionLocal, Arc::new({ let session = session.clone(); - move |q| super::admin::on_admin_query(&session, q) + move |q| on_admin_query(&session, q) }), ); } } -pub(crate) fn on_admin_query(session: &Session, query: Query) { +pub(crate) fn on_admin_query(session: &WeakSession, query: Query) { fn reply_peer(own_zid: &keyexpr, query: &Query, peer: TransportPeer) { let zid = peer.zid.to_string(); if let Ok(zid) = keyexpr::new(&zid) { @@ -104,7 +104,7 @@ pub(crate) fn on_admin_query(session: &Session, query: Query) { } } - if let Ok(own_zid) = keyexpr::new(&session.zid().to_string()) { + if let Ok(own_zid) = keyexpr::new(&session.runtime.zid().to_string()) { for transport in zenoh_runtime::ZRuntime::Net .block_in_place(session.runtime.manager().get_transports_unicast()) { @@ -124,14 +124,12 @@ pub(crate) fn on_admin_query(session: &Session, query: Query) { #[derive(Clone)] pub(crate) struct Handler { - pub(crate) session: Arc, + pub(crate) session: WeakSession, } impl Handler { - pub(crate) fn new(session: Session) -> Self { - Self { - session: Arc::new(session), - } + pub(crate) fn new(session: WeakSession) -> Self { + Self { session } } } @@ -157,7 +155,7 @@ impl TransportMulticastEventHandler for Handler { &self, peer: zenoh_transport::TransportPeer, ) -> ZResult> { - if let Ok(own_zid) = keyexpr::new(&self.session.zid().to_string()) { + if let Ok(own_zid) = keyexpr::new(&self.session.runtime.zid().to_string()) { if let Ok(zid) = keyexpr::new(&peer.zid.to_string()) { let expr = WireExpr::from( &(*KE_PREFIX / own_zid / *KE_SESSION / *KE_TRANSPORT_UNICAST / zid), @@ -200,7 +198,7 @@ impl TransportMulticastEventHandler for Handler { pub(crate) struct PeerHandler { pub(crate) expr: WireExpr<'static>, - pub(crate) session: Arc, + pub(crate) session: WeakSession, } impl TransportPeerEventHandler for PeerHandler { diff --git a/zenoh/src/api/builders/publisher.rs b/zenoh/src/api/builders/publisher.rs index d361272f66..ba8ac98947 100644 --- a/zenoh/src/api/builders/publisher.rs +++ b/zenoh/src/api/builders/publisher.rs @@ -21,14 +21,16 @@ use zenoh_protocol::{core::CongestionControl, network::Mapping}; use super::sample::TimestampBuilderTrait; #[cfg(feature = "unstable")] use crate::api::sample::SourceInfo; -use crate::api::{ - builders::sample::{EncodingBuilderTrait, QoSBuilderTrait, SampleBuilderTrait}, - bytes::{OptionZBytes, ZBytes}, - encoding::Encoding, - key_expr::KeyExpr, - publisher::{Priority, Publisher}, - sample::{Locality, SampleKind}, - session::SessionRef, +use crate::{ + api::{ + builders::sample::{EncodingBuilderTrait, QoSBuilderTrait, SampleBuilderTrait}, + bytes::{OptionZBytes, ZBytes}, + encoding::Encoding, + key_expr::KeyExpr, + publisher::{Priority, Publisher}, + sample::{Locality, SampleKind}, + }, + Session, }; pub type SessionPutBuilder<'a, 'b> = @@ -57,7 +59,7 @@ pub struct PublicationBuilderDelete; /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::{bytes::Encoding, prelude::*, qos::CongestionControl}; +/// use zenoh::{bytes::Encoding, qos::CongestionControl}; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// session @@ -237,7 +239,7 @@ impl IntoFuture for PublicationBuilder, PublicationBuil /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::{prelude::*, qos::CongestionControl}; +/// use zenoh::qos::CongestionControl; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session @@ -249,8 +251,8 @@ impl IntoFuture for PublicationBuilder, PublicationBuil /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] #[derive(Debug)] -pub struct PublisherBuilder<'a, 'b: 'a> { - pub(crate) session: SessionRef<'a>, +pub struct PublisherBuilder<'a, 'b> { + pub(crate) session: &'a Session, pub(crate) key_expr: ZResult>, pub(crate) encoding: Encoding, pub(crate) congestion_control: CongestionControl, @@ -264,7 +266,7 @@ pub struct PublisherBuilder<'a, 'b: 'a> { impl<'a, 'b> Clone for PublisherBuilder<'a, 'b> { fn clone(&self) -> Self { Self { - session: self.session.clone(), + session: self.session, key_expr: match &self.key_expr { Ok(k) => Ok(k.clone()), Err(e) => Err(zerror!("Cloned KE Error: {}", e).into()), @@ -329,9 +331,11 @@ impl<'a, 'b> PublisherBuilder<'a, 'b> { } // internal function for performing the publication - fn create_one_shot_publisher(self) -> ZResult> { + fn create_one_shot_publisher(self) -> ZResult> { Ok(Publisher { - session: self.session, + #[cfg(feature = "unstable")] + session_id: self.session.0.runtime.zid(), + session: self.session.downgrade(), id: 0, // This is a one shot Publisher key_expr: self.key_expr?, encoding: self.encoding, @@ -349,15 +353,15 @@ impl<'a, 'b> PublisherBuilder<'a, 'b> { } impl<'a, 'b> Resolvable for PublisherBuilder<'a, 'b> { - type To = ZResult>; + type To = ZResult>; } impl<'a, 'b> Wait for PublisherBuilder<'a, 'b> { fn wait(self) -> ::To { let mut key_expr = self.key_expr?; - if !key_expr.is_fully_optimized(&self.session) { - let session_id = self.session.id; - let expr_id = self.session.declare_prefix(key_expr.as_str()).wait(); + if !key_expr.is_fully_optimized(&self.session.0) { + let session_id = self.session.0.id; + let expr_id = self.session.0.declare_prefix(key_expr.as_str()).wait()?; let prefix_len = key_expr .len() .try_into() @@ -385,23 +389,27 @@ impl<'a, 'b> Wait for PublisherBuilder<'a, 'b> { } } } - self.session - .declare_publisher_inner(key_expr.clone(), self.destination) - .map(|id| Publisher { - session: self.session, - id, - key_expr, - encoding: self.encoding, - congestion_control: self.congestion_control, - priority: self.priority, - is_express: self.is_express, - destination: self.destination, - #[cfg(feature = "unstable")] - reliability: self.reliability, - #[cfg(feature = "unstable")] - matching_listeners: Default::default(), - undeclare_on_drop: true, - }) + let id = self + .session + .0 + .declare_publisher_inner(key_expr.clone(), self.destination)?; + Ok(Publisher { + #[cfg(feature = "unstable")] + session_id: self.session.0.runtime.zid(), + session: self.session.downgrade(), + id, + key_expr, + encoding: self.encoding, + congestion_control: self.congestion_control, + priority: self.priority, + is_express: self.is_express, + destination: self.destination, + #[cfg(feature = "unstable")] + reliability: self.reliability, + #[cfg(feature = "unstable")] + matching_listeners: Default::default(), + undeclare_on_drop: true, + }) } } diff --git a/zenoh/src/api/handlers/callback.rs b/zenoh/src/api/handlers/callback.rs index 4f49e7c41f..7e609949ef 100644 --- a/zenoh/src/api/handlers/callback.rs +++ b/zenoh/src/api/handlers/callback.rs @@ -30,11 +30,31 @@ where F: Fn(T) + Send + Sync + 'a, { type Handler = (); + fn into_handler(self) -> (Callback<'a, T>, Self::Handler) { (Dyn::from(self), ()) } } +impl<'a, T, F, H> IntoHandler<'a, T> for (F, H) +where + F: Fn(T) + Send + Sync + 'a, +{ + type Handler = H; + + fn into_handler(self) -> (Callback<'a, T>, Self::Handler) { + (Dyn::from(self.0), self.1) + } +} + +impl<'a, T, H> IntoHandler<'a, T> for (Callback<'static, T>, H) { + type Handler = H; + + fn into_handler(self) -> (Callback<'a, T>, Self::Handler) { + self + } +} + impl IntoHandler<'static, T> for (flume::Sender, flume::Receiver) { type Handler = flume::Receiver; diff --git a/zenoh/src/api/info.rs b/zenoh/src/api/info.rs index 32bed0eb53..a63797c86c 100644 --- a/zenoh/src/api/info.rs +++ b/zenoh/src/api/info.rs @@ -19,7 +19,7 @@ use zenoh_config::wrappers::ZenohId; use zenoh_core::{Resolvable, Wait}; use zenoh_protocol::core::WhatAmI; -use super::session::SessionRef; +use crate::net::runtime::Runtime; /// A builder retuned by [`SessionInfo::zid()`](SessionInfo::zid) that allows /// to access the [`ZenohId`] of the current zenoh [`Session`](crate::Session). @@ -28,16 +28,14 @@ use super::session::SessionRef; /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let zid = session.info().zid().await; /// # } /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] -#[derive(Debug)] pub struct ZenohIdBuilder<'a> { - pub(crate) session: SessionRef<'a>, + runtime: &'a Runtime, } impl<'a> Resolvable for ZenohIdBuilder<'a> { @@ -46,7 +44,7 @@ impl<'a> Resolvable for ZenohIdBuilder<'a> { impl<'a> Wait for ZenohIdBuilder<'a> { fn wait(self) -> Self::To { - self.session.runtime.zid() + self.runtime.zid() } } @@ -67,7 +65,6 @@ impl<'a> IntoFuture for ZenohIdBuilder<'a> { /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let mut routers_zid = session.info().routers_zid().await; @@ -75,9 +72,8 @@ impl<'a> IntoFuture for ZenohIdBuilder<'a> { /// # } /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] -#[derive(Debug)] pub struct RoutersZenohIdBuilder<'a> { - pub(crate) session: SessionRef<'a>, + runtime: &'a Runtime, } impl<'a> Resolvable for RoutersZenohIdBuilder<'a> { @@ -88,7 +84,7 @@ impl<'a> Wait for RoutersZenohIdBuilder<'a> { fn wait(self) -> Self::To { Box::new( zenoh_runtime::ZRuntime::Application - .block_in_place(self.session.runtime.manager().get_transports_unicast()) + .block_in_place(self.runtime.manager().get_transports_unicast()) .into_iter() .filter_map(|s| { s.get_whatami() @@ -116,7 +112,6 @@ impl<'a> IntoFuture for RoutersZenohIdBuilder<'a> { /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let zid = session.info().zid().await; @@ -125,9 +120,8 @@ impl<'a> IntoFuture for RoutersZenohIdBuilder<'a> { /// # } /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] -#[derive(Debug)] pub struct PeersZenohIdBuilder<'a> { - pub(crate) session: SessionRef<'a>, + runtime: &'a Runtime, } impl<'a> Resolvable for PeersZenohIdBuilder<'a> { @@ -138,7 +132,7 @@ impl<'a> Wait for PeersZenohIdBuilder<'a> { fn wait(self) -> ::To { Box::new( zenoh_runtime::ZRuntime::Application - .block_in_place(self.session.runtime.manager().get_transports_unicast()) + .block_in_place(self.runtime.manager().get_transports_unicast()) .into_iter() .filter_map(|s| { s.get_whatami() @@ -159,32 +153,30 @@ impl<'a> IntoFuture for PeersZenohIdBuilder<'a> { } } -/// Struct returned by [`Session::info()`](crate::session::SessionDeclarations::info) which allows +/// Struct returned by [`Session::info()`](crate::Session::info) which allows /// to access information about the current zenoh [`Session`](crate::Session). /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let info = session.info(); /// let zid = info.zid().await; /// # } /// ``` -pub struct SessionInfo<'a> { - pub(crate) session: SessionRef<'a>, +pub struct SessionInfo { + pub(crate) runtime: Runtime, } -impl SessionInfo<'_> { +impl SessionInfo { /// Return the [`ZenohId`] of the current zenoh [`Session`](crate::Session). /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let zid = session.info().zid().await; @@ -192,7 +184,7 @@ impl SessionInfo<'_> { /// ``` pub fn zid(&self) -> ZenohIdBuilder<'_> { ZenohIdBuilder { - session: self.session.clone(), + runtime: &self.runtime, } } @@ -203,7 +195,6 @@ impl SessionInfo<'_> { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let mut routers_zid = session.info().routers_zid().await; @@ -212,7 +203,7 @@ impl SessionInfo<'_> { /// ``` pub fn routers_zid(&self) -> RoutersZenohIdBuilder<'_> { RoutersZenohIdBuilder { - session: self.session.clone(), + runtime: &self.runtime, } } @@ -222,7 +213,6 @@ impl SessionInfo<'_> { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let mut peers_zid = session.info().peers_zid().await; @@ -231,7 +221,7 @@ impl SessionInfo<'_> { /// ``` pub fn peers_zid(&self) -> PeersZenohIdBuilder<'_> { PeersZenohIdBuilder { - session: self.session.clone(), + runtime: &self.runtime, } } } diff --git a/zenoh/src/api/key_expr.rs b/zenoh/src/api/key_expr.rs index fc472e0db3..fff40a5286 100644 --- a/zenoh/src/api/key_expr.rs +++ b/zenoh/src/api/key_expr.rs @@ -25,7 +25,7 @@ use zenoh_protocol::{ }; use zenoh_result::ZResult; -use super::session::{Session, UndeclarableSealed}; +use super::session::{Session, SessionInner, UndeclarableSealed}; use crate::net::primitives::Primitives; #[derive(Clone, Debug)] @@ -492,7 +492,7 @@ impl<'a> KeyExpr<'a> { //pub(crate) fn is_optimized(&self, session: &Session) -> bool { // matches!(&self.0, KeyExprInner::Wire { expr_id, session_id, .. } | KeyExprInner::BorrowedWire { expr_id, session_id, .. } if *expr_id != 0 && session.id == *session_id) //} - pub(crate) fn is_fully_optimized(&self, session: &Session) -> bool { + pub(crate) fn is_fully_optimized(&self, session: &SessionInner) -> bool { match &self.0 { KeyExprInner::Wire { key_expr, @@ -509,7 +509,7 @@ impl<'a> KeyExpr<'a> { _ => false, } } - pub(crate) fn to_wire(&'a self, session: &Session) -> WireExpr<'a> { + pub(crate) fn to_wire(&'a self, session: &SessionInner) -> WireExpr<'a> { match &self.0 { KeyExprInner::Wire { key_expr, @@ -549,8 +549,10 @@ impl<'a> KeyExpr<'a> { } } -impl<'a> UndeclarableSealed<&'a Session, KeyExprUndeclaration<'a>> for KeyExpr<'a> { - fn undeclare_inner(self, session: &'a Session) -> KeyExprUndeclaration<'a> { +impl<'a> UndeclarableSealed<&'a Session> for KeyExpr<'a> { + type Undeclaration = KeyExprUndeclaration<'a>; + + fn undeclare_inner(self, session: &'a Session) -> Self::Undeclaration { KeyExprUndeclaration { session, expr: self, @@ -564,7 +566,6 @@ impl<'a> UndeclarableSealed<&'a Session, KeyExprUndeclaration<'a>> for KeyExpr<' /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let key_expr = session.declare_keyexpr("key/expression").await.unwrap(); @@ -592,7 +593,7 @@ impl Wait for KeyExprUndeclaration<'_> { session_id, .. } if *prefix_len as usize == key_expr.len() => { - if *session_id == session.id { + if *session_id == session.0.id { *expr_id } else { return Err(zerror!("Failed to undeclare {}, as it was declared by an other Session", expr).into()) @@ -605,7 +606,7 @@ impl Wait for KeyExprUndeclaration<'_> { session_id, .. } if *prefix_len as usize == key_expr.len() => { - if *session_id == session.id { + if *session_id == session.0.id { *expr_id } else { return Err(zerror!("Failed to undeclare {}, as it was declared by an other Session", expr).into()) @@ -614,10 +615,10 @@ impl Wait for KeyExprUndeclaration<'_> { _ => return Err(zerror!("Failed to undeclare {}, make sure you use the result of `Session::declare_keyexpr` to call `Session::undeclare`", expr).into()), }; tracing::trace!("undeclare_keyexpr({:?})", expr_id); - let mut state = zwrite!(session.state); + let mut state = zwrite!(session.0.state); state.local_resources.remove(&expr_id); - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_declare(zenoh_protocol::network::Declare { interest_id: None, diff --git a/zenoh/src/api/liveliness.rs b/zenoh/src/api/liveliness.rs index e9a12400fd..58d6ea7a71 100644 --- a/zenoh/src/api/liveliness.rs +++ b/zenoh/src/api/liveliness.rs @@ -19,6 +19,7 @@ use std::{ time::Duration, }; +use tracing::error; use zenoh_config::unwrap_or_default; use zenoh_core::{Resolvable, Resolve, Result as ZResult, Wait}; @@ -27,10 +28,11 @@ use super::{ key_expr::KeyExpr, query::Reply, sample::{Locality, Sample}, - session::{Session, SessionRef, UndeclarableSealed}, + session::{Session, UndeclarableSealed}, subscriber::{Subscriber, SubscriberInner}, Id, }; +use crate::api::session::WeakSession; /// A structure with functions to declare a /// [`LivelinessToken`](LivelinessToken), query @@ -49,7 +51,6 @@ use super::{ /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let liveliness = session @@ -64,7 +65,6 @@ use super::{ /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let replies = session.liveliness().get("key/**").await.unwrap(); @@ -80,7 +80,7 @@ use super::{ /// ```no_run /// # #[tokio::main] /// # async fn main() { -/// use zenoh::{prelude::*, sample::SampleKind}; +/// use zenoh::sample::SampleKind; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session.liveliness().declare_subscriber("key/**").await.unwrap(); @@ -94,7 +94,7 @@ use super::{ /// ``` #[zenoh_macros::unstable] pub struct Liveliness<'a> { - pub(crate) session: SessionRef<'a>, + pub(crate) session: &'a Session, } #[zenoh_macros::unstable] @@ -109,7 +109,6 @@ impl<'a> Liveliness<'a> { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let liveliness = session @@ -129,7 +128,7 @@ impl<'a> Liveliness<'a> { >>::Error: Into, { LivelinessTokenBuilder { - session: self.session.clone(), + session: self.session, key_expr: TryIntoKeyExpr::try_into(key_expr).map_err(Into::into), } } @@ -144,7 +143,7 @@ impl<'a> Liveliness<'a> { /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::{prelude::*, sample::SampleKind}; + /// use zenoh::sample::SampleKind; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session.liveliness().declare_subscriber("key/expression").await.unwrap(); @@ -166,10 +165,11 @@ impl<'a> Liveliness<'a> { >>::Error: Into, { LivelinessSubscriberBuilder { - session: self.session.clone(), + session: self.session, key_expr: TryIntoKeyExpr::try_into(key_expr).map_err(Into::into), handler: DefaultHandler::default(), history: false, + undeclare_on_drop: true, } } @@ -183,7 +183,6 @@ impl<'a> Liveliness<'a> { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let replies = session.liveliness().get("key/expression").await.unwrap(); @@ -205,11 +204,11 @@ impl<'a> Liveliness<'a> { { let key_expr = key_expr.try_into().map_err(Into::into); let timeout = { - let conf = self.session.runtime.config().lock(); + let conf = self.session.0.runtime.config().lock(); Duration::from_millis(unwrap_or_default!(conf.queries_default_timeout())) }; LivelinessGetBuilder { - session: &self.session, + session: self.session, key_expr, timeout, handler: DefaultHandler::default(), @@ -223,7 +222,6 @@ impl<'a> Liveliness<'a> { /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let liveliness = session @@ -237,13 +235,13 @@ impl<'a> Liveliness<'a> { #[zenoh_macros::unstable] #[derive(Debug)] pub struct LivelinessTokenBuilder<'a, 'b> { - pub(crate) session: SessionRef<'a>, + pub(crate) session: &'a Session, pub(crate) key_expr: ZResult>, } #[zenoh_macros::unstable] -impl<'a> Resolvable for LivelinessTokenBuilder<'a, '_> { - type To = ZResult>; +impl Resolvable for LivelinessTokenBuilder<'_, '_> { + type To = ZResult; } #[zenoh_macros::unstable] @@ -253,9 +251,10 @@ impl Wait for LivelinessTokenBuilder<'_, '_> { let session = self.session; let key_expr = self.key_expr?.into_owned(); session + .0 .declare_liveliness_inner(&key_expr) .map(|tok_state| LivelinessToken { - session, + session: self.session.downgrade(), state: tok_state, undeclare_on_drop: true, }) @@ -289,13 +288,12 @@ pub(crate) struct LivelinessTokenState { /// that declared the token has Zenoh connectivity with the Zenoh application /// that monitors it. /// -/// `LivelinessTokens` are automatically undeclared when dropped. +/// Liveliness tokens are automatically undeclared when dropped. /// /// # Examples /// ```no_run /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let liveliness = session @@ -307,19 +305,18 @@ pub(crate) struct LivelinessTokenState { /// ``` #[zenoh_macros::unstable] #[derive(Debug)] -pub struct LivelinessToken<'a> { - pub(crate) session: SessionRef<'a>, - pub(crate) state: Arc, +pub struct LivelinessToken { + session: WeakSession, + state: Arc, undeclare_on_drop: bool, } -/// A [`Resolvable`] returned when undeclaring a [`LivelinessToken`](LivelinessToken). +/// A [`Resolvable`] returned when undeclaring a [`LivelinessToken`]. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let liveliness = session @@ -333,26 +330,22 @@ pub struct LivelinessToken<'a> { /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] #[zenoh_macros::unstable] -pub struct LivelinessTokenUndeclaration<'a> { - token: LivelinessToken<'a>, -} +pub struct LivelinessTokenUndeclaration(LivelinessToken); #[zenoh_macros::unstable] -impl Resolvable for LivelinessTokenUndeclaration<'_> { +impl Resolvable for LivelinessTokenUndeclaration { type To = ZResult<()>; } #[zenoh_macros::unstable] -impl Wait for LivelinessTokenUndeclaration<'_> { +impl Wait for LivelinessTokenUndeclaration { fn wait(mut self) -> ::To { - // set the flag first to avoid double panic if this function panic - self.token.undeclare_on_drop = false; - self.token.session.undeclare_liveliness(self.token.state.id) + self.0.undeclare_impl() } } #[zenoh_macros::unstable] -impl<'a> IntoFuture for LivelinessTokenUndeclaration<'a> { +impl IntoFuture for LivelinessTokenUndeclaration { type Output = ::To; type IntoFuture = Ready<::To>; @@ -362,18 +355,13 @@ impl<'a> IntoFuture for LivelinessTokenUndeclaration<'a> { } #[zenoh_macros::unstable] -impl<'a> LivelinessToken<'a> { - /// Undeclare a [`LivelinessToken`]. - /// - /// LivelinessTokens are automatically closed when dropped, - /// but you may want to use this function to handle errors or - /// undeclare the LivelinessToken asynchronously. +impl LivelinessToken { + /// Undeclare the [`LivelinessToken`]. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let liveliness = session @@ -386,33 +374,33 @@ impl<'a> LivelinessToken<'a> { /// # } /// ``` #[inline] - pub fn undeclare(self) -> impl Resolve> + 'a { + pub fn undeclare(self) -> impl Resolve> { UndeclarableSealed::undeclare_inner(self, ()) } - /// Keep this liveliness token in background, until the session is closed. - #[inline] - #[zenoh_macros::unstable] - pub fn background(mut self) { - // It's not necessary to undeclare this resource when session close, as other sessions - // will clean all resources related to the closed one. - // So we can just never undeclare it. + fn undeclare_impl(&mut self) -> ZResult<()> { + // set the flag first to avoid double panic if this function panic self.undeclare_on_drop = false; + self.session.undeclare_liveliness(self.state.id) } } #[zenoh_macros::unstable] -impl<'a> UndeclarableSealed<(), LivelinessTokenUndeclaration<'a>> for LivelinessToken<'a> { - fn undeclare_inner(self, _: ()) -> LivelinessTokenUndeclaration<'a> { - LivelinessTokenUndeclaration { token: self } +impl UndeclarableSealed<()> for LivelinessToken { + type Undeclaration = LivelinessTokenUndeclaration; + + fn undeclare_inner(self, _: ()) -> Self::Undeclaration { + LivelinessTokenUndeclaration(self) } } #[zenoh_macros::unstable] -impl Drop for LivelinessToken<'_> { +impl Drop for LivelinessToken { fn drop(&mut self) { if self.undeclare_on_drop { - let _ = self.session.undeclare_liveliness(self.state.id); + if let Err(error) = self.undeclare_impl() { + error!(error); + } } } } @@ -423,7 +411,6 @@ impl Drop for LivelinessToken<'_> { /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session @@ -437,21 +424,27 @@ impl Drop for LivelinessToken<'_> { #[zenoh_macros::unstable] #[derive(Debug)] pub struct LivelinessSubscriberBuilder<'a, 'b, Handler> { - pub session: SessionRef<'a>, + pub session: &'a Session, pub key_expr: ZResult>, pub handler: Handler, pub history: bool, + pub undeclare_on_drop: bool, } #[zenoh_macros::unstable] impl<'a, 'b> LivelinessSubscriberBuilder<'a, 'b, DefaultHandler> { /// Receive the samples for this liveliness subscription with a callback. /// + /// Liveliness subscriber will not be undeclared when dropped, + /// with the callback running in background until the session is closed. + /// + /// It is in fact just a convenient shortcut for + /// `.with(my_callback).undeclare_on_drop(false)`. + /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session @@ -471,30 +464,21 @@ impl<'a, 'b> LivelinessSubscriberBuilder<'a, 'b, DefaultHandler> { where Callback: Fn(Sample) + Send + Sync + 'static, { - let LivelinessSubscriberBuilder { - session, - key_expr, - handler: _, - history, - } = self; - LivelinessSubscriberBuilder { - session, - key_expr, - handler: callback, - history, - } + self.with(callback).undeclare_on_drop(false) } /// Receive the samples for this liveliness subscription with a mutable callback. /// /// Using this guarantees that your callback will never be called concurrently. - /// If your callback is also accepted by the [`callback`](LivelinessSubscriberBuilder::callback) method, we suggest you use it instead of `callback_mut` + /// If your callback is also accepted by the [`callback`](LivelinessSubscriberBuilder::callback) method, we suggest you use it instead of `callback_mut`. + /// + /// Liveliness subscriber will not be undeclared when dropped, + /// with the callback running in background until the session is closed. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let mut n = 0; @@ -524,7 +508,6 @@ impl<'a, 'b> LivelinessSubscriberBuilder<'a, 'b, DefaultHandler> { /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session @@ -549,33 +532,36 @@ impl<'a, 'b> LivelinessSubscriberBuilder<'a, 'b, DefaultHandler> { key_expr, handler: _, history, + undeclare_on_drop, } = self; LivelinessSubscriberBuilder { session, key_expr, handler, history, + undeclare_on_drop, } } } -#[zenoh_macros::unstable] impl LivelinessSubscriberBuilder<'_, '_, Handler> { + /// Set whether the liveliness subscriber will be undeclared when dropped. + /// + /// The method is usually used in combination with a callback like in + /// [`callback`](Self::callback) method, or a channel sender. + /// Be careful when using it, as liveliness subscribers not undeclared will consume + /// resources until the session is closed. + #[inline] + pub fn undeclare_on_drop(mut self, undeclare_on_drop: bool) -> Self { + self.undeclare_on_drop = undeclare_on_drop; + self + } + #[inline] #[zenoh_macros::unstable] - pub fn history(self, history: bool) -> Self { - let LivelinessSubscriberBuilder { - session, - key_expr, - handler, - history: _, - } = self; - LivelinessSubscriberBuilder { - session, - key_expr, - handler, - history, - } + pub fn history(mut self, history: bool) -> Self { + self.history = history; + self } } @@ -585,11 +571,11 @@ where Handler: IntoHandler<'static, Sample> + Send, Handler::Handler: Send, { - type To = ZResult>; + type To = ZResult>; } #[zenoh_macros::unstable] -impl<'a, Handler> Wait for LivelinessSubscriberBuilder<'a, '_, Handler> +impl Wait for LivelinessSubscriberBuilder<'_, '_, Handler> where Handler: IntoHandler<'static, Sample> + Send, Handler::Handler: Send, @@ -602,6 +588,7 @@ where let session = self.session; let (callback, handler) = self.handler.into_handler(); session + .0 .declare_liveliness_subscriber_inner( &key_expr, Locality::default(), @@ -609,11 +596,13 @@ where callback, ) .map(|sub_state| Subscriber { - subscriber: SubscriberInner { - session, + inner: SubscriberInner { + #[cfg(feature = "unstable")] + session_id: session.zid(), + session: self.session.downgrade(), state: sub_state, kind: SubscriberKind::LivelinessSubscriber, - undeclare_on_drop: true, + undeclare_on_drop: self.undeclare_on_drop, }, handler, }) @@ -621,7 +610,7 @@ where } #[zenoh_macros::unstable] -impl<'a, Handler> IntoFuture for LivelinessSubscriberBuilder<'a, '_, Handler> +impl IntoFuture for LivelinessSubscriberBuilder<'_, '_, Handler> where Handler: IntoHandler<'static, Sample> + Send, Handler::Handler: Send, @@ -642,7 +631,6 @@ where /// # #[tokio::main] /// # async fn main() { /// # use std::convert::TryFrom; -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let tokens = session @@ -674,7 +662,6 @@ impl<'a, 'b> LivelinessGetBuilder<'a, 'b, DefaultHandler> { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let queryable = session @@ -690,30 +677,18 @@ impl<'a, 'b> LivelinessGetBuilder<'a, 'b, DefaultHandler> { where Callback: Fn(Reply) + Send + Sync + 'static, { - let LivelinessGetBuilder { - session, - key_expr, - timeout, - handler: _, - } = self; - LivelinessGetBuilder { - session, - key_expr, - timeout, - handler: callback, - } + self.with(callback) } /// Receive the replies for this liveliness query with a mutable callback. /// /// Using this guarantees that your callback will never be called concurrently. - /// If your callback is also accepted by the [`callback`](LivelinessGetBuilder::callback) method, we suggest you use it instead of `callback_mut` + /// If your callback is also accepted by the [`callback`](LivelinessGetBuilder::callback) method, we suggest you use it instead of `callback_mut`. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let mut n = 0; @@ -742,7 +717,6 @@ impl<'a, 'b> LivelinessGetBuilder<'a, 'b, DefaultHandler> { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let replies = session @@ -776,7 +750,7 @@ impl<'a, 'b> LivelinessGetBuilder<'a, 'b, DefaultHandler> { } } -impl<'a, 'b, Handler> LivelinessGetBuilder<'a, 'b, Handler> { +impl LivelinessGetBuilder<'_, '_, Handler> { /// Set query timeout. #[inline] pub fn timeout(mut self, timeout: Duration) -> Self { @@ -801,6 +775,7 @@ where fn wait(self) -> ::To { let (callback, receiver) = self.handler.into_handler(); self.session + .0 .liveliness_query(&self.key_expr?, self.timeout, callback) .map(|_| receiver) } diff --git a/zenoh/src/api/publisher.rs b/zenoh/src/api/publisher.rs index 0c52d24857..fcd4ce59d3 100644 --- a/zenoh/src/api/publisher.rs +++ b/zenoh/src/api/publisher.rs @@ -21,6 +21,7 @@ use std::{ }; use futures::Sink; +use tracing::error; use zenoh_core::{zread, Resolvable, Resolve, Wait}; use zenoh_protocol::{ core::{CongestionControl, Reliability}, @@ -34,11 +35,9 @@ use { handlers::{Callback, DefaultHandler, IntoHandler}, sample::SourceInfo, }, - std::{ - collections::HashSet, - sync::{Arc, Mutex}, - }, + std::{collections::HashSet, sync::Arc, sync::Mutex}, zenoh_config::wrappers::EntityGlobalId, + zenoh_config::ZenohId, zenoh_protocol::core::EntityGlobalIdProto, }; @@ -51,10 +50,10 @@ use super::{ encoding::Encoding, key_expr::KeyExpr, sample::{DataInfo, Locality, QoS, Sample, SampleFields, SampleKind}, - session::{SessionRef, UndeclarableSealed}, + session::UndeclarableSealed, }; use crate::{ - api::{subscriber::SubscriberKind, Id}, + api::{session::WeakSession, subscriber::SubscriberKind, Id}, net::primitives::Primitives, }; @@ -74,35 +73,6 @@ impl fmt::Debug for PublisherState { } } -#[zenoh_macros::unstable] -#[derive(Clone)] -pub enum PublisherRef<'a> { - Borrow(&'a Publisher<'a>), - Shared(std::sync::Arc>), -} - -#[zenoh_macros::unstable] -impl<'a> std::ops::Deref for PublisherRef<'a> { - type Target = Publisher<'a>; - - fn deref(&self) -> &Self::Target { - match self { - PublisherRef::Borrow(b) => b, - PublisherRef::Shared(s) => s, - } - } -} - -#[zenoh_macros::unstable] -impl std::fmt::Debug for PublisherRef<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - PublisherRef::Borrow(b) => Publisher::fmt(b, f), - PublisherRef::Shared(s) => Publisher::fmt(s, f), - } - } -} - /// A publisher that allows to send data through a stream. /// /// Publishers are automatically undeclared when dropped. @@ -111,9 +81,8 @@ impl std::fmt::Debug for PublisherRef<'_> { /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// -/// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); +/// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); /// publisher.put("value").await.unwrap(); /// # } @@ -126,9 +95,8 @@ impl std::fmt::Debug for PublisherRef<'_> { /// # #[tokio::main] /// # async fn main() { /// use futures::StreamExt; -/// use zenoh::prelude::*; /// -/// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); +/// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let mut subscriber = session.declare_subscriber("key/expression").await.unwrap(); /// let publisher = session.declare_publisher("another/key/expression").await.unwrap(); /// subscriber.stream().map(Ok).forward(publisher).await.unwrap(); @@ -136,7 +104,9 @@ impl std::fmt::Debug for PublisherRef<'_> { /// ``` #[derive(Debug)] pub struct Publisher<'a> { - pub(crate) session: SessionRef<'a>, + #[cfg(feature = "unstable")] + pub(crate) session_id: ZenohId, + pub(crate) session: WeakSession, pub(crate) id: Id, pub(crate) key_expr: KeyExpr<'a>, pub(crate) encoding: Encoding, @@ -158,7 +128,6 @@ impl<'a> Publisher<'a> { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression") @@ -170,7 +139,7 @@ impl<'a> Publisher<'a> { #[zenoh_macros::unstable] pub fn id(&self) -> EntityGlobalId { EntityGlobalIdProto { - zid: self.session.zid().into(), + zid: self.session_id.into(), eid: self.id, } .into() @@ -206,51 +175,14 @@ impl<'a> Publisher<'a> { self.reliability } - /// Consumes the given `Publisher`, returning a thread-safe reference-counting - /// pointer to it (`Arc`). This is equivalent to `Arc::new(Publisher)`. - /// - /// This is useful to share ownership of the `Publisher` between several threads - /// and tasks. It also allows to create [`MatchingListener`] with static - /// lifetime that can be moved to several threads and tasks. - /// - /// Note: the given zenoh `Publisher` will be undeclared when the last reference to - /// it is dropped. - /// - /// # Examples - /// ```no_run - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let publisher = session.declare_publisher("key/expression").await.unwrap().into_arc(); - /// let matching_listener = publisher.matching_listener().await.unwrap(); - /// - /// tokio::task::spawn(async move { - /// while let Ok(matching_status) = matching_listener.recv_async().await { - /// if matching_status.matching_subscribers() { - /// println!("Publisher has matching subscribers."); - /// } else { - /// println!("Publisher has NO MORE matching subscribers."); - /// } - /// } - /// }).await; - /// # } - /// ``` - #[zenoh_macros::unstable] - pub fn into_arc(self) -> std::sync::Arc { - std::sync::Arc::new(self) - } - /// Put data. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); /// publisher.put("value").await.unwrap(); /// # } @@ -279,9 +211,8 @@ impl<'a> Publisher<'a> { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); /// publisher.delete().await.unwrap(); /// # } @@ -306,9 +237,8 @@ impl<'a> Publisher<'a> { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); /// let matching_subscribers: bool = publisher /// .matching_status() @@ -334,7 +264,6 @@ impl<'a> Publisher<'a> { /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); @@ -349,20 +278,20 @@ impl<'a> Publisher<'a> { /// # } /// ``` #[zenoh_macros::unstable] - pub fn matching_listener(&self) -> MatchingListenerBuilder<'_, DefaultHandler> { + pub fn matching_listener(&self) -> MatchingListenerBuilder<'_, 'a, DefaultHandler> { MatchingListenerBuilder { - publisher: PublisherRef::Borrow(self), + publisher: self, handler: DefaultHandler::default(), + undeclare_on_drop: true, } } - /// Undeclares the [`Publisher`], informing the network that it needn't optimize publications for its key expression anymore. + /// Undeclare the [`Publisher`], informing the network that it needn't optimize publications for its key expression anymore. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); @@ -373,107 +302,25 @@ impl<'a> Publisher<'a> { UndeclarableSealed::undeclare_inner(self, ()) } - #[cfg(feature = "unstable")] - fn undeclare_matching_listeners(&self) -> ZResult<()> { - let ids: Vec = zlock!(self.matching_listeners).drain().collect(); - for id in ids { - self.session.undeclare_matches_listener_inner(id)? + fn undeclare_impl(&mut self) -> ZResult<()> { + // set the flag first to avoid double panic if this function panic + self.undeclare_on_drop = false; + #[cfg(feature = "unstable")] + { + let ids: Vec = zlock!(self.matching_listeners).drain().collect(); + for id in ids { + self.session.undeclare_matches_listener_inner(id)? + } } - Ok(()) + self.session.undeclare_publisher_inner(self.id) } } -/// Functions to create zenoh entities with `'static` lifetime. -/// -/// This trait contains functions to create zenoh entities like -/// [`MatchingListener`] with a `'static` lifetime. -/// This is useful to move zenoh entities to several threads and tasks. -/// -/// This trait is implemented for `Arc`. -/// -/// # Examples -/// ```no_run -/// # #[tokio::main] -/// # async fn main() { -/// use zenoh::prelude::*; -/// -/// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); -/// let publisher = session.declare_publisher("key/expression").await.unwrap().into_arc(); -/// let matching_listener = publisher.matching_listener().await.unwrap(); -/// -/// tokio::task::spawn(async move { -/// while let Ok(matching_status) = matching_listener.recv_async().await { -/// if matching_status.matching_subscribers() { -/// println!("Publisher has matching subscribers."); -/// } else { -/// println!("Publisher has NO MORE matching subscribers."); -/// } -/// } -/// }).await; -/// # } -/// ``` -#[zenoh_macros::unstable] -pub trait PublisherDeclarations { - /// # Examples - /// ```no_run - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let publisher = session.declare_publisher("key/expression").await.unwrap().into_arc(); - /// let matching_listener = publisher.matching_listener().await.unwrap(); - /// - /// tokio::task::spawn(async move { - /// while let Ok(matching_status) = matching_listener.recv_async().await { - /// if matching_status.matching_subscribers() { - /// println!("Publisher has matching subscribers."); - /// } else { - /// println!("Publisher has NO MORE matching subscribers."); - /// } - /// } - /// }).await; - /// # } - /// ``` - #[zenoh_macros::unstable] - fn matching_listener(&self) -> MatchingListenerBuilder<'static, DefaultHandler>; -} +impl<'a> UndeclarableSealed<()> for Publisher<'a> { + type Undeclaration = PublisherUndeclaration<'a>; -#[zenoh_macros::unstable] -impl PublisherDeclarations for std::sync::Arc> { - /// # Examples - /// ```no_run - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let publisher = session.declare_publisher("key/expression").await.unwrap().into_arc(); - /// let matching_listener = publisher.matching_listener().await.unwrap(); - /// - /// tokio::task::spawn(async move { - /// while let Ok(matching_status) = matching_listener.recv_async().await { - /// if matching_status.matching_subscribers() { - /// println!("Publisher has matching subscribers."); - /// } else { - /// println!("Publisher has NO MORE matching subscribers."); - /// } - /// } - /// }).await; - /// # } - /// ``` - #[zenoh_macros::unstable] - fn matching_listener(&self) -> MatchingListenerBuilder<'static, DefaultHandler> { - MatchingListenerBuilder { - publisher: PublisherRef::Shared(self.clone()), - handler: DefaultHandler::default(), - } - } -} - -impl<'a> UndeclarableSealed<(), PublisherUndeclaration<'a>> for Publisher<'a> { - fn undeclare_inner(self, _: ()) -> PublisherUndeclaration<'a> { - PublisherUndeclaration { publisher: self } + fn undeclare_inner(self, _: ()) -> Self::Undeclaration { + PublisherUndeclaration(self) } } @@ -483,7 +330,6 @@ impl<'a> UndeclarableSealed<(), PublisherUndeclaration<'a>> for Publisher<'a> { /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); @@ -491,9 +337,7 @@ impl<'a> UndeclarableSealed<(), PublisherUndeclaration<'a>> for Publisher<'a> { /// # } /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] -pub struct PublisherUndeclaration<'a> { - publisher: Publisher<'a>, -} +pub struct PublisherUndeclaration<'a>(Publisher<'a>); impl Resolvable for PublisherUndeclaration<'_> { type To = ZResult<()>; @@ -501,13 +345,7 @@ impl Resolvable for PublisherUndeclaration<'_> { impl Wait for PublisherUndeclaration<'_> { fn wait(mut self) -> ::To { - // set the flag first to avoid double panic if this function panic - self.publisher.undeclare_on_drop = false; - #[cfg(feature = "unstable")] - self.publisher.undeclare_matching_listeners()?; - self.publisher - .session - .undeclare_publisher_inner(self.publisher.id) + self.0.undeclare_impl() } } @@ -523,9 +361,9 @@ impl IntoFuture for PublisherUndeclaration<'_> { impl Drop for Publisher<'_> { fn drop(&mut self) { if self.undeclare_on_drop { - #[cfg(feature = "unstable")] - let _ = self.undeclare_matching_listeners(); - let _ = self.session.undeclare_publisher_inner(self.id); + if let Err(error) = self.undeclare_impl() { + error!(error); + } } } } @@ -581,11 +419,7 @@ impl Publisher<'_> { attachment: Option, ) -> ZResult<()> { tracing::trace!("write({:?}, [...])", &self.key_expr); - let primitives = zread!(self.session.state) - .primitives - .as_ref() - .unwrap() - .clone(); + let primitives = zread!(self.session.state).primitives()?; let timestamp = if timestamp.is_none() { self.session.runtime.new_timestamp() } else { @@ -759,9 +593,8 @@ impl TryFrom for Priority { /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// -/// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); +/// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); /// let matching_status = publisher.matching_status().await.unwrap(); /// # } @@ -780,9 +613,8 @@ impl MatchingStatus { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); /// let matching_subscribers: bool = publisher /// .matching_status() @@ -799,20 +631,20 @@ impl MatchingStatus { /// A builder for initializing a [`MatchingListener`]. #[zenoh_macros::unstable] #[derive(Debug)] -pub struct MatchingListenerBuilder<'a, Handler> { - pub(crate) publisher: PublisherRef<'a>, +pub struct MatchingListenerBuilder<'a, 'b, Handler> { + pub(crate) publisher: &'a Publisher<'b>, pub handler: Handler, + pub(crate) undeclare_on_drop: bool, } #[zenoh_macros::unstable] -impl<'a> MatchingListenerBuilder<'a, DefaultHandler> { +impl<'a, 'b> MatchingListenerBuilder<'a, 'b, DefaultHandler> { /// Receive the MatchingStatuses for this listener with a callback. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); @@ -831,18 +663,11 @@ impl<'a> MatchingListenerBuilder<'a, DefaultHandler> { /// ``` #[inline] #[zenoh_macros::unstable] - pub fn callback(self, callback: Callback) -> MatchingListenerBuilder<'a, Callback> + pub fn callback(self, callback: Callback) -> MatchingListenerBuilder<'a, 'b, Callback> where Callback: Fn(MatchingStatus) + Send + Sync + 'static, { - let MatchingListenerBuilder { - publisher, - handler: _, - } = self; - MatchingListenerBuilder { - publisher, - handler: callback, - } + self.with(callback).undeclare_on_drop(false) } /// Receive the MatchingStatuses for this listener with a mutable callback. @@ -851,7 +676,6 @@ impl<'a> MatchingListenerBuilder<'a, DefaultHandler> { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let mut n = 0; /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); @@ -868,7 +692,7 @@ impl<'a> MatchingListenerBuilder<'a, DefaultHandler> { pub fn callback_mut( self, callback: CallbackMut, - ) -> MatchingListenerBuilder<'a, impl Fn(MatchingStatus) + Send + Sync + 'static> + ) -> MatchingListenerBuilder<'a, 'b, impl Fn(MatchingStatus) + Send + Sync + 'static> where CallbackMut: FnMut(MatchingStatus) + Send + Sync + 'static, { @@ -881,7 +705,6 @@ impl<'a> MatchingListenerBuilder<'a, DefaultHandler> { /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); @@ -901,54 +724,75 @@ impl<'a> MatchingListenerBuilder<'a, DefaultHandler> { /// ``` #[inline] #[zenoh_macros::unstable] - pub fn with(self, handler: Handler) -> MatchingListenerBuilder<'a, Handler> + pub fn with(self, handler: Handler) -> MatchingListenerBuilder<'a, 'b, Handler> where Handler: IntoHandler<'static, MatchingStatus>, { let MatchingListenerBuilder { publisher, handler: _, + undeclare_on_drop, } = self; - MatchingListenerBuilder { publisher, handler } + MatchingListenerBuilder { + publisher, + handler, + undeclare_on_drop, + } + } +} + +#[zenoh_macros::unstable] +impl MatchingListenerBuilder<'_, '_, Handler> { + /// Set whether the matching listener will be undeclared when dropped. + /// + /// The method is usually used in combination with a callback like in + /// [`callback`](Self::callback) method, or a channel sender. + /// Be careful when using it, as matching listeners not undeclared will consume + /// resources until the publisher is undeclared. + #[inline] + pub fn undeclare_on_drop(mut self, undeclare_on_drop: bool) -> Self { + self.undeclare_on_drop = undeclare_on_drop; + self } } #[zenoh_macros::unstable] -impl<'a, Handler> Resolvable for MatchingListenerBuilder<'a, Handler> +impl Resolvable for MatchingListenerBuilder<'_, '_, Handler> where Handler: IntoHandler<'static, MatchingStatus> + Send, Handler::Handler: Send, { - type To = ZResult>; + type To = ZResult>; } #[zenoh_macros::unstable] -impl<'a, Handler> Wait for MatchingListenerBuilder<'a, Handler> +impl Wait for MatchingListenerBuilder<'_, '_, Handler> where Handler: IntoHandler<'static, MatchingStatus> + Send, Handler::Handler: Send, { #[zenoh_macros::unstable] fn wait(self) -> ::To { - let (callback, receiver) = self.handler.into_handler(); + let (callback, handler) = self.handler.into_handler(); let state = self .publisher .session - .declare_matches_listener_inner(&self.publisher, callback)?; + .declare_matches_listener_inner(self.publisher, callback)?; zlock!(self.publisher.matching_listeners).insert(state.id); Ok(MatchingListener { - listener: MatchingListenerInner { - publisher: self.publisher, + inner: MatchingListenerInner { + session: self.publisher.session.clone(), + matching_listeners: self.publisher.matching_listeners.clone(), state, - undeclare_on_drop: true, + undeclare_on_drop: self.undeclare_on_drop, }, - receiver, + handler, }) } } #[zenoh_macros::unstable] -impl<'a, Handler> IntoFuture for MatchingListenerBuilder<'a, Handler> +impl IntoFuture for MatchingListenerBuilder<'_, '_, Handler> where Handler: IntoHandler<'static, MatchingStatus> + Send, Handler::Handler: Send, @@ -965,15 +809,15 @@ where #[zenoh_macros::unstable] pub(crate) struct MatchingListenerState { pub(crate) id: Id, - pub(crate) current: std::sync::Mutex, + pub(crate) current: Mutex, pub(crate) key_expr: KeyExpr<'static>, pub(crate) destination: Locality, pub(crate) callback: Callback<'static, MatchingStatus>, } #[zenoh_macros::unstable] -impl std::fmt::Debug for MatchingListenerState { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { +impl fmt::Debug for MatchingListenerState { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("MatchingListener") .field("id", &self.id) .field("key_expr", &self.key_expr) @@ -982,35 +826,24 @@ impl std::fmt::Debug for MatchingListenerState { } #[zenoh_macros::unstable] -pub(crate) struct MatchingListenerInner<'a> { - pub(crate) publisher: PublisherRef<'a>, - pub(crate) state: std::sync::Arc, - undeclare_on_drop: bool, -} - -#[zenoh_macros::unstable] -impl<'a> MatchingListenerInner<'a> { - #[inline] - pub fn undeclare(self) -> MatchingListenerUndeclaration<'a> { - UndeclarableSealed::undeclare_inner(self, ()) - } -} - -#[zenoh_macros::unstable] -impl<'a> UndeclarableSealed<(), MatchingListenerUndeclaration<'a>> for MatchingListenerInner<'a> { - fn undeclare_inner(self, _: ()) -> MatchingListenerUndeclaration<'a> { - MatchingListenerUndeclaration { subscriber: self } - } +pub(crate) struct MatchingListenerInner { + pub(crate) session: WeakSession, + pub(crate) matching_listeners: Arc>>, + pub(crate) state: Arc, + pub(crate) undeclare_on_drop: bool, } /// A listener that sends notifications when the [`MatchingStatus`] of a /// publisher changes. /// +/// Callback matching listeners will run in background until the publisher is undeclared, +/// or until it is undeclared. +/// On the other hand, matching listener with a handler are automatically undeclared when dropped. +/// /// # Examples /// ```no_run /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); @@ -1025,23 +858,19 @@ impl<'a> UndeclarableSealed<(), MatchingListenerUndeclaration<'a>> for MatchingL /// # } /// ``` #[zenoh_macros::unstable] -pub struct MatchingListener<'a, Receiver> { - pub(crate) listener: MatchingListenerInner<'a>, - pub(crate) receiver: Receiver, +pub struct MatchingListener { + pub(crate) inner: MatchingListenerInner, + pub(crate) handler: Handler, } #[zenoh_macros::unstable] -impl<'a, Receiver> MatchingListener<'a, Receiver> { - /// Close a [`MatchingListener`]. - /// - /// MatchingListeners are automatically closed when dropped, but you may want to use this function to handle errors or - /// close the MatchingListener asynchronously. +impl MatchingListener { + /// Undeclare the [`MatchingListener`]. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); @@ -1050,66 +879,64 @@ impl<'a, Receiver> MatchingListener<'a, Receiver> { /// # } /// ``` #[inline] - pub fn undeclare(self) -> MatchingListenerUndeclaration<'a> { - self.listener.undeclare() + pub fn undeclare(self) -> MatchingListenerUndeclaration + where + Handler: Send, + { + self.undeclare_inner(()) } - /// Make the matching listener run in background, until the publisher is undeclared. - #[inline] - #[zenoh_macros::unstable] - pub fn background(mut self) { - // The matching listener will be undeclared as part of publisher undeclaration. - self.listener.undeclare_on_drop = false; + fn undeclare_impl(&mut self) -> ZResult<()> { + // set the flag first to avoid double panic if this function panic + self.inner.undeclare_on_drop = false; + zlock!(self.inner.matching_listeners).remove(&self.inner.state.id); + self.inner + .session + .undeclare_matches_listener_inner(self.inner.state.id) } } #[zenoh_macros::unstable] -impl<'a, T> UndeclarableSealed<(), MatchingListenerUndeclaration<'a>> for MatchingListener<'a, T> { - fn undeclare_inner(self, _: ()) -> MatchingListenerUndeclaration<'a> { - UndeclarableSealed::undeclare_inner(self.listener, ()) +impl UndeclarableSealed<()> for MatchingListener { + type Undeclaration = MatchingListenerUndeclaration; + + fn undeclare_inner(self, _: ()) -> Self::Undeclaration { + MatchingListenerUndeclaration(self) } } #[zenoh_macros::unstable] -impl std::ops::Deref for MatchingListener<'_, Receiver> { - type Target = Receiver; +impl std::ops::Deref for MatchingListener { + type Target = Handler; fn deref(&self) -> &Self::Target { - &self.receiver + &self.handler } } #[zenoh_macros::unstable] -impl std::ops::DerefMut for MatchingListener<'_, Receiver> { +impl std::ops::DerefMut for MatchingListener { fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.receiver + &mut self.handler } } #[zenoh_macros::unstable] -pub struct MatchingListenerUndeclaration<'a> { - subscriber: MatchingListenerInner<'a>, -} +pub struct MatchingListenerUndeclaration(MatchingListener); #[zenoh_macros::unstable] -impl Resolvable for MatchingListenerUndeclaration<'_> { +impl Resolvable for MatchingListenerUndeclaration { type To = ZResult<()>; } #[zenoh_macros::unstable] -impl Wait for MatchingListenerUndeclaration<'_> { +impl Wait for MatchingListenerUndeclaration { fn wait(mut self) -> ::To { - // set the flag first to avoid double panic if this function panic - self.subscriber.undeclare_on_drop = false; - zlock!(self.subscriber.publisher.matching_listeners).remove(&self.subscriber.state.id); - self.subscriber - .publisher - .session - .undeclare_matches_listener_inner(self.subscriber.state.id) + self.0.undeclare_impl() } } #[zenoh_macros::unstable] -impl IntoFuture for MatchingListenerUndeclaration<'_> { +impl IntoFuture for MatchingListenerUndeclaration { type Output = ::To; type IntoFuture = Ready<::To>; @@ -1118,25 +945,12 @@ impl IntoFuture for MatchingListenerUndeclaration<'_> { } } -#[zenoh_macros::unstable] -impl Drop for MatchingListenerInner<'_> { - fn drop(&mut self) { - if self.undeclare_on_drop { - zlock!(self.publisher.matching_listeners).remove(&self.state.id); - let _ = self - .publisher - .session - .undeclare_matches_listener_inner(self.state.id); - } - } -} - #[cfg(test)] mod tests { use zenoh_config::Config; use zenoh_core::Wait; - use crate::api::{sample::SampleKind, session::SessionDeclarations}; + use crate::api::sample::SampleKind; #[cfg(feature = "internal")] #[test] diff --git a/zenoh/src/api/query.rs b/zenoh/src/api/query.rs index 922f88e1a4..ae55d5ab8d 100644 --- a/zenoh/src/api/query.rs +++ b/zenoh/src/api/query.rs @@ -178,7 +178,7 @@ impl QueryState { /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::{prelude::*, query::{ConsolidationMode, QueryTarget}}; +/// use zenoh::{query::{ConsolidationMode, QueryTarget}}; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let replies = session @@ -265,7 +265,6 @@ impl<'a, 'b> SessionGetBuilder<'a, 'b, DefaultHandler> { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let queryable = session @@ -280,46 +279,18 @@ impl<'a, 'b> SessionGetBuilder<'a, 'b, DefaultHandler> { where Callback: Fn(Reply) + Send + Sync + 'static, { - let SessionGetBuilder { - session, - selector, - target, - consolidation, - qos, - destination, - timeout, - value, - attachment, - #[cfg(feature = "unstable")] - source_info, - handler: _, - } = self; - SessionGetBuilder { - session, - selector, - target, - consolidation, - qos, - destination, - timeout, - value, - attachment, - #[cfg(feature = "unstable")] - source_info, - handler: callback, - } + self.with(callback) } /// Receive the replies for this query with a mutable callback. /// /// Using this guarantees that your callback will never be called concurrently. - /// If your callback is also accepted by the [`callback`](crate::session::SessionGetBuilder::callback) method, we suggest you use it instead of `callback_mut` + /// If your callback is also accepted by the [`callback`](crate::session::SessionGetBuilder::callback) method, we suggest you use it instead of `callback_mut`. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let mut n = 0; @@ -347,7 +318,6 @@ impl<'a, 'b> SessionGetBuilder<'a, 'b, DefaultHandler> { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let replies = session @@ -492,6 +462,7 @@ where parameters, } = self.selector?; self.session + .0 .query( &key_expr, ¶meters, diff --git a/zenoh/src/api/queryable.rs b/zenoh/src/api/queryable.rs index 92d27ffa87..951600d1e6 100644 --- a/zenoh/src/api/queryable.rs +++ b/zenoh/src/api/queryable.rs @@ -18,6 +18,7 @@ use std::{ sync::Arc, }; +use tracing::error; use uhlc::Timestamp; use zenoh_core::{Resolvable, Resolve, Wait}; use zenoh_protocol::{ @@ -28,30 +29,33 @@ use zenoh_protocol::{ use zenoh_result::ZResult; #[zenoh_macros::unstable] use { - super::{query::ReplyKeyExpr, sample::SourceInfo}, - zenoh_config::wrappers::EntityGlobalId, + crate::api::{query::ReplyKeyExpr, sample::SourceInfo}, + zenoh_config::wrappers::{EntityGlobalId, ZenohId}, zenoh_protocol::core::EntityGlobalIdProto, }; #[zenoh_macros::unstable] -use super::selector::ZenohParameters; -use super::{ - builders::sample::{ - EncodingBuilderTrait, QoSBuilderTrait, SampleBuilder, SampleBuilderTrait, - TimestampBuilderTrait, +use crate::api::selector::ZenohParameters; +use crate::{ + api::{ + builders::sample::{ + EncodingBuilderTrait, QoSBuilderTrait, SampleBuilder, SampleBuilderTrait, + TimestampBuilderTrait, + }, + bytes::{OptionZBytes, ZBytes}, + encoding::Encoding, + handlers::{locked, DefaultHandler, IntoHandler}, + key_expr::KeyExpr, + publisher::Priority, + sample::{Locality, QoSBuilder, Sample, SampleKind}, + selector::Selector, + session::{UndeclarableSealed, WeakSession}, + value::Value, + Id, }, - bytes::{OptionZBytes, ZBytes}, - encoding::Encoding, - handlers::{locked, DefaultHandler, IntoHandler}, - key_expr::KeyExpr, - publisher::Priority, - sample::{Locality, QoSBuilder, Sample, SampleKind}, - selector::Selector, - session::{SessionRef, UndeclarableSealed}, - value::Value, - Id, + net::primitives::Primitives, + Session, }; -use crate::net::primitives::Primitives; pub(crate) struct QueryInner { pub(crate) key_expr: KeyExpr<'static>, @@ -539,43 +543,14 @@ impl fmt::Debug for QueryableState { } } -/// An entity able to reply to queries through a callback. -/// -/// CallbackQueryables can be created from a zenoh [`Session`](crate::Session) -/// with the [`declare_queryable`](crate::Session::declare_queryable) function -/// and the [`callback`](QueryableBuilder::callback) function -/// of the resulting builder. -/// -/// Queryables are automatically undeclared when dropped. -/// -/// # Examples -/// ```no_run -/// # #[tokio::main] -/// # async fn main() { -/// use futures::prelude::*; -/// use zenoh::prelude::*; -/// -/// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); -/// let queryable = session.declare_queryable("key/expression").await.unwrap(); -/// while let Ok(query) = queryable.recv_async().await { -/// println!(">> Handling query '{}'", query.selector()); -/// query.reply("key/expression", "value") -/// .await -/// .unwrap(); -/// } -/// # } -/// ``` #[derive(Debug)] -pub(crate) struct CallbackQueryable<'a> { - pub(crate) session: SessionRef<'a>, +pub(crate) struct QueryableInner { + #[cfg(feature = "unstable")] + pub(crate) session_id: ZenohId, + pub(crate) session: WeakSession, pub(crate) state: Arc, - undeclare_on_drop: bool, -} - -impl<'a> UndeclarableSealed<(), QueryableUndeclaration<'a>> for CallbackQueryable<'a> { - fn undeclare_inner(self, _: ()) -> QueryableUndeclaration<'a> { - QueryableUndeclaration { queryable: self } - } + // Queryable is undeclared on drop unless its handler is a ZST, i.e. it is callback-only + pub(crate) undeclare_on_drop: bool, } /// A [`Resolvable`] returned when undeclaring a queryable. @@ -584,7 +559,6 @@ impl<'a> UndeclarableSealed<(), QueryableUndeclaration<'a>> for CallbackQueryabl /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let queryable = session.declare_queryable("key/expression").await.unwrap(); @@ -592,25 +566,19 @@ impl<'a> UndeclarableSealed<(), QueryableUndeclaration<'a>> for CallbackQueryabl /// # } /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] -pub struct QueryableUndeclaration<'a> { - queryable: CallbackQueryable<'a>, -} +pub struct QueryableUndeclaration(Queryable); -impl Resolvable for QueryableUndeclaration<'_> { +impl Resolvable for QueryableUndeclaration { type To = ZResult<()>; } -impl Wait for QueryableUndeclaration<'_> { +impl Wait for QueryableUndeclaration { fn wait(mut self) -> ::To { - // set the flag first to avoid double panic if this function panic - self.queryable.undeclare_on_drop = false; - self.queryable - .session - .close_queryable(self.queryable.state.id) + self.0.undeclare_impl() } } -impl<'a> IntoFuture for QueryableUndeclaration<'a> { +impl IntoFuture for QueryableUndeclaration { type Output = ::To; type IntoFuture = Ready<::To>; @@ -619,21 +587,12 @@ impl<'a> IntoFuture for QueryableUndeclaration<'a> { } } -impl Drop for CallbackQueryable<'_> { - fn drop(&mut self) { - if self.undeclare_on_drop { - let _ = self.session.close_queryable(self.state.id); - } - } -} - /// A builder for initializing a [`Queryable`]. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let queryable = session.declare_queryable("key/expression").await.unwrap(); @@ -642,21 +601,27 @@ impl Drop for CallbackQueryable<'_> { #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] #[derive(Debug)] pub struct QueryableBuilder<'a, 'b, Handler> { - pub(crate) session: SessionRef<'a>, + pub(crate) session: &'a Session, pub(crate) key_expr: ZResult>, pub(crate) complete: bool, pub(crate) origin: Locality, pub(crate) handler: Handler, + pub(crate) undeclare_on_drop: bool, } impl<'a, 'b> QueryableBuilder<'a, 'b, DefaultHandler> { - /// Receive the queries for this Queryable with a callback. + /// Receive the queries for this queryable with a callback. + /// + /// Queryable will not be undeclared when dropped, with the callback running + /// in background until the session is closed. + /// + /// It is in fact just a convenient shortcut for + /// `.with(my_callback).undeclare_on_drop(false)`. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let queryable = session @@ -671,32 +636,21 @@ impl<'a, 'b> QueryableBuilder<'a, 'b, DefaultHandler> { where Callback: Fn(Query) + Send + Sync + 'static, { - let QueryableBuilder { - session, - key_expr, - complete, - origin, - handler: _, - } = self; - QueryableBuilder { - session, - key_expr, - complete, - origin, - handler: callback, - } + self.with(callback).undeclare_on_drop(false) } /// Receive the queries for this Queryable with a mutable callback. /// /// Using this guarantees that your callback will never be called concurrently. - /// If your callback is also accepted by the [`callback`](QueryableBuilder::callback) method, we suggest you use it instead of `callback_mut` + /// If your callback is also accepted by the [`callback`](QueryableBuilder::callback) method, we suggest you use it instead of `callback_mut`. + /// + /// Queryable will not be undeclared when dropped, with the callback running + /// in background until the session is closed. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let mut n = 0; @@ -724,7 +678,6 @@ impl<'a, 'b> QueryableBuilder<'a, 'b, DefaultHandler> { /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let queryable = session @@ -748,6 +701,7 @@ impl<'a, 'b> QueryableBuilder<'a, 'b, DefaultHandler> { complete, origin, handler: _, + undeclare_on_drop, } = self; QueryableBuilder { session, @@ -755,8 +709,18 @@ impl<'a, 'b> QueryableBuilder<'a, 'b, DefaultHandler> { complete, origin, handler, + undeclare_on_drop, } } +} + +impl QueryableBuilder<'_, '_, Handler> { + /// Change queryable completeness. + #[inline] + pub fn complete(mut self, complete: bool) -> Self { + self.complete = complete; + self + } /// Restrict the matching queries that will be receive by this [`Queryable`] /// to the ones that have the given [`Locality`](crate::prelude::Locality). @@ -766,12 +730,16 @@ impl<'a, 'b> QueryableBuilder<'a, 'b, DefaultHandler> { self.origin = origin; self } -} -impl<'a, 'b, Handler> QueryableBuilder<'a, 'b, Handler> { - /// Change queryable completeness. + + /// Set whether the queryable will be undeclared when dropped. + /// + /// The method is usually used in combination with a callback like in + /// [`callback`](Self::callback) method, or a channel sender. + /// Be careful when using it, as queryables not undeclared will consume + /// resources until the session is closed. #[inline] - pub fn complete(mut self, complete: bool) -> Self { - self.complete = complete; + pub fn undeclare_on_drop(mut self, undeclare_on_drop: bool) -> Self { + self.undeclare_on_drop = undeclare_on_drop; self } } @@ -779,17 +747,41 @@ impl<'a, 'b, Handler> QueryableBuilder<'a, 'b, Handler> { /// A queryable that provides data through a [`Handler`](crate::handlers::IntoHandler). /// /// Queryables can be created from a zenoh [`Session`](crate::Session) -/// with the [`declare_queryable`](crate::session::SessionDeclarations::declare_queryable) function -/// and the [`with`](QueryableBuilder::with) function -/// of the resulting builder. +/// with the [`declare_queryable`](crate::Session::declare_queryable) function. /// -/// Queryables are automatically undeclared when dropped. +/// Callback queryables will run in background until the session is closed, +/// or until it is undeclared. +/// On the other hand, queryables with a handler are automatically undeclared when dropped. /// /// # Examples +/// +/// Using callback: +/// ```no_run +/// # #[tokio::main] +/// # async fn main() { +/// use futures::prelude::*; +/// +/// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); +/// let (tx, rx) = flume::bounded(32); +/// session +/// .declare_queryable("key/expression") +/// .callback(move |query| tx.send(query).unwrap()) +/// .await +/// .unwrap(); +/// // queryable run in background until the session is closed +/// tokio::spawn(async move { +/// while let Ok(query) = rx.recv_async().await { +/// println!(">> Handling query '{}'", query.selector()); +/// query.reply("key/expression", "value").await.unwrap(); +/// } +/// }); +/// # } +/// ``` +/// +/// Using channel handler: /// ```no_run /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let queryable = session @@ -803,23 +795,23 @@ impl<'a, 'b, Handler> QueryableBuilder<'a, 'b, Handler> { /// .await /// .unwrap(); /// } +/// // queryable is undeclared at the end of the scope /// # } /// ``` #[non_exhaustive] #[derive(Debug)] -pub struct Queryable<'a, Handler> { - pub(crate) queryable: CallbackQueryable<'a>, +pub struct Queryable { + pub(crate) inner: QueryableInner, pub(crate) handler: Handler, } -impl<'a, Handler> Queryable<'a, Handler> { +impl Queryable { /// Returns the [`EntityGlobalId`] of this Queryable. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let queryable = session.declare_queryable("key/expression") @@ -831,8 +823,8 @@ impl<'a, Handler> Queryable<'a, Handler> { #[zenoh_macros::unstable] pub fn id(&self) -> EntityGlobalId { EntityGlobalIdProto { - zid: self.queryable.session.zid().into(), - eid: self.queryable.state.id, + zid: self.inner.session_id.into(), + eid: self.inner.state.id, } .into() } @@ -851,29 +843,54 @@ impl<'a, Handler> Queryable<'a, Handler> { &mut self.handler } + /// Undeclare the [`Queryable`]. + /// + /// # Examples + /// ``` + /// # #[tokio::main] + /// # async fn main() { + /// + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); + /// let queryable = session.declare_queryable("key/expression") + /// .await + /// .unwrap(); + /// queryable.undeclare().await.unwrap(); + /// # } + /// ``` #[inline] - pub fn undeclare(self) -> impl Resolve> + 'a { + pub fn undeclare(self) -> impl Resolve> + where + Handler: Send, + { UndeclarableSealed::undeclare_inner(self, ()) } - /// Make the queryable run in background, until the session is closed. - #[inline] - #[zenoh_macros::unstable] - pub fn background(mut self) { - // It's not necessary to undeclare this resource when session close, as other sessions - // will clean all resources related to the closed one. - // So we can just never undeclare it. - self.queryable.undeclare_on_drop = false; + fn undeclare_impl(&mut self) -> ZResult<()> { + // set the flag first to avoid double panic if this function panic + self.inner.undeclare_on_drop = false; + self.inner.session.close_queryable(self.inner.state.id) + } +} + +impl Drop for Queryable { + fn drop(&mut self) { + if self.inner.undeclare_on_drop { + if let Err(error) = self.undeclare_impl() { + error!(error); + } + } } } -impl<'a, T> UndeclarableSealed<(), QueryableUndeclaration<'a>> for Queryable<'a, T> { - fn undeclare_inner(self, _: ()) -> QueryableUndeclaration<'a> { - UndeclarableSealed::undeclare_inner(self.queryable, ()) +impl UndeclarableSealed<()> for Queryable { + type Undeclaration = QueryableUndeclaration; + + fn undeclare_inner(self, _: ()) -> Self::Undeclaration { + QueryableUndeclaration(self) } } -impl Deref for Queryable<'_, Handler> { +impl Deref for Queryable { type Target = Handler; fn deref(&self) -> &Self::Target { @@ -881,21 +898,21 @@ impl Deref for Queryable<'_, Handler> { } } -impl DerefMut for Queryable<'_, Handler> { +impl DerefMut for Queryable { fn deref_mut(&mut self) -> &mut Self::Target { self.handler_mut() } } -impl<'a, Handler> Resolvable for QueryableBuilder<'a, '_, Handler> +impl Resolvable for QueryableBuilder<'_, '_, Handler> where Handler: IntoHandler<'static, Query> + Send, Handler::Handler: Send, { - type To = ZResult>; + type To = ZResult>; } -impl<'a, Handler> Wait for QueryableBuilder<'a, '_, Handler> +impl Wait for QueryableBuilder<'_, '_, Handler> where Handler: IntoHandler<'static, Query> + Send, Handler::Handler: Send, @@ -904,24 +921,27 @@ where let session = self.session; let (callback, receiver) = self.handler.into_handler(); session + .0 .declare_queryable_inner( - &self.key_expr?.to_wire(&session), + &self.key_expr?.to_wire(&session.0), self.complete, self.origin, callback, ) .map(|qable_state| Queryable { - queryable: CallbackQueryable { - session, + inner: QueryableInner { + #[cfg(feature = "unstable")] + session_id: session.zid(), + session: self.session.downgrade(), state: qable_state, - undeclare_on_drop: true, + undeclare_on_drop: self.undeclare_on_drop, }, handler: receiver, }) } } -impl<'a, Handler> IntoFuture for QueryableBuilder<'a, '_, Handler> +impl IntoFuture for QueryableBuilder<'_, '_, Handler> where Handler: IntoHandler<'static, Query> + Send, Handler::Handler: Send, diff --git a/zenoh/src/api/scouting.rs b/zenoh/src/api/scouting.rs index 4f08530533..0a41294548 100644 --- a/zenoh/src/api/scouting.rs +++ b/zenoh/src/api/scouting.rs @@ -37,7 +37,7 @@ use crate::{ /// ```no_run /// # #[tokio::main] /// # async fn main() { -/// use zenoh::{config::WhatAmI, prelude::*}; +/// use zenoh::config::WhatAmI; /// /// let receiver = zenoh::scout(WhatAmI::Peer | WhatAmI::Router, zenoh::config::default()) /// .await @@ -62,7 +62,7 @@ impl ScoutBuilder { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::{config::WhatAmI, prelude::*}; + /// use zenoh::config::WhatAmI; /// /// let scout = zenoh::scout(WhatAmI::Peer | WhatAmI::Router, zenoh::config::default()) /// .callback(|hello| { println!("{}", hello); }) @@ -75,16 +75,7 @@ impl ScoutBuilder { where Callback: Fn(Hello) + Send + Sync + 'static, { - let ScoutBuilder { - what, - config, - handler: _, - } = self; - ScoutBuilder { - what, - config, - handler: callback, - } + self.with(callback) } /// Receive the [`Hello`] messages from this scout with a mutable callback. @@ -96,7 +87,7 @@ impl ScoutBuilder { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::{config::WhatAmI, prelude::*}; + /// use zenoh::config::WhatAmI; /// /// let mut n = 0; /// let scout = zenoh::scout(WhatAmI::Peer | WhatAmI::Router, zenoh::config::default()) @@ -122,7 +113,7 @@ impl ScoutBuilder { /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::{config::WhatAmI, prelude::*}; + /// use zenoh::config::WhatAmI; /// /// let receiver = zenoh::scout(WhatAmI::Peer | WhatAmI::Router, zenoh::config::default()) /// .with(flume::bounded(32)) @@ -189,7 +180,7 @@ where /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::{config::WhatAmI, prelude::*}; +/// use zenoh::config::WhatAmI; /// /// let scout = zenoh::scout(WhatAmI::Peer | WhatAmI::Router, zenoh::config::default()) /// .callback(|hello| { println!("{}", hello); }) @@ -209,7 +200,7 @@ impl ScoutInner { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::{config::WhatAmI, prelude::*}; + /// use zenoh::config::WhatAmI; /// /// let scout = zenoh::scout(WhatAmI::Peer | WhatAmI::Router, zenoh::config::default()) /// .callback(|hello| { println!("{}", hello); }) @@ -244,7 +235,7 @@ impl fmt::Debug for ScoutInner { /// ```no_run /// # #[tokio::main] /// # async fn main() { -/// use zenoh::{config::WhatAmI, prelude::*}; +/// use zenoh::config::WhatAmI; /// /// let receiver = zenoh::scout(WhatAmI::Peer | WhatAmI::Router, zenoh::config::default()) /// .with(flume::bounded(32)) @@ -277,7 +268,7 @@ impl Scout { /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::{config::WhatAmI, prelude::*}; + /// use zenoh::config::WhatAmI; /// /// let scout = zenoh::scout(WhatAmI::Router, zenoh::config::default()) /// .with(flume::bounded(32)) @@ -359,7 +350,7 @@ fn _scout( /// ```no_run /// # #[tokio::main] /// # async fn main() { -/// use zenoh::{config::WhatAmI, prelude::*}; +/// use zenoh::config::WhatAmI; /// /// let receiver = zenoh::scout(WhatAmI::Peer | WhatAmI::Router, zenoh::config::default()) /// .await diff --git a/zenoh/src/api/session.rs b/zenoh/src/api/session.rs index 2e059710c9..b147edbb01 100644 --- a/zenoh/src/api/session.rs +++ b/zenoh/src/api/session.rs @@ -19,12 +19,12 @@ use std::{ ops::Deref, sync::{ atomic::{AtomicU16, Ordering}, - Arc, RwLock, + Arc, Mutex, RwLock, }, time::{Duration, SystemTime, UNIX_EPOCH}, }; -use tracing::{error, trace, warn}; +use tracing::{error, info, trace, warn}; use uhlc::{Timestamp, HLC}; use zenoh_buffers::ZBuf; use zenoh_collections::SingleOrVec; @@ -174,6 +174,14 @@ impl SessionState { } impl SessionState { + #[inline] + pub(crate) fn primitives(&self) -> ZResult> { + self.primitives + .as_ref() + .cloned() + .ok_or_else(|| zerror!("session closed").into()) + } + #[inline] fn get_local_res(&self, id: &ExprId) -> Option<&Resource> { self.local_resources.get(id) @@ -359,140 +367,149 @@ impl Resource { } } -#[derive(Clone)] -pub enum SessionRef<'a> { - Borrow(&'a Session), - Shared(Arc), +/// A trait implemented by types that can be undeclared. +pub trait UndeclarableSealed { + type Undeclaration: Resolve> + Send; + fn undeclare_inner(self, session: S) -> Self::Undeclaration; } -impl<'s, 'a> SessionDeclarations<'s, 'a> for SessionRef<'a> { - fn declare_subscriber<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> SubscriberBuilder<'a, 'b, DefaultHandler> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into, - { - SubscriberBuilder { - session: self.clone(), - key_expr: TryIntoKeyExpr::try_into(key_expr).map_err(Into::into), - origin: Locality::default(), - handler: DefaultHandler::default(), - } - } - fn declare_queryable<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> QueryableBuilder<'a, 'b, DefaultHandler> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into, - { - QueryableBuilder { - session: self.clone(), - key_expr: key_expr.try_into().map_err(Into::into), - complete: false, - origin: Locality::default(), - handler: DefaultHandler::default(), - } - } - fn declare_publisher<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> PublisherBuilder<'a, 'b> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into, - { - PublisherBuilder { - session: self.clone(), - key_expr: key_expr.try_into().map_err(Into::into), - encoding: Encoding::default(), - congestion_control: CongestionControl::DEFAULT, - priority: Priority::DEFAULT, - is_express: false, - #[cfg(feature = "unstable")] - reliability: Reliability::DEFAULT, - destination: Locality::default(), - } +impl<'a, T> UndeclarableSealed<&'a Session> for T +where + T: UndeclarableSealed<()>, +{ + type Undeclaration = >::Undeclaration; + + fn undeclare_inner(self, _session: &'a Session) -> Self::Undeclaration { + self.undeclare_inner(()) } - #[zenoh_macros::unstable] - fn liveliness(&'s self) -> Liveliness<'a> { - Liveliness { - session: self.clone(), - } +} + +// NOTE: `UndeclarableInner` is only pub(crate) to hide the `undeclare_inner` method. So we don't +// care about the `private_bounds` lint in this particular case. +#[allow(private_bounds)] +/// A trait implemented by types that can be undeclared. +pub trait Undeclarable: UndeclarableSealed {} + +impl Undeclarable for T where T: UndeclarableSealed {} + +pub(crate) struct SessionInner { + /// See [`WeakSession`] doc + weak_counter: Mutex, + pub(crate) runtime: Runtime, + pub(crate) state: RwLock, + pub(crate) id: u16, + owns_runtime: bool, + task_controller: TaskController, +} + +impl fmt::Debug for SessionInner { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Session") + .field("id", &self.runtime.zid()) + .finish() } - fn info(&'s self) -> SessionInfo<'a> { - SessionInfo { - session: self.clone(), - } +} + +/// The entrypoint of the zenoh API. +/// +/// Zenoh session is instantiated using [`zenoh::open`](crate::open) and it can be used to declare various +/// entities like publishers, subscribers, or querybables, as well as issuing queries. +/// +/// Session is an `Arc`-like type, it can be cloned, and it is closed when the last instance +/// is dropped (see [`Session::close`]). +/// +/// # Examples +/// ``` +/// # #[tokio::main] +/// # async fn main() { +/// +/// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); +/// session.put("key/expression", "value").await.unwrap(); +/// # } +pub struct Session(pub(crate) Arc); + +impl Session { + pub(crate) fn downgrade(&self) -> WeakSession { + WeakSession::new(&self.0) } } -impl Deref for SessionRef<'_> { - type Target = Session; +impl fmt::Debug for Session { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} - fn deref(&self) -> &Self::Target { - match self { - SessionRef::Borrow(b) => b, - SessionRef::Shared(s) => s, - } +impl Clone for Session { + fn clone(&self) -> Self { + let _weak = self.0.weak_counter.lock().unwrap(); + Self(self.0.clone()) } } -impl fmt::Debug for SessionRef<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - SessionRef::Borrow(b) => Session::fmt(b, f), - SessionRef::Shared(s) => Session::fmt(s, f), +impl Drop for Session { + fn drop(&mut self) { + let weak = self.0.weak_counter.lock().unwrap(); + if Arc::strong_count(&self.0) == *weak + /* the `Arc` currently dropped */ 1 { + drop(weak); + if let Err(error) = self.close().wait() { + tracing::error!(error) + } } } } -pub(crate) trait UndeclarableSealed> -where - O: Resolve + Send, -{ - fn undeclare_inner(self, session: S) -> O; +/// `WeakSession` provides a weak-like semantic to the arc-like session, without using [`Weak`]. +/// It allows notably to establish reference cycles inside the session, for the primitive +/// implementation. +/// When all `Session` instance are dropped, [`Session::close`] is be called and cleans +/// the reference cycles, allowing the underlying `Arc` to be properly reclaimed. +/// +/// The pseudo-weak algorithm relies on a counter wrapped in a mutex. It was indeed the simplest +/// to implement it, because atomic manipulations to achieve this semantic would not have been +/// trivial at all — what could happen if a pseudo-weak is cloned while the last session instance +/// is dropped? With a mutex, it's simple, and it works perfectly fine, as we don't care about the +/// performance penalty when it comes to session entities cloning/dropping. +/// +/// (Although it was planed to be used initially, `Weak` was in fact causing errors in the session +/// closing, because the primitive implementation seemed to be used in the closing operation.) +pub(crate) struct WeakSession(Arc); + +impl WeakSession { + fn new(session: &Arc) -> Self { + let mut weak = session.weak_counter.lock().unwrap(); + *weak += 1; + Self(session.clone()) + } } -impl<'a, O, T, G> UndeclarableSealed<&'a Session, O, T> for G -where - O: Resolve + Send, - G: UndeclarableSealed<(), O, T>, -{ - fn undeclare_inner(self, _: &'a Session) -> O { - self.undeclare_inner(()) +impl Clone for WeakSession { + fn clone(&self) -> Self { + let mut weak = self.0.weak_counter.lock().unwrap(); + *weak += 1; + Self(self.0.clone()) } } -// NOTE: `UndeclarableInner` is only pub(crate) to hide the `undeclare_inner` method. So we don't -// care about the `private_bounds` lint in this particular case. -#[allow(private_bounds)] -/// A trait implemented by types that can be undeclared. -pub trait Undeclarable: UndeclarableSealed -where - O: Resolve + Send, -{ +impl fmt::Debug for WeakSession { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } } -impl Undeclarable for U -where - O: Resolve + Send, - U: UndeclarableSealed, -{ +impl Deref for WeakSession { + type Target = Arc; + + fn deref(&self) -> &Self::Target { + &self.0 + } } -/// A zenoh session. -/// -pub struct Session { - pub(crate) runtime: Runtime, - pub(crate) state: Arc>, - pub(crate) id: u16, - close_on_drop: bool, - owns_runtime: bool, - task_controller: TaskController, +impl Drop for WeakSession { + fn drop(&mut self) { + let mut weak = self.0.weak_counter.lock().unwrap(); + *weak -= 1; + } } static SESSION_ID_COUNTER: AtomicU16 = AtomicU16::new(0); @@ -501,144 +518,103 @@ impl Session { runtime: Runtime, aggregated_subscribers: Vec, aggregated_publishers: Vec, + owns_runtime: bool, ) -> impl Resolve { ResolveClosure::new(move || { let router = runtime.router(); - let state = Arc::new(RwLock::new(SessionState::new( + let state = RwLock::new(SessionState::new( aggregated_subscribers, aggregated_publishers, - ))); - let session = Session { + )); + let session = Session(Arc::new(SessionInner { + weak_counter: Mutex::new(0), runtime: runtime.clone(), - state: state.clone(), + state, id: SESSION_ID_COUNTER.fetch_add(1, Ordering::SeqCst), - close_on_drop: true, - owns_runtime: false, + owns_runtime, task_controller: TaskController::default(), - }; + })); - runtime.new_handler(Arc::new(admin::Handler::new(session.clone()))); + runtime.new_handler(Arc::new(admin::Handler::new(session.downgrade()))); - let primitives = Some(router.new_primitives(Arc::new(session.clone()))); - zwrite!(state).primitives = primitives; + let primitives = Some(router.new_primitives(Arc::new(session.downgrade()))); + zwrite!(session.0.state).primitives = primitives; - admin::init(&session); + admin::init(session.downgrade()); session }) } - /// Consumes the given `Session`, returning a thread-safe reference-counting - /// pointer to it (`Arc`). This is equivalent to `Arc::new(session)`. - /// - /// This is useful to share ownership of the `Session` between several threads - /// and tasks. It also allows to create [`Subscriber`](crate::pubsub::Subscriber) and - /// [`Queryable`](crate::query::Queryable) with static lifetime that can be moved to several - /// threads and tasks - /// - /// Note: the given zenoh `Session` will be closed when the last reference to - /// it is dropped. - /// - /// # Examples - /// ```no_run - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let subscriber = session.declare_subscriber("key/expression") - /// .await - /// .unwrap(); - /// tokio::task::spawn(async move { - /// while let Ok(sample) = subscriber.recv_async().await { - /// println!("Received: {:?}", sample); - /// } - /// }).await; - /// # } - /// ``` - pub fn into_arc(self) -> Arc { - Arc::new(self) + /// Returns the identifier of the current session. `zid()` is a convenient shortcut. + /// See [`Session::info()`](`Session::info()`) and [`SessionInfo::zid()`](`SessionInfo::zid()`) for more details. + pub fn zid(&self) -> ZenohId { + self.info().zid().wait() + } + + pub fn hlc(&self) -> Option<&HLC> { + self.0.runtime.hlc() } - /// Consumes and leaks the given `Session`, returning a `'static` mutable - /// reference to it. The given `Session` will live for the remainder of - /// the program's life. Dropping the returned reference will cause a memory - /// leak. + /// Close the zenoh [`Session`](Session). + /// + /// Every subscriber and queryable declared will stop receiving data, and further attempt to + /// publish or query with the session or publishers will result in an error. Undeclaring an + /// entity after session closing is a no-op. Session state can be checked with + /// [`Session::is_closed`]. /// - /// This is useful to move entities (like [`Subscriber`](crate::pubsub::Subscriber)) which - /// lifetimes are bound to the session lifetime in several threads or tasks. + /// Session are automatically closed when all its instances are dropped, same as `Arc`. + /// You may still want to use this function to handle errors or close the session + /// asynchronously. + ///
+ /// Closing the session can also save bandwidth, as it avoids propagating the undeclaration + /// of the remaining entities. /// - /// Note: the given zenoh `Session` cannot be closed any more. At process - /// termination the zenoh session will terminate abruptly. If possible prefer - /// using [`Session::into_arc()`](Session::into_arc). /// /// # Examples /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// - /// let session = zenoh::Session::leak(zenoh::open(zenoh::config::peer()).await.unwrap()); - /// let subscriber = session.declare_subscriber("key/expression").await.unwrap(); - /// tokio::task::spawn(async move { + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); + /// let subscriber = session + /// .declare_subscriber("key/expression") + /// .await + /// .unwrap(); + /// let subscriber_task = tokio::spawn(async move { /// while let Ok(sample) = subscriber.recv_async().await { - /// println!("Received: {:?}", sample); + /// println!("Received: {} {:?}", sample.key_expr(), sample.payload()); /// } - /// }).await; + /// }); + /// session.close().await.unwrap(); + /// // subscriber task will end as `subscriber.recv_async()` will return `Err` + /// // subscriber undeclaration has not been sent on the wire + /// subscriber_task.await.unwrap(); /// # } /// ``` - pub fn leak(s: Self) -> &'static mut Self { - Box::leak(Box::new(s)) - } - - /// Returns the identifier of the current session. `zid()` is a convenient shortcut. - /// See [`Session::info()`](`Session::info()`) and [`SessionInfo::zid()`](`SessionInfo::zid()`) for more details. - pub fn zid(&self) -> ZenohId { - self.info().zid().wait() + pub fn close(&self) -> impl Resolve> + '_ { + self.0.close() } - pub fn hlc(&self) -> Option<&HLC> { - self.runtime.hlc() - } - - /// Close the zenoh [`Session`](Session). - /// - /// Sessions are automatically closed when dropped, but you may want to use this function to handle errors or - /// close the Session asynchronously. + /// Check if the session has been closed. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); + /// assert!(!session.is_closed()); /// session.close().await.unwrap(); + /// assert!(session.is_closed()); /// # } - /// ``` - pub fn close(mut self) -> impl Resolve> { - ResolveFuture::new(async move { - trace!("close()"); - // set the flag first to avoid double panic if this function panic - self.close_on_drop = false; - self.task_controller.terminate_all(Duration::from_secs(10)); - if self.owns_runtime { - self.runtime.close().await?; - } - let mut state = zwrite!(self.state); - // clean up to break cyclic references from self.state to itself - let primitives = state.primitives.take(); - state.queryables.clear(); - drop(state); - primitives.as_ref().unwrap().send_close(); - Ok(()) - }) + pub fn is_closed(&self) -> bool { + zread!(self.0.state).primitives.is_none() } - pub fn undeclare<'a, T, O>(&'a self, decl: T) -> O + pub fn undeclare<'a, T>(&'a self, decl: T) -> impl Resolve> + 'a where - O: Resolve>, - T: Undeclarable<&'a Self, O, ZResult<()>>, + T: Undeclarable<&'a Session> + 'a, { UndeclarableSealed::undeclare_inner(decl, self) } @@ -655,7 +631,6 @@ impl Session { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let peers = session.config().get("connect/endpoints").unwrap(); @@ -666,14 +641,13 @@ impl Session { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let _ = session.config().insert_json5("connect/endpoints", r#"["tcp/127.0.0.1/7447"]"#); /// # } /// ``` pub fn config(&self) -> &Notifier { - self.runtime.config() + self.0.runtime.config() } /// Get a new Timestamp from a Zenoh session [`Session`](Session). @@ -685,7 +659,6 @@ impl Session { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let timestamp = session.new_timestamp(); @@ -698,49 +671,176 @@ impl Session { // Called in the case that the runtime is not initialized with an hlc // UNIX_EPOCH is Returns a Timespec::zero(), Unwrap Should be permissable here let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().into(); - Timestamp::new(now, self.runtime.zid().into()) + Timestamp::new(now, self.0.runtime.zid().into()) } } } + + /// Wrap the session into an `Arc`. + #[deprecated(since = "1.0.0", note = "use `Session` directly instead")] + pub fn into_arc(self) -> Arc { + Arc::new(self) + } } -impl<'a> SessionDeclarations<'a, 'a> for Session { - fn info(&self) -> SessionInfo { - SessionRef::Borrow(self).info() +impl Session { + /// Get information about the zenoh [`Session`](Session). + /// + /// # Examples + /// ``` + /// # #[tokio::main] + /// # async fn main() { + /// + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); + /// let info = session.info(); + /// # } + /// ``` + pub fn info(&self) -> SessionInfo { + SessionInfo { + runtime: self.0.runtime.clone(), + } } - fn declare_subscriber<'b, TryIntoKeyExpr>( - &'a self, + + /// Create a [`Subscriber`](crate::pubsub::Subscriber) for the given key expression. + /// + /// # Arguments + /// + /// * `key_expr` - The resourkey expression to subscribe to + /// + /// # Examples + /// ```no_run + /// # #[tokio::main] + /// # async fn main() { + /// + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); + /// let subscriber = session.declare_subscriber("key/expression") + /// .await + /// .unwrap(); + /// tokio::task::spawn(async move { + /// while let Ok(sample) = subscriber.recv_async().await { + /// println!("Received: {:?}", sample); + /// } + /// }).await; + /// # } + /// ``` + pub fn declare_subscriber<'b, TryIntoKeyExpr>( + &self, key_expr: TryIntoKeyExpr, - ) -> SubscriberBuilder<'a, 'b, DefaultHandler> + ) -> SubscriberBuilder<'_, 'b, DefaultHandler> where TryIntoKeyExpr: TryInto>, >>::Error: Into, { - SessionRef::Borrow(self).declare_subscriber(key_expr) + SubscriberBuilder { + session: self, + key_expr: TryIntoKeyExpr::try_into(key_expr).map_err(Into::into), + origin: Locality::default(), + handler: DefaultHandler::default(), + undeclare_on_drop: true, + } } - fn declare_queryable<'b, TryIntoKeyExpr>( - &'a self, + + /// Create a [`Queryable`](crate::query::Queryable) for the given key expression. + /// + /// # Arguments + /// + /// * `key_expr` - The key expression matching the queries the + /// [`Queryable`](crate::query::Queryable) will reply to + /// + /// # Examples + /// ```no_run + /// # #[tokio::main] + /// # async fn main() { + /// + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); + /// let queryable = session.declare_queryable("key/expression") + /// .await + /// .unwrap(); + /// tokio::task::spawn(async move { + /// while let Ok(query) = queryable.recv_async().await { + /// query.reply( + /// "key/expression", + /// "value", + /// ).await.unwrap(); + /// } + /// }).await; + /// # } + /// ``` + pub fn declare_queryable<'b, TryIntoKeyExpr>( + &self, key_expr: TryIntoKeyExpr, - ) -> QueryableBuilder<'a, 'b, DefaultHandler> + ) -> QueryableBuilder<'_, 'b, DefaultHandler> where TryIntoKeyExpr: TryInto>, >>::Error: Into, { - SessionRef::Borrow(self).declare_queryable(key_expr) + QueryableBuilder { + session: self, + key_expr: key_expr.try_into().map_err(Into::into), + complete: false, + origin: Locality::default(), + handler: DefaultHandler::default(), + undeclare_on_drop: true, + } } - fn declare_publisher<'b, TryIntoKeyExpr>( - &'a self, + + /// Create a [`Publisher`](crate::pubsub::Publisher) for the given key expression. + /// + /// # Arguments + /// + /// * `key_expr` - The key expression matching resources to write + /// + /// # Examples + /// ``` + /// # #[tokio::main] + /// # async fn main() { + /// + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); + /// let publisher = session.declare_publisher("key/expression") + /// .await + /// .unwrap(); + /// publisher.put("value").await.unwrap(); + /// # } + /// ``` + pub fn declare_publisher<'b, TryIntoKeyExpr>( + &self, key_expr: TryIntoKeyExpr, - ) -> PublisherBuilder<'a, 'b> + ) -> PublisherBuilder<'_, 'b> where TryIntoKeyExpr: TryInto>, >>::Error: Into, { - SessionRef::Borrow(self).declare_publisher(key_expr) + PublisherBuilder { + session: self, + key_expr: key_expr.try_into().map_err(Into::into), + encoding: Encoding::default(), + congestion_control: CongestionControl::DEFAULT, + priority: Priority::DEFAULT, + is_express: false, + #[cfg(feature = "unstable")] + reliability: Reliability::DEFAULT, + destination: Locality::default(), + } } + + /// Obtain a [`Liveliness`] struct tied to this Zenoh [`Session`]. + /// + /// # Examples + /// ``` + /// # #[tokio::main] + /// # async fn main() { + /// + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); + /// let liveliness = session + /// .liveliness() + /// .declare_token("key/expression") + /// .await + /// .unwrap(); + /// # } + /// ``` #[zenoh_macros::unstable] - fn liveliness(&'a self) -> Liveliness { - SessionRef::Borrow(self).liveliness() + pub fn liveliness(&self) -> Liveliness<'_> { + Liveliness { session: self } } } @@ -754,7 +854,6 @@ impl Session { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let key_expr = session.declare_keyexpr("key/expression").await.unwrap(); @@ -769,18 +868,11 @@ impl Session { >>::Error: Into, { let key_expr: ZResult = key_expr.try_into().map_err(Into::into); - self._declare_keyexpr(key_expr) - } - - fn _declare_keyexpr<'a, 'b: 'a>( - &'a self, - key_expr: ZResult>, - ) -> impl Resolve>> + 'a { - let sid = self.id; + let sid = self.0.id; ResolveClosure::new(move || { let key_expr: KeyExpr = key_expr?; let prefix_len = key_expr.len() as u32; - let expr_id = self.declare_prefix(key_expr.as_str()).wait(); + let expr_id = self.0.declare_prefix(key_expr.as_str()).wait()?; let key_expr = match key_expr.0 { KeyExprInner::Borrowed(key_expr) | KeyExprInner::BorrowedWire { key_expr, .. } => { KeyExpr(KeyExprInner::BorrowedWire { @@ -816,7 +908,7 @@ impl Session { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::{bytes::Encoding, prelude::*}; + /// use zenoh::bytes::Encoding; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// session @@ -860,7 +952,6 @@ impl Session { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// session.delete("key/expression").await.unwrap(); @@ -897,7 +988,6 @@ impl Session { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let replies = session.get("key/expression").await.unwrap(); @@ -916,7 +1006,7 @@ impl Session { { let selector = selector.try_into().map_err(Into::into); let timeout = { - let conf = self.runtime.config().lock(); + let conf = self.0.runtime.config().lock(); Duration::from_millis(unwrap_or_default!(conf.queries_default_timeout())) }; let qos: QoS = request::ext::QoSType::REQUEST.into(); @@ -938,17 +1028,6 @@ impl Session { } impl Session { - pub(crate) fn clone(&self) -> Self { - Self { - runtime: self.runtime.clone(), - state: self.state.clone(), - id: self.id, - close_on_drop: false, - owns_runtime: self.owns_runtime, - task_controller: self.task_controller.clone(), - } - } - #[allow(clippy::new_ret_no_self)] pub(super) fn new( config: Config, @@ -966,28 +1045,52 @@ impl Session { } let mut runtime = runtime.build().await?; - let mut session = Self::init( + let session = Self::init( runtime.clone(), aggregated_subscribers, aggregated_publishers, + true, ) .await; - session.owns_runtime = true; runtime.start().await?; Ok(session) }) } +} +impl SessionInner { + fn close(&self) -> impl Resolve> + '_ { + ResolveFuture::new(async move { + let Some(primitives) = zwrite!(self.state).primitives.take() else { + return Ok(()); + }; + if self.owns_runtime { + info!(zid = %self.runtime.zid(), "close session"); + } + self.task_controller.terminate_all(Duration::from_secs(10)); + if self.owns_runtime { + self.runtime.close().await?; + } else { + primitives.send_close(); + } + zwrite!(self.state).queryables.clear(); + Ok(()) + }) + } - pub(crate) fn declare_prefix<'a>(&'a self, prefix: &'a str) -> impl Resolve + 'a { + pub(crate) fn declare_prefix<'a>( + &'a self, + prefix: &'a str, + ) -> impl Resolve> + 'a { ResolveClosure::new(move || { trace!("declare_prefix({:?})", prefix); let mut state = zwrite!(self.state); + let primitives = state.primitives()?; match state .local_resources .iter() .find(|(_expr_id, res)| res.name() == prefix) { - Some((expr_id, _res)) => *expr_id, + Some((expr_id, _res)) => Ok(*expr_id), None => { let expr_id = state.expr_id_counter.fetch_add(1, Ordering::SeqCst); let mut res = Resource::new(Box::from(prefix)); @@ -1004,7 +1107,6 @@ impl Session { } } state.local_resources.insert(expr_id, res); - let primitives = state.primitives.as_ref().unwrap().clone(); drop(state); primitives.send_declare(Declare { interest_id: None, @@ -1020,7 +1122,7 @@ impl Session { }, }), }); - expr_id + Ok(expr_id) } } }) @@ -1077,7 +1179,7 @@ impl Session { state.publishers.insert(id, pub_state); if let Some(res) = declared_pub { - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_interest(Interest { id, @@ -1102,7 +1204,7 @@ impl Session { if !state.publishers.values().any(|p| { p.destination != Locality::SessionLocal && p.remote_id == pub_state.remote_id }) { - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_interest(Interest { id: pub_state.remote_id, @@ -1122,7 +1224,7 @@ impl Session { } pub(crate) fn declare_subscriber_inner( - &self, + self: &Arc, key_expr: &KeyExpr, origin: Locality, callback: Callback<'static, Sample>, @@ -1205,7 +1307,7 @@ impl Session { } if let Some(key_expr) = declared_sub { - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); // If key_expr is a pure Expr, remap it to optimal Rid or RidWithSuffix // let key_expr = if !key_expr.is_optimized(self) { @@ -1251,7 +1353,11 @@ impl Session { Ok(sub_state) } - pub(crate) fn undeclare_subscriber_inner(&self, sid: Id, kind: SubscriberKind) -> ZResult<()> { + pub(crate) fn undeclare_subscriber_inner( + self: &Arc, + sid: Id, + kind: SubscriberKind, + ) -> ZResult<()> { let mut state = zwrite!(self.state); if let Some(sub_state) = state.subscribers_mut(kind).remove(&sid) { trace!("undeclare_subscriber({:?})", sub_state); @@ -1278,7 +1384,7 @@ impl Session { if !state.subscribers(kind).values().any(|s| { s.origin != Locality::SessionLocal && s.remote_id == sub_state.remote_id }) { - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_declare(Declare { interest_id: None, @@ -1301,7 +1407,7 @@ impl Session { } else { #[cfg(feature = "unstable")] if kind == SubscriberKind::LivelinessSubscriber { - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_interest(Interest { @@ -1343,7 +1449,7 @@ impl Session { state.queryables.insert(id, qable_state.clone()); if origin != Locality::SessionLocal { - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); let qabl_info = QueryableInfoType { complete, @@ -1369,7 +1475,7 @@ impl Session { if let Some(qable_state) = state.queryables.remove(&qid) { trace!("undeclare_queryable({:?})", qable_state); if qable_state.origin != Locality::SessionLocal { - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_declare(Declare { interest_id: None, @@ -1404,7 +1510,7 @@ impl Session { }); state.tokens.insert(tok_state.id, tok_state.clone()); - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_declare(Declare { interest_id: None, @@ -1467,7 +1573,7 @@ impl Session { } } - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_interest(Interest { @@ -1496,7 +1602,7 @@ impl Session { let key_expr = &tok_state.key_expr; let twin_tok = state.tokens.values().any(|s| s.key_expr == *key_expr); if !twin_tok { - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_declare(Declare { interest_id: None, @@ -1587,14 +1693,14 @@ impl Session { } #[zenoh_macros::unstable] - pub(crate) fn update_status_up(&self, state: &SessionState, key_expr: &KeyExpr) { + pub(crate) fn update_status_up(self: &Arc, state: &SessionState, key_expr: &KeyExpr) { for msub in state.matching_listeners.values() { if key_expr.intersects(&msub.key_expr) { // Cannot hold session lock when calling tables (matching_status()) // TODO: check which ZRuntime should be used self.task_controller .spawn_with_rt(zenoh_runtime::ZRuntime::Net, { - let session = self.clone(); + let session = WeakSession::new(self); let msub = msub.clone(); async move { match msub.current.lock() { @@ -1625,14 +1731,14 @@ impl Session { } #[zenoh_macros::unstable] - pub(crate) fn update_status_down(&self, state: &SessionState, key_expr: &KeyExpr) { + pub(crate) fn update_status_down(self: &Arc, state: &SessionState, key_expr: &KeyExpr) { for msub in state.matching_listeners.values() { if key_expr.intersects(&msub.key_expr) { // Cannot hold session lock when calling tables (matching_status()) // TODO: check which ZRuntime should be used self.task_controller .spawn_with_rt(zenoh_runtime::ZRuntime::Net, { - let session = self.clone(); + let session = WeakSession::new(self); let msub = msub.clone(); async move { match msub.current.lock() { @@ -1753,7 +1859,7 @@ impl Session { #[allow(clippy::too_many_arguments)] pub(crate) fn query( - &self, + self: &Arc, key_expr: &KeyExpr<'_>, parameters: &Parameters<'_>, target: QueryTarget, @@ -1788,13 +1894,13 @@ impl Session { let token = self.task_controller.get_cancellation_token(); self.task_controller .spawn_with_rt(zenoh_runtime::ZRuntime::Net, { - let state = self.state.clone(); + let session = WeakSession::new(self); #[cfg(feature = "unstable")] let zid = self.runtime.zid(); async move { tokio::select! { _ = tokio::time::sleep(timeout) => { - let mut state = zwrite!(state); + let mut state = zwrite!(session.state); if let Some(query) = state.queries.remove(&qid) { std::mem::drop(state); tracing::debug!("Timeout on query {}! Send error and close.", qid); @@ -1829,7 +1935,7 @@ impl Session { }, ); - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); if destination != Locality::SessionLocal { @@ -1883,7 +1989,7 @@ impl Session { #[cfg(feature = "unstable")] pub(crate) fn liveliness_query( - &self, + self: &Arc, key_expr: &KeyExpr<'_>, timeout: Duration, callback: Callback<'static, Reply>, @@ -1894,12 +2000,12 @@ impl Session { let token = self.task_controller.get_cancellation_token(); self.task_controller .spawn_with_rt(zenoh_runtime::ZRuntime::Net, { - let state = self.state.clone(); + let session = WeakSession::new(self); let zid = self.runtime.zid(); async move { tokio::select! { _ = tokio::time::sleep(timeout) => { - let mut state = zwrite!(state); + let mut state = zwrite!(session.state); if let Some(query) = state.liveliness_queries.remove(&id) { std::mem::drop(state); tracing::debug!("Timeout on liveliness query {}! Send error and close.", id); @@ -1921,7 +2027,7 @@ impl Session { .liveliness_queries .insert(id, LivelinessQueryState { callback }); - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_interest(Interest { @@ -1939,7 +2045,7 @@ impl Session { #[allow(clippy::too_many_arguments)] pub(crate) fn handle_query( - &self, + self: &Arc, local: bool, key_expr: &WireExpr, parameters: &str, @@ -1951,6 +2057,9 @@ impl Session { ) { let (primitives, key_expr, queryables) = { let state = zread!(self.state); + let Ok(primitives) = state.primitives() else { + return; + }; match state.wireexpr_to_keyexpr(key_expr, local) { Ok(key_expr) => { let queryables = state @@ -1976,11 +2085,7 @@ impl Session { ) .map(|(id, qable)| (*id, qable.callback.clone())) .collect::)>>(); - ( - state.primitives.as_ref().unwrap().clone(), - key_expr.into_owned(), - queryables, - ) + (primitives, key_expr.into_owned(), queryables) } Err(err) => { error!("Received Query for unknown key_expr: {}", err); @@ -1997,7 +2102,7 @@ impl Session { qid, zid: zid.into(), primitives: if local { - Arc::new(self.clone()) + Arc::new(WeakSession::new(self)) } else { primitives }, @@ -2016,161 +2121,7 @@ impl Session { } } -impl<'s> SessionDeclarations<'s, 'static> for Arc { - /// Create a [`Subscriber`](crate::pubsub::Subscriber) for the given key expression. - /// - /// # Arguments - /// - /// * `key_expr` - The resourkey expression to subscribe to - /// - /// # Examples - /// ```no_run - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let subscriber = session.declare_subscriber("key/expression") - /// .await - /// .unwrap(); - /// tokio::task::spawn(async move { - /// while let Ok(sample) = subscriber.recv_async().await { - /// println!("Received: {:?}", sample); - /// } - /// }).await; - /// # } - /// ``` - fn declare_subscriber<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> SubscriberBuilder<'static, 'b, DefaultHandler> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into, - { - SubscriberBuilder { - session: SessionRef::Shared(self.clone()), - key_expr: key_expr.try_into().map_err(Into::into), - origin: Locality::default(), - handler: DefaultHandler::default(), - } - } - - /// Create a [`Queryable`](crate::query::Queryable) for the given key expression. - /// - /// # Arguments - /// - /// * `key_expr` - The key expression matching the queries the - /// [`Queryable`](crate::query::Queryable) will reply to - /// - /// # Examples - /// ```no_run - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let queryable = session.declare_queryable("key/expression") - /// .await - /// .unwrap(); - /// tokio::task::spawn(async move { - /// while let Ok(query) = queryable.recv_async().await { - /// query.reply( - /// "key/expression", - /// "value", - /// ).await.unwrap(); - /// } - /// }).await; - /// # } - /// ``` - fn declare_queryable<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> QueryableBuilder<'static, 'b, DefaultHandler> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into, - { - QueryableBuilder { - session: SessionRef::Shared(self.clone()), - key_expr: key_expr.try_into().map_err(Into::into), - complete: false, - origin: Locality::default(), - handler: DefaultHandler::default(), - } - } - - /// Create a [`Publisher`](crate::pubsub::Publisher) for the given key expression. - /// - /// # Arguments - /// - /// * `key_expr` - The key expression matching resources to write - /// - /// # Examples - /// ``` - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let publisher = session.declare_publisher("key/expression") - /// .await - /// .unwrap(); - /// publisher.put("value").await.unwrap(); - /// # } - /// ``` - fn declare_publisher<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> PublisherBuilder<'static, 'b> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into, - { - PublisherBuilder { - session: SessionRef::Shared(self.clone()), - key_expr: key_expr.try_into().map_err(Into::into), - encoding: Encoding::default(), - congestion_control: CongestionControl::DEFAULT, - priority: Priority::DEFAULT, - is_express: false, - #[cfg(feature = "unstable")] - reliability: Reliability::DEFAULT, - destination: Locality::default(), - } - } - - /// Obtain a [`Liveliness`] struct tied to this Zenoh [`Session`]. - /// - /// # Examples - /// ``` - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let liveliness = session - /// .liveliness() - /// .declare_token("key/expression") - /// .await - /// .unwrap(); - /// # } - /// ``` - #[zenoh_macros::unstable] - fn liveliness(&'s self) -> Liveliness<'static> { - Liveliness { - session: SessionRef::Shared(self.clone()), - } - } - - fn info(&'s self) -> SessionInfo<'static> { - SessionInfo { - session: SessionRef::Shared(self.clone()), - } - } -} - -impl Primitives for Session { +impl Primitives for WeakSession { fn send_interest(&self, msg: zenoh_protocol::network::Interest) { trace!("recv Interest {} {:?}", msg.id, msg.wire_expr); } @@ -2663,174 +2614,7 @@ impl Primitives for Session { } } -impl Drop for Session { - fn drop(&mut self) { - if self.close_on_drop { - let _ = self.clone().close().wait(); - } - } -} - -impl fmt::Debug for Session { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Session").field("id", &self.zid()).finish() - } -} - -/// Functions to create zenoh entities -/// -/// This trait contains functions to create zenoh entities like -/// [`Subscriber`](crate::pubsub::Subscriber), and -/// [`Queryable`](crate::query::Queryable) -/// -/// This trait is implemented by [`Session`](crate::session::Session) itself and -/// by wrappers [`SessionRef`](crate::session::SessionRef) and [`Arc`](std::sync::Arc) -/// -/// # Examples -/// ```no_run -/// # #[tokio::main] -/// # async fn main() { -/// use zenoh::prelude::*; -/// -/// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); -/// let subscriber = session.declare_subscriber("key/expression") -/// .await -/// .unwrap(); -/// tokio::task::spawn(async move { -/// while let Ok(sample) = subscriber.recv_async().await { -/// println!("Received: {:?}", sample); -/// } -/// }).await; -/// # } -/// ``` -pub trait SessionDeclarations<'s, 'a> { - /// Create a [`Subscriber`](crate::pubsub::Subscriber) for the given key expression. - /// - /// # Arguments - /// - /// * `key_expr` - The resourkey expression to subscribe to - /// - /// # Examples - /// ```no_run - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let subscriber = session.declare_subscriber("key/expression") - /// .await - /// .unwrap(); - /// tokio::task::spawn(async move { - /// while let Ok(sample) = subscriber.recv_async().await { - /// println!("Received: {:?}", sample); - /// } - /// }).await; - /// # } - /// ``` - fn declare_subscriber<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> SubscriberBuilder<'a, 'b, DefaultHandler> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into; - - /// Create a [`Queryable`](crate::query::Queryable) for the given key expression. - /// - /// # Arguments - /// - /// * `key_expr` - The key expression matching the queries the - /// [`Queryable`](crate::query::Queryable) will reply to - /// - /// # Examples - /// ```no_run - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let queryable = session.declare_queryable("key/expression") - /// .await - /// .unwrap(); - /// tokio::task::spawn(async move { - /// while let Ok(query) = queryable.recv_async().await { - /// query.reply( - /// "key/expression", - /// "value", - /// ).await.unwrap(); - /// } - /// }).await; - /// # } - /// ``` - fn declare_queryable<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> QueryableBuilder<'a, 'b, DefaultHandler> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into; - - /// Create a [`Publisher`](crate::pubsub::Publisher) for the given key expression. - /// - /// # Arguments - /// - /// * `key_expr` - The key expression matching resources to write - /// - /// # Examples - /// ``` - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let publisher = session.declare_publisher("key/expression") - /// .await - /// .unwrap(); - /// publisher.put("value").await.unwrap(); - /// # } - /// ``` - fn declare_publisher<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> PublisherBuilder<'a, 'b> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into; - - /// Obtain a [`Liveliness`] struct tied to this Zenoh [`Session`]. - /// - /// # Examples - /// ``` - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let liveliness = session - /// .liveliness() - /// .declare_token("key/expression") - /// .await - /// .unwrap(); - /// # } - /// ``` - #[zenoh_macros::unstable] - fn liveliness(&'s self) -> Liveliness<'a>; - /// Get information about the zenoh [`Session`](Session). - /// - /// # Examples - /// ``` - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); - /// let info = session.info(); - /// # } - /// ``` - fn info(&'s self) -> SessionInfo<'a>; -} - -impl crate::net::primitives::EPrimitives for Session { +impl crate::net::primitives::EPrimitives for WeakSession { #[inline] fn send_interest(&self, ctx: crate::net::routing::RoutingContext) { (self as &dyn Primitives).send_interest(ctx.msg) @@ -2876,7 +2660,6 @@ impl crate::net::primitives::EPrimitives for Session { /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// # } @@ -2886,7 +2669,7 @@ impl crate::net::primitives::EPrimitives for Session { /// # #[tokio::main] /// # async fn main() { /// use std::str::FromStr; -/// use zenoh::{session::ZenohId, prelude::*}; +/// use zenoh::session::ZenohId; /// /// let mut config = zenoh::config::peer(); /// config.set_id(ZenohId::from_str("221b72df20924c15b8794c6bdb471150").unwrap()); @@ -2914,7 +2697,6 @@ where /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// # } @@ -3030,6 +2812,7 @@ impl Wait for InitBuilder { self.runtime, self.aggregated_subscribers, self.aggregated_publishers, + false, ) .wait()) } diff --git a/zenoh/src/api/subscriber.rs b/zenoh/src/api/subscriber.rs index 74f7605d8b..ac5202ed85 100644 --- a/zenoh/src/api/subscriber.rs +++ b/zenoh/src/api/subscriber.rs @@ -18,20 +18,27 @@ use std::{ sync::Arc, }; +use tracing::error; use zenoh_core::{Resolvable, Wait}; use zenoh_result::ZResult; #[cfg(feature = "unstable")] -use {zenoh_config::wrappers::EntityGlobalId, zenoh_protocol::core::EntityGlobalIdProto}; - -use super::{ - handlers::{locked, Callback, DefaultHandler, IntoHandler}, - key_expr::KeyExpr, - sample::{Locality, Sample}, - session::{SessionRef, UndeclarableSealed}, - Id, +use { + zenoh_config::wrappers::{EntityGlobalId, ZenohId}, + zenoh_protocol::core::EntityGlobalIdProto, }; + #[cfg(feature = "unstable")] use crate::pubsub::Reliability; +use crate::{ + api::{ + handlers::{locked, Callback, DefaultHandler, IntoHandler}, + key_expr::KeyExpr, + sample::{Locality, Sample}, + session::{UndeclarableSealed, WeakSession}, + Id, + }, + Session, +}; pub(crate) struct SubscriberState { pub(crate) id: Id, @@ -50,78 +57,23 @@ impl fmt::Debug for SubscriberState { } } -/// A subscriber that provides data through a callback. -/// -/// CallbackSubscribers can be created from a zenoh [`Session`](crate::Session) -/// with the [`declare_subscriber`](crate::SessionDeclarations::declare_subscriber) function -/// and the [`callback`](SubscriberBuilder::callback) function -/// of the resulting builder. -/// -/// Subscribers are automatically undeclared when dropped. -/// -/// # Examples -/// ``` -/// # #[tokio::main] -/// # async fn main() { -/// use zenoh::prelude::*; -/// -/// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); -/// let subscriber = session -/// .declare_subscriber("key/expression") -/// .callback(|sample| { println!("Received: {} {:?}", sample.key_expr(), sample.payload()) }) -/// .await -/// .unwrap(); -/// # } -/// ``` #[derive(Debug)] -pub(crate) struct SubscriberInner<'a> { - pub(crate) session: SessionRef<'a>, +pub(crate) struct SubscriberInner { + #[cfg(feature = "unstable")] + pub(crate) session_id: ZenohId, + pub(crate) session: WeakSession, pub(crate) state: Arc, pub(crate) kind: SubscriberKind, + // Subscriber is undeclared on drop unless its handler is a ZST, i.e. it is callback-only pub(crate) undeclare_on_drop: bool, } -impl<'a> SubscriberInner<'a> { - /// Close a [`CallbackSubscriber`](CallbackSubscriber). - /// - /// `CallbackSubscribers` are automatically closed when dropped, but you may want to use this function to handle errors or - /// close the `CallbackSubscriber` asynchronously. - /// - /// # Examples - /// ``` - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::{prelude::*, sample::Sample}; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); - /// # fn data_handler(_sample: Sample) { }; - /// let subscriber = session - /// .declare_subscriber("key/expression") - /// .callback(data_handler) - /// .await - /// .unwrap(); - /// subscriber.undeclare().await.unwrap(); - /// # } - /// ``` - #[inline] - pub fn undeclare(self) -> SubscriberUndeclaration<'a> { - UndeclarableSealed::undeclare_inner(self, ()) - } -} - -impl<'a> UndeclarableSealed<(), SubscriberUndeclaration<'a>> for SubscriberInner<'a> { - fn undeclare_inner(self, _: ()) -> SubscriberUndeclaration<'a> { - SubscriberUndeclaration { subscriber: self } - } -} - /// A [`Resolvable`] returned when undeclaring a subscriber. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session @@ -132,25 +84,19 @@ impl<'a> UndeclarableSealed<(), SubscriberUndeclaration<'a>> for SubscriberInner /// # } /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] -pub struct SubscriberUndeclaration<'a> { - subscriber: SubscriberInner<'a>, -} +pub struct SubscriberUndeclaration(Subscriber); -impl Resolvable for SubscriberUndeclaration<'_> { +impl Resolvable for SubscriberUndeclaration { type To = ZResult<()>; } -impl Wait for SubscriberUndeclaration<'_> { +impl Wait for SubscriberUndeclaration { fn wait(mut self) -> ::To { - // set the flag first to avoid double panic if this function panic - self.subscriber.undeclare_on_drop = false; - self.subscriber - .session - .undeclare_subscriber_inner(self.subscriber.state.id, self.subscriber.kind) + self.0.undeclare_impl() } } -impl IntoFuture for SubscriberUndeclaration<'_> { +impl IntoFuture for SubscriberUndeclaration { type Output = ::To; type IntoFuture = Ready<::To>; @@ -159,23 +105,12 @@ impl IntoFuture for SubscriberUndeclaration<'_> { } } -impl Drop for SubscriberInner<'_> { - fn drop(&mut self) { - if self.undeclare_on_drop { - let _ = self - .session - .undeclare_subscriber_inner(self.state.id, self.kind); - } - } -} - /// A builder for initializing a [`FlumeSubscriber`]. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session @@ -189,9 +124,9 @@ impl Drop for SubscriberInner<'_> { #[derive(Debug)] pub struct SubscriberBuilder<'a, 'b, Handler> { #[cfg(feature = "unstable")] - pub session: SessionRef<'a>, + pub session: &'a Session, #[cfg(not(feature = "unstable"))] - pub(crate) session: SessionRef<'a>, + pub(crate) session: &'a Session, #[cfg(feature = "unstable")] pub key_expr: ZResult>, @@ -207,16 +142,26 @@ pub struct SubscriberBuilder<'a, 'b, Handler> { pub handler: Handler, #[cfg(not(feature = "unstable"))] pub(crate) handler: Handler, + + #[cfg(feature = "unstable")] + pub undeclare_on_drop: bool, + #[cfg(not(feature = "unstable"))] + pub(crate) undeclare_on_drop: bool, } impl<'a, 'b> SubscriberBuilder<'a, 'b, DefaultHandler> { /// Receive the samples for this subscription with a callback. /// + /// Subscriber will not be undeclared when dropped, with the callback running + /// in background until the session is closed. + /// + /// It is in fact just a convenient shortcut for + /// `.with(my_callback).undeclare_on_drop(false)`. + /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session @@ -231,30 +176,21 @@ impl<'a, 'b> SubscriberBuilder<'a, 'b, DefaultHandler> { where Callback: Fn(Sample) + Send + Sync + 'static, { - let SubscriberBuilder { - session, - key_expr, - origin, - handler: _, - } = self; - SubscriberBuilder { - session, - key_expr, - origin, - handler: callback, - } + self.with(callback).undeclare_on_drop(false) } /// Receive the samples for this subscription with a mutable callback. /// /// Using this guarantees that your callback will never be called concurrently. - /// If your callback is also accepted by the [`callback`](SubscriberBuilder::callback) method, we suggest you use it instead of `callback_mut` + /// If your callback is also accepted by the [`callback`](SubscriberBuilder::callback) method, we suggest you use it instead of `callback_mut`. + /// + /// Subscriber will not be undeclared when dropped, with the callback running + /// in background until the session is closed. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let mut n = 0; @@ -282,7 +218,6 @@ impl<'a, 'b> SubscriberBuilder<'a, 'b, DefaultHandler> { /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session @@ -305,17 +240,19 @@ impl<'a, 'b> SubscriberBuilder<'a, 'b, DefaultHandler> { key_expr, origin, handler: _, + undeclare_on_drop, } = self; SubscriberBuilder { session, key_expr, origin, handler, + undeclare_on_drop, } } } -impl<'a, 'b, Handler> SubscriberBuilder<'a, 'b, Handler> { +impl SubscriberBuilder<'_, '_, Handler> { /// Change the subscription reliability. #[cfg(feature = "unstable")] #[deprecated( @@ -327,7 +264,7 @@ impl<'a, 'b, Handler> SubscriberBuilder<'a, 'b, Handler> { self } - /// Change the subscription reliability to `Reliable`. + /// Change the subscription reliability to `Reliable`. #[cfg(feature = "unstable")] #[deprecated( since = "1.0.0", @@ -357,18 +294,30 @@ impl<'a, 'b, Handler> SubscriberBuilder<'a, 'b, Handler> { self.origin = origin; self } + + /// Set whether the subscriber will be undeclared when dropped. + /// + /// The method is usually used in combination with a callback like in + /// [`callback`](Self::callback) method, or a channel sender. + /// Be careful when using it, as subscribers not undeclared will consume + /// resources until the session is closed. + #[inline] + pub fn undeclare_on_drop(mut self, undeclare_on_drop: bool) -> Self { + self.undeclare_on_drop = undeclare_on_drop; + self + } } // Push mode -impl<'a, Handler> Resolvable for SubscriberBuilder<'a, '_, Handler> +impl Resolvable for SubscriberBuilder<'_, '_, Handler> where Handler: IntoHandler<'static, Sample> + Send, Handler::Handler: Send, { - type To = ZResult>; + type To = ZResult>; } -impl<'a, Handler> Wait for SubscriberBuilder<'a, '_, Handler> +impl Wait for SubscriberBuilder<'_, '_, Handler> where Handler: IntoHandler<'static, Sample> + Send, Handler::Handler: Send, @@ -378,20 +327,23 @@ where let session = self.session; let (callback, receiver) = self.handler.into_handler(); session + .0 .declare_subscriber_inner(&key_expr, self.origin, callback) .map(|sub_state| Subscriber { - subscriber: SubscriberInner { - session, + inner: SubscriberInner { + #[cfg(feature = "unstable")] + session_id: session.zid(), + session: session.downgrade(), state: sub_state, kind: SubscriberKind::Subscriber, - undeclare_on_drop: true, + undeclare_on_drop: self.undeclare_on_drop, }, handler: receiver, }) } } -impl<'a, Handler> IntoFuture for SubscriberBuilder<'a, '_, Handler> +impl IntoFuture for SubscriberBuilder<'_, '_, Handler> where Handler: IntoHandler<'static, Sample> + Send, Handler::Handler: Send, @@ -407,17 +359,33 @@ where /// A subscriber that provides data through a [`Handler`](crate::handlers::IntoHandler). /// /// Subscribers can be created from a zenoh [`Session`](crate::Session) -/// with the [`declare_subscriber`](crate::session::SessionDeclarations::declare_subscriber) function -/// and the [`with`](SubscriberBuilder::with) function -/// of the resulting builder. +/// with the [`declare_subscriber`](crate::Session::declare_subscriber) function. /// -/// Subscribers are automatically undeclared when dropped. +/// Callback subscribers will run in background until the session is closed, +/// or until it is undeclared. +/// On the other hand, subscribers with a handler are automatically undeclared when dropped. /// /// # Examples +/// +/// Using callback: +/// ```no_run +/// # #[tokio::main] +/// # async fn main() { +/// +/// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); +/// session +/// .declare_subscriber("key/expression") +/// .callback(|sample| { println!("Received: {} {:?}", sample.key_expr(), sample.payload()) }) +/// .await +/// .unwrap(); +/// // subscriber run in background until the session is closed +/// # } +/// ``` +/// +/// Using channel handler: /// ```no_run /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session @@ -428,23 +396,23 @@ where /// while let Ok(sample) = subscriber.recv_async().await { /// println!("Received: {} {:?}", sample.key_expr(), sample.payload()); /// } +/// // subscriber is undeclared at the end of the scope /// # } /// ``` #[non_exhaustive] #[derive(Debug)] -pub struct Subscriber<'a, Handler> { - pub(crate) subscriber: SubscriberInner<'a>, +pub struct Subscriber { + pub(crate) inner: SubscriberInner, pub(crate) handler: Handler, } -impl<'a, Handler> Subscriber<'a, Handler> { +impl Subscriber { /// Returns the [`EntityGlobalId`] of this Subscriber. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session.declare_subscriber("key/expression") @@ -456,15 +424,15 @@ impl<'a, Handler> Subscriber<'a, Handler> { #[zenoh_macros::unstable] pub fn id(&self) -> EntityGlobalId { EntityGlobalIdProto { - zid: self.subscriber.session.zid().into(), - eid: self.subscriber.state.id, + zid: self.inner.session_id.into(), + eid: self.inner.state.id, } .into() } /// Returns the [`KeyExpr`] this Subscriber subscribes to. pub fn key_expr(&self) -> &KeyExpr<'static> { - &self.subscriber.state.key_expr + &self.inner.state.key_expr } /// Returns a reference to this subscriber's handler. @@ -481,16 +449,12 @@ impl<'a, Handler> Subscriber<'a, Handler> { &mut self.handler } - /// Close a [`Subscriber`]. - /// - /// Subscribers are automatically closed when dropped, but you may want to use this function to handle errors or - /// close the Subscriber asynchronously. + /// Undeclare the [`Subscriber`]. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session.declare_subscriber("key/expression") @@ -500,42 +464,55 @@ impl<'a, Handler> Subscriber<'a, Handler> { /// # } /// ``` #[inline] - pub fn undeclare(self) -> SubscriberUndeclaration<'a> { - self.subscriber.undeclare() + pub fn undeclare(self) -> SubscriberUndeclaration + where + Handler: Send, + { + self.undeclare_inner(()) } - /// Make the subscriber run in background, until the session is closed. - #[inline] - #[zenoh_macros::unstable] - pub fn background(mut self) { - // It's not necessary to undeclare this resource when session close, as other sessions - // will clean all resources related to the closed one. - // So we can just never undeclare it. - self.subscriber.undeclare_on_drop = false; + fn undeclare_impl(&mut self) -> ZResult<()> { + // set the flag first to avoid double panic if this function panic + self.inner.undeclare_on_drop = false; + self.inner + .session + .undeclare_subscriber_inner(self.inner.state.id, self.inner.kind) } } -impl<'a, T> UndeclarableSealed<(), SubscriberUndeclaration<'a>> for Subscriber<'a, T> { - fn undeclare_inner(self, _: ()) -> SubscriberUndeclaration<'a> { - UndeclarableSealed::undeclare_inner(self.subscriber, ()) +impl Drop for Subscriber { + fn drop(&mut self) { + if self.inner.undeclare_on_drop { + if let Err(error) = self.undeclare_impl() { + error!(error); + } + } + } +} + +impl UndeclarableSealed<()> for Subscriber { + type Undeclaration = SubscriberUndeclaration; + + fn undeclare_inner(self, _: ()) -> Self::Undeclaration { + SubscriberUndeclaration(self) } } -impl Deref for Subscriber<'_, Handler> { +impl Deref for Subscriber { type Target = Handler; fn deref(&self) -> &Self::Target { self.handler() } } -impl DerefMut for Subscriber<'_, Handler> { +impl DerefMut for Subscriber { fn deref_mut(&mut self) -> &mut Self::Target { self.handler_mut() } } /// A [`Subscriber`] that provides data through a `flume` channel. -pub type FlumeSubscriber<'a> = Subscriber<'a, flume::Receiver>; +pub type FlumeSubscriber = Subscriber>; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) enum SubscriberKind { diff --git a/zenoh/src/lib.rs b/zenoh/src/lib.rs index 9a3cefa96f..3fa24e3c36 100644 --- a/zenoh/src/lib.rs +++ b/zenoh/src/lib.rs @@ -34,7 +34,6 @@ //! ### Publishing Data //! The example below shows how to produce a value for a key expression. //! ``` -//! use zenoh::prelude::*; //! //! #[tokio::main] //! async fn main() { @@ -48,7 +47,6 @@ //! The example below shows how to consume values for a key expressions. //! ```no_run //! use futures::prelude::*; -//! use zenoh::prelude::*; //! //! #[tokio::main] //! async fn main() { @@ -65,7 +63,6 @@ //! resources whose key match the given *key expression*. //! ``` //! use futures::prelude::*; -//! use zenoh::prelude::*; //! //! #[tokio::main] //! async fn main() { @@ -128,6 +125,7 @@ pub use crate::{ session::{open, Session}, }; +#[deprecated(since = "1.0.0")] pub mod prelude; /// [Key expression](https://github.com/eclipse-zenoh/roadmap/blob/main/rfcs/ALL/Key%20Expressions.md) are Zenoh's address space. @@ -197,7 +195,7 @@ pub mod session { builders::publisher::{SessionDeleteBuilder, SessionPutBuilder}, info::{PeersZenohIdBuilder, RoutersZenohIdBuilder, SessionInfo, ZenohIdBuilder}, query::SessionGetBuilder, - session::{open, OpenBuilder, Session, SessionDeclarations, SessionRef, Undeclarable}, + session::{open, OpenBuilder, Session, Undeclarable}, }; } @@ -234,7 +232,6 @@ pub mod pubsub { #[zenoh_macros::unstable] pub use crate::api::publisher::{ MatchingListener, MatchingListenerBuilder, MatchingListenerUndeclaration, MatchingStatus, - PublisherDeclarations, PublisherRef, }; pub use crate::api::{ builders::publisher::{ @@ -298,7 +295,6 @@ pub mod scouting { /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let liveliness = session @@ -313,7 +309,6 @@ pub mod scouting { /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let replies = session.liveliness().get("key/**").await.unwrap(); @@ -329,7 +324,7 @@ pub mod scouting { /// ```no_run /// # #[tokio::main] /// # async fn main() { -/// use zenoh::{prelude::*, sample::SampleKind}; +/// use zenoh::sample::SampleKind; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session.liveliness().declare_subscriber("key/**").await.unwrap(); diff --git a/zenoh/src/net/routing/dispatcher/resource.rs b/zenoh/src/net/routing/dispatcher/resource.rs index 595bdd0a8d..2931dfdd0f 100644 --- a/zenoh/src/net/routing/dispatcher/resource.rs +++ b/zenoh/src/net/routing/dispatcher/resource.rs @@ -339,6 +339,7 @@ impl Resource { r.parent.take(); r.children.clear(); r.nonwild_prefix.take(); + r.context.take(); r.session_ctxs.clear(); } diff --git a/zenoh/src/net/runtime/adminspace.rs b/zenoh/src/net/runtime/adminspace.rs index b29401e23e..e38847c249 100644 --- a/zenoh/src/net/runtime/adminspace.rs +++ b/zenoh/src/net/runtime/adminspace.rs @@ -19,7 +19,7 @@ use std::{ use serde_json::json; use tracing::{error, trace}; use zenoh_buffers::buffer::SplitBuffer; -use zenoh_config::{unwrap_or_default, wrappers::ZenohId, ConfigValidator, ValidatedMap, WhatAmI}; +use zenoh_config::{unwrap_or_default, wrappers::ZenohId, ConfigValidator, WhatAmI}; use zenoh_core::Wait; #[cfg(feature = "plugins")] use zenoh_plugin_trait::{PluginControl, PluginStatus}; @@ -398,8 +398,7 @@ impl Primitives for AdminSpace { key, json ); - if let Err(e) = (&self.context.runtime.state.config).insert_json5(key, json) - { + if let Err(e) = self.context.runtime.state.config.insert_json5(key, json) { error!( "Error inserting conf value @/{}/{}/config/{} : {} - {}", self.context.runtime.state.zid, diff --git a/zenoh/src/net/runtime/mod.rs b/zenoh/src/net/runtime/mod.rs index f50d597247..1a02513494 100644 --- a/zenoh/src/net/runtime/mod.rs +++ b/zenoh/src/net/runtime/mod.rs @@ -279,13 +279,10 @@ impl Runtime { // the task responsible for resource clean up was aborted earlier than expected. // This should be resolved by identfying correspodning task, and placing // cancellation token manually inside it. - self.router() - .tables - .tables - .write() - .unwrap() - .root_res - .close(); + let router = self.router(); + let mut tables = router.tables.tables.write().unwrap(); + tables.root_res.close(); + tables.faces.clear(); Ok(()) } diff --git a/zenoh/src/prelude.rs b/zenoh/src/prelude.rs index 7adf400679..572788a834 100644 --- a/zenoh/src/prelude.rs +++ b/zenoh/src/prelude.rs @@ -21,23 +21,9 @@ //! Examples: //! //! ``` -//!use zenoh::prelude::*; +//! use zenoh::prelude::*; //! ``` -mod _prelude { - #[zenoh_macros::unstable] - pub use crate::api::publisher::PublisherDeclarations; - #[zenoh_macros::unstable] - pub use crate::api::selector::ZenohParameters; - pub use crate::{ - api::session::{SessionDeclarations, Undeclarable}, - config::ValidatedMap, - Error as ZError, Resolvable, Resolve, Result as ZResult, - }; -} - -pub use _prelude::*; - #[allow(deprecated)] pub use crate::AsyncResolve; #[allow(deprecated)] @@ -45,16 +31,14 @@ pub use crate::SyncResolve; pub use crate::Wait; /// Prelude to import when using Zenoh's sync API. -#[deprecated(since = "1.0.0", note = "use `zenoh::prelude` instead")] +#[deprecated(since = "1.0.0", note = "use `zenoh::Wait` instead")] pub mod sync { - pub use super::_prelude::*; #[allow(deprecated)] pub use crate::SyncResolve; } /// Prelude to import when using Zenoh's async API. -#[deprecated(since = "1.0.0", note = "use `zenoh::prelude` instead")] +#[deprecated(since = "1.0.0")] pub mod r#async { - pub use super::_prelude::*; #[allow(deprecated)] pub use crate::AsyncResolve; } diff --git a/zenoh/tests/acl.rs b/zenoh/tests/acl.rs index 2505a81983..285e68b254 100644 --- a/zenoh/tests/acl.rs +++ b/zenoh/tests/acl.rs @@ -22,7 +22,6 @@ mod test { use zenoh::{ config, config::{EndPoint, WhatAmI}, - prelude::*, sample::SampleKind, Config, Session, }; diff --git a/zenoh/tests/attachments.rs b/zenoh/tests/attachments.rs index 38b1fea136..dd9e287428 100644 --- a/zenoh/tests/attachments.rs +++ b/zenoh/tests/attachments.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // #![cfg(feature = "unstable")] -use zenoh::{bytes::ZBytes, config::Config, prelude::*}; +use zenoh::{bytes::ZBytes, config::Config, Wait}; #[test] fn attachment_pubsub() { @@ -61,7 +61,6 @@ fn attachment_pubsub() { #[test] fn attachment_queries() { - use zenoh::prelude::*; let zenoh = zenoh::open(Config::default()).wait().unwrap(); let _sub = zenoh .declare_queryable("test/attachment") diff --git a/zenoh/tests/authentication.rs b/zenoh/tests/authentication.rs index f9fb7a3b0e..63ddfcc03c 100644 --- a/zenoh/tests/authentication.rs +++ b/zenoh/tests/authentication.rs @@ -24,7 +24,6 @@ mod test { use zenoh::{ config, config::{EndPoint, WhatAmI}, - prelude::*, Config, Session, }; use zenoh_core::{zlock, ztimeout}; diff --git a/zenoh/tests/bytes.rs b/zenoh/tests/bytes.rs index a8c9c7f17a..c9a2e016f4 100644 --- a/zenoh/tests/bytes.rs +++ b/zenoh/tests/bytes.rs @@ -14,11 +14,11 @@ #![cfg(all(feature = "shared-memory", feature = "unstable"))] use zenoh::{ bytes::ZBytes, - prelude::*, shm::{ zshm, zshmmut, PosixShmProviderBackend, ShmProviderBuilder, ZShm, ZShmMut, POSIX_PROTOCOL_ID, }, + Wait, }; #[test] diff --git a/zenoh/tests/connection_retry.rs b/zenoh/tests/connection_retry.rs index 78814556f7..6bb655851b 100644 --- a/zenoh/tests/connection_retry.rs +++ b/zenoh/tests/connection_retry.rs @@ -12,11 +12,9 @@ // ZettaScale Zenoh Team, // use zenoh::{ - config::{ConnectionRetryConf, EndPoint}, - prelude::*, - Config, + config::{ConnectionRetryConf, EndPoint, ModeDependent}, + Config, Wait, }; -use zenoh_config::ModeDependent; #[test] fn retry_config_overriding() { diff --git a/zenoh/tests/events.rs b/zenoh/tests/events.rs index 11a6e18b53..e3a4d61656 100644 --- a/zenoh/tests/events.rs +++ b/zenoh/tests/events.rs @@ -52,7 +52,6 @@ async fn close_session(session: Session) { #[tokio::test(flavor = "multi_thread", worker_threads = 4)] async fn zenoh_events() { - use zenoh::prelude::SessionDeclarations; let session = open_session(&["tcp/127.0.0.1:18447"], &[]).await; let zid = session.zid(); let sub1 = diff --git a/zenoh/tests/handler.rs b/zenoh/tests/handler.rs index 640ed33b89..d87917a0dd 100644 --- a/zenoh/tests/handler.rs +++ b/zenoh/tests/handler.rs @@ -13,7 +13,7 @@ // use std::{thread, time::Duration}; -use zenoh::{handlers::RingChannel, prelude::*, Config}; +use zenoh::{handlers::RingChannel, Config, Wait}; #[test] fn pubsub_with_ringbuffer() { diff --git a/zenoh/tests/interceptors.rs b/zenoh/tests/interceptors.rs index 1f3981b66e..57ba51d5ba 100644 --- a/zenoh/tests/interceptors.rs +++ b/zenoh/tests/interceptors.rs @@ -24,8 +24,7 @@ use std::{ use zenoh::{ config::{DownsamplingItemConf, DownsamplingRuleConf, InterceptorFlow}, key_expr::KeyExpr, - prelude::*, - Config, + Config, Wait, }; // Tokio's time granularity on different platforms diff --git a/zenoh/tests/liveliness.rs b/zenoh/tests/liveliness.rs index 3f1d38af23..ff0bb4ee99 100644 --- a/zenoh/tests/liveliness.rs +++ b/zenoh/tests/liveliness.rs @@ -19,7 +19,7 @@ use zenoh_core::ztimeout; async fn test_liveliness_subscriber_clique() { use std::time::Duration; - use zenoh::{config, prelude::*, sample::SampleKind}; + use zenoh::{config, sample::SampleKind}; use zenoh_config::WhatAmI; use zenoh_link::EndPoint; const TIMEOUT: Duration = Duration::from_secs(60); @@ -83,7 +83,7 @@ async fn test_liveliness_subscriber_clique() { async fn test_liveliness_query_clique() { use std::time::Duration; - use zenoh::{config, prelude::*, sample::SampleKind}; + use zenoh::{config, sample::SampleKind}; use zenoh_config::WhatAmI; use zenoh_link::EndPoint; const TIMEOUT: Duration = Duration::from_secs(60); @@ -140,7 +140,7 @@ async fn test_liveliness_query_clique() { async fn test_liveliness_subscriber_brokered() { use std::time::Duration; - use zenoh::{config, prelude::*, sample::SampleKind}; + use zenoh::{config, sample::SampleKind}; use zenoh_config::WhatAmI; use zenoh_link::EndPoint; @@ -219,7 +219,7 @@ async fn test_liveliness_subscriber_brokered() { async fn test_liveliness_query_brokered() { use std::time::Duration; - use zenoh::{config, prelude::*, sample::SampleKind}; + use zenoh::{config, sample::SampleKind}; use zenoh_config::WhatAmI; use zenoh_link::EndPoint; const TIMEOUT: Duration = Duration::from_secs(60); @@ -290,7 +290,7 @@ async fn test_liveliness_query_brokered() { async fn test_liveliness_subscriber_local() { use std::time::Duration; - use zenoh::{config, prelude::*, sample::SampleKind}; + use zenoh::{config, sample::SampleKind}; use zenoh_config::WhatAmI; const TIMEOUT: Duration = Duration::from_secs(60); const SLEEP: Duration = Duration::from_secs(1); @@ -333,7 +333,7 @@ async fn test_liveliness_subscriber_local() { async fn test_liveliness_query_local() { use std::time::Duration; - use zenoh::{config, prelude::*, sample::SampleKind}; + use zenoh::{config, sample::SampleKind}; use zenoh_config::WhatAmI; const TIMEOUT: Duration = Duration::from_secs(60); const SLEEP: Duration = Duration::from_secs(1); diff --git a/zenoh/tests/matching.rs b/zenoh/tests/matching.rs index b2a180552d..d7825e85b8 100644 --- a/zenoh/tests/matching.rs +++ b/zenoh/tests/matching.rs @@ -15,7 +15,7 @@ use std::{str::FromStr, time::Duration}; use flume::RecvTimeoutError; -use zenoh::{config, config::Locator, prelude::*, sample::Locality, Session}; +use zenoh::{config, config::Locator, sample::Locality, Result as ZResult, Session}; use zenoh_core::ztimeout; const TIMEOUT: Duration = Duration::from_secs(60); diff --git a/zenoh/tests/qos.rs b/zenoh/tests/qos.rs index 8d7d7e7322..2ba3226310 100644 --- a/zenoh/tests/qos.rs +++ b/zenoh/tests/qos.rs @@ -15,7 +15,6 @@ use std::time::Duration; use zenoh::{ bytes::Encoding, - prelude::*, qos::{CongestionControl, Priority}, }; use zenoh_core::ztimeout; diff --git a/zenoh/tests/routing.rs b/zenoh/tests/routing.rs index 0c4c0b42f1..e9c8fd899f 100644 --- a/zenoh/tests/routing.rs +++ b/zenoh/tests/routing.rs @@ -22,7 +22,6 @@ use std::{ use tokio_util::sync::CancellationToken; use zenoh::{ config::{ModeDependentValue, WhatAmI, WhatAmIMatcher}, - prelude::*, qos::CongestionControl, Config, Result, Session, }; @@ -56,7 +55,7 @@ enum Task { impl Task { async fn run( &self, - session: Arc, + session: Session, remaining_checkpoints: Arc, token: CancellationToken, ) -> Result<()> { @@ -386,7 +385,7 @@ impl Recipe { // In case of client can't connect to some peers/routers loop { if let Ok(session) = ztimeout!(zenoh::open(config.clone())) { - break session.into_arc(); + break session; } else { tokio::time::sleep(Duration::from_secs(1)).await; } @@ -421,7 +420,7 @@ impl Recipe { // node_task_tracker.wait().await; // Close the session once all the task associated with the node are done. - ztimeout!(Arc::try_unwrap(session).unwrap().close())?; + ztimeout!(session.close())?; println!("Node: {} is closed.", &node.name); Result::Ok(()) diff --git a/zenoh/tests/session.rs b/zenoh/tests/session.rs index 1195bd2099..04f3bde4f9 100644 --- a/zenoh/tests/session.rs +++ b/zenoh/tests/session.rs @@ -23,9 +23,7 @@ use std::{ use zenoh::internal::runtime::{Runtime, RuntimeBuilder}; #[cfg(feature = "unstable")] use zenoh::pubsub::Reliability; -use zenoh::{ - config, key_expr::KeyExpr, prelude::*, qos::CongestionControl, sample::SampleKind, Session, -}; +use zenoh::{config, key_expr::KeyExpr, qos::CongestionControl, sample::SampleKind, Session}; use zenoh_core::ztimeout; #[cfg(not(feature = "unstable"))] use zenoh_protocol::core::Reliability; diff --git a/zenoh/tests/shm.rs b/zenoh/tests/shm.rs index 7b0c3aaaba..8e1205f711 100644 --- a/zenoh/tests/shm.rs +++ b/zenoh/tests/shm.rs @@ -22,14 +22,13 @@ use std::{ use zenoh::{ config, - prelude::*, pubsub::Reliability, qos::CongestionControl, shm::{ zshm, BlockOn, GarbageCollect, PosixShmProviderBackend, ShmProviderBuilder, POSIX_PROTOCOL_ID, }, - Session, + Session, Wait, }; use zenoh_core::ztimeout; diff --git a/zenoh/tests/unicity.rs b/zenoh/tests/unicity.rs index 5163420131..de63b0a97e 100644 --- a/zenoh/tests/unicity.rs +++ b/zenoh/tests/unicity.rs @@ -24,7 +24,6 @@ use zenoh::{ config, config::{EndPoint, WhatAmI}, key_expr::KeyExpr, - prelude::*, qos::CongestionControl, Session, }; diff --git a/zenohd/src/main.rs b/zenohd/src/main.rs index 9ce0a64333..85a063e3a2 100644 --- a/zenohd/src/main.rs +++ b/zenohd/src/main.rs @@ -18,7 +18,7 @@ use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilte #[cfg(feature = "loki")] use url::Url; use zenoh::{ - config::{Config, EndPoint, ModeDependentValue, PermissionsConf, ValidatedMap, WhatAmI}, + config::{Config, EndPoint, ModeDependentValue, PermissionsConf, WhatAmI}, Result, }; use zenoh_util::LibSearchDirs;