diff --git a/commons/zenoh-macros/src/lib.rs b/commons/zenoh-macros/src/lib.rs index 003525daa9..f3533a6aea 100644 --- a/commons/zenoh-macros/src/lib.rs +++ b/commons/zenoh-macros/src/lib.rs @@ -19,7 +19,7 @@ //! [Click here for Zenoh's documentation](../zenoh/index.html) use proc_macro::TokenStream; use quote::{quote, ToTokens}; -use syn::{parse_macro_input, parse_quote, Attribute, Error, Item, LitStr, TraitItem}; +use syn::{parse_macro_input, parse_quote, Attribute, Error, Item, ItemImpl, LitStr, TraitItem}; use zenoh_keyexpr::{ format::{ macro_support::{self, SegmentBuilder}, @@ -522,3 +522,81 @@ pub fn register_param(input: proc_macro::TokenStream) -> proc_macro::TokenStream .unwrap_or_else(syn::Error::into_compile_error) .into() } + +/// Macro `#[internal_trait]` should precede +/// `impl Trait for Struct { ... }` +/// +/// This macro wraps the implementations of "internal" tratis. +/// +/// These traits are used to group set of functions which should be implemented +/// together and with the same portotyoe. E.g. `QoSBuilderTrait` provides set of +/// setters (`congestion_control`, `priority`, `express`) and we should not +/// forget to implement all these setters for each entity which supports +/// QoS functionality. +/// +/// The traits mechanism is a good way to group functions. But additional traits +/// adds extra burden to end user who have to import it every time. +/// +/// The macro `internal_trait` solves this problem by adding +/// methods with same names as in trait to structure implementation itself, +/// making them available to user without additional trait import. +/// +#[proc_macro_attribute] +pub fn internal_trait(_attr: TokenStream, item: TokenStream) -> TokenStream { + let input = parse_macro_input!(item as ItemImpl); + let trait_path = &input.trait_.as_ref().unwrap().1; + let struct_path = &input.self_ty; + let generics = &input.generics; + // let struct_lifetime = get_type_path_lifetime(struct_path); + + let mut struct_methods = quote! {}; + for item_fn in input.items.iter() { + if let syn::ImplItem::Fn(method) = item_fn { + let method_name = &method.sig.ident; + let method_generic_params = &method.sig.generics.params; + let method_generic_params = if method_generic_params.is_empty() { + quote! {} + } else { + quote! {<#method_generic_params>} + }; + let method_args = &method.sig.inputs; + let method_output = &method.sig.output; + let where_clause = &method.sig.generics.where_clause; + let mut method_call_args = quote! {}; + for arg in method_args.iter() { + match arg { + syn::FnArg::Receiver(_) => { + method_call_args.extend(quote! { self, }); + } + syn::FnArg::Typed(pat_type) => { + let pat = &pat_type.pat; + method_call_args.extend(quote! { #pat, }); + } + } + } + let mut attributes = quote! {}; + for attr in &method.attrs { + attributes.extend(quote! { + #attr + }); + } + // call corresponding trait method from struct method + struct_methods.extend(quote! { + #attributes + pub fn #method_name #method_generic_params (#method_args) #method_output #where_clause { + <#struct_path as #trait_path>::#method_name(#method_call_args) + } + }); + } + } + let struct_methods_output = quote! { + impl #generics #struct_path { + #struct_methods + } + }; + (quote! { + #input + #struct_methods_output + }) + .into() +} diff --git a/plugins/zenoh-plugin-rest/examples/z_serve_sse.rs b/plugins/zenoh-plugin-rest/examples/z_serve_sse.rs index aefdfd4f86..161e647457 100644 --- a/plugins/zenoh-plugin-rest/examples/z_serve_sse.rs +++ b/plugins/zenoh-plugin-rest/examples/z_serve_sse.rs @@ -15,10 +15,7 @@ use std::time::Duration; use clap::{arg, Command}; use zenoh::{ - config::Config, - key_expr::keyexpr, - qos::{CongestionControl, QoSBuilderTrait}, - session::SessionDeclarations, + config::Config, key_expr::keyexpr, qos::CongestionControl, session::SessionDeclarations, }; const HTML: &str = r#" diff --git a/plugins/zenoh-plugin-rest/src/lib.rs b/plugins/zenoh-plugin-rest/src/lib.rs index eb65a991d6..7ed44ebe2f 100644 --- a/plugins/zenoh-plugin-rest/src/lib.rs +++ b/plugins/zenoh-plugin-rest/src/lib.rs @@ -53,7 +53,7 @@ use zenoh_plugin_trait::{plugin_long_version, plugin_version, Plugin, PluginCont mod config; pub use config::Config; -use zenoh::{bytes::EncodingBuilderTrait, query::ReplyError}; +use zenoh::query::ReplyError; const GIT_VERSION: &str = git_version::git_version!(prefix = "v", cargo_prefix = "v"); lazy_static::lazy_static! { diff --git a/plugins/zenoh-plugin-storage-manager/src/replica/aligner.rs b/plugins/zenoh-plugin-storage-manager/src/replica/aligner.rs index 952a72f499..cf38fe4728 100644 --- a/plugins/zenoh-plugin-storage-manager/src/replica/aligner.rs +++ b/plugins/zenoh-plugin-storage-manager/src/replica/aligner.rs @@ -24,7 +24,6 @@ use tokio::sync::RwLock; use zenoh::{ internal::Value, key_expr::{KeyExpr, OwnedKeyExpr}, - prelude::*, query::Selector, sample::{Sample, SampleBuilder}, time::Timestamp, diff --git a/plugins/zenoh-plugin-storage-manager/src/replica/storage.rs b/plugins/zenoh-plugin-storage-manager/src/replica/storage.rs index d2147b137c..7352ccdeb7 100644 --- a/plugins/zenoh-plugin-storage-manager/src/replica/storage.rs +++ b/plugins/zenoh-plugin-storage-manager/src/replica/storage.rs @@ -23,7 +23,6 @@ use flume::{Receiver, Sender}; use futures::select; use tokio::sync::{Mutex, RwLock}; use zenoh::{ - bytes::EncodingBuilderTrait, internal::{ buffers::{SplitBuffer, ZBuf}, zenoh_home, Timed, TimedEvent, Timer, Value, @@ -35,7 +34,7 @@ use zenoh::{ KeyExpr, OwnedKeyExpr, }, query::{ConsolidationMode, QueryTarget}, - sample::{Sample, SampleBuilder, SampleKind, TimestampBuilderTrait}, + sample::{Sample, SampleBuilder, SampleKind}, session::{Session, SessionDeclarations}, time::{Timestamp, NTP64}, }; diff --git a/zenoh-ext/src/querying_subscriber.rs b/zenoh-ext/src/querying_subscriber.rs index 224abfde87..e3ab70c1c6 100644 --- a/zenoh-ext/src/querying_subscriber.rs +++ b/zenoh-ext/src/querying_subscriber.rs @@ -27,7 +27,7 @@ use zenoh::{ prelude::Wait, pubsub::{Reliability, Subscriber}, query::{QueryConsolidation, QueryTarget, ReplyKeyExpr, Selector}, - sample::{Locality, Sample, SampleBuilder, TimestampBuilderTrait}, + sample::{Locality, Sample, SampleBuilder}, session::{SessionDeclarations, SessionRef}, time::Timestamp, Error, Resolvable, Resolve, Result as ZResult, diff --git a/zenoh/src/api/builders/publisher.rs b/zenoh/src/api/builders/publisher.rs index 8a6961ac55..d361272f66 100644 --- a/zenoh/src/api/builders/publisher.rs +++ b/zenoh/src/api/builders/publisher.rs @@ -18,12 +18,11 @@ use zenoh_core::{Resolvable, Result as ZResult, Wait}; use zenoh_protocol::core::Reliability; 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, TimestampBuilderTrait, - }, + builders::sample::{EncodingBuilderTrait, QoSBuilderTrait, SampleBuilderTrait}, bytes::{OptionZBytes, ZBytes}, encoding::Encoding, key_expr::KeyExpr, @@ -80,6 +79,7 @@ pub struct PublicationBuilder { pub(crate) attachment: Option, } +#[zenoh_macros::internal_trait] impl QoSBuilderTrait for PublicationBuilder, T> { #[inline] fn congestion_control(self, congestion_control: CongestionControl) -> Self { @@ -126,6 +126,7 @@ impl PublicationBuilder, T> { } } +#[zenoh_macros::internal_trait] impl EncodingBuilderTrait for PublisherBuilder<'_, '_> { fn encoding>(self, encoding: T) -> Self { Self { @@ -135,6 +136,7 @@ impl EncodingBuilderTrait for PublisherBuilder<'_, '_> { } } +#[zenoh_macros::internal_trait] impl

EncodingBuilderTrait for PublicationBuilder { fn encoding>(self, encoding: T) -> Self { Self { @@ -147,6 +149,7 @@ impl

EncodingBuilderTrait for PublicationBuilder { } } +#[zenoh_macros::internal_trait] impl SampleBuilderTrait for PublicationBuilder { #[cfg(feature = "unstable")] fn source_info(self, source_info: SourceInfo) -> Self { @@ -164,6 +167,7 @@ impl SampleBuilderTrait for PublicationBuilder { } } +#[zenoh_macros::internal_trait] impl TimestampBuilderTrait for PublicationBuilder { fn timestamp>>(self, timestamp: TS) -> Self { Self { @@ -276,6 +280,7 @@ impl<'a, 'b> Clone for PublisherBuilder<'a, 'b> { } } +#[zenoh_macros::internal_trait] impl QoSBuilderTrait for PublisherBuilder<'_, '_> { /// Change the `congestion_control` to apply when routing the data. #[inline] diff --git a/zenoh/src/api/builders/sample.rs b/zenoh/src/api/builders/sample.rs index 4c1fa81406..cb7ada9e4f 100644 --- a/zenoh/src/api/builders/sample.rs +++ b/zenoh/src/api/builders/sample.rs @@ -166,6 +166,7 @@ impl SampleBuilder { } } +#[zenoh_macros::internal_trait] impl TimestampBuilderTrait for SampleBuilder { fn timestamp>>(self, timestamp: U) -> Self { Self { @@ -178,6 +179,7 @@ impl TimestampBuilderTrait for SampleBuilder { } } +#[zenoh_macros::internal_trait] impl SampleBuilderTrait for SampleBuilder { #[zenoh_macros::unstable] fn source_info(self, source_info: SourceInfo) -> Self { @@ -202,6 +204,7 @@ impl SampleBuilderTrait for SampleBuilder { } } +#[zenoh_macros::internal_trait] impl QoSBuilderTrait for SampleBuilder { fn congestion_control(self, congestion_control: CongestionControl) -> Self { let qos: QoSBuilder = self.sample.qos.into(); @@ -229,6 +232,7 @@ impl QoSBuilderTrait for SampleBuilder { } } +#[zenoh_macros::internal_trait] impl EncodingBuilderTrait for SampleBuilder { fn encoding>(self, encoding: T) -> Self { Self { diff --git a/zenoh/src/api/query.rs b/zenoh/src/api/query.rs index 2a1016db5f..1e5efee48f 100644 --- a/zenoh/src/api/query.rs +++ b/zenoh/src/api/query.rs @@ -28,7 +28,7 @@ use zenoh_protocol::core::{CongestionControl, Parameters}; use zenoh_result::ZResult; use super::{ - builders::sample::{EncodingBuilderTrait, QoSBuilderTrait}, + builders::sample::{EncodingBuilderTrait, QoSBuilderTrait, SampleBuilderTrait}, bytes::ZBytes, encoding::Encoding, handlers::{locked, Callback, DefaultHandler, IntoHandler}, @@ -41,7 +41,7 @@ use super::{ }; #[cfg(feature = "unstable")] use super::{sample::SourceInfo, selector::ZenohParameters}; -use crate::{bytes::OptionZBytes, sample::SampleBuilderTrait}; +use crate::bytes::OptionZBytes; /// The [`Queryable`](crate::query::Queryable)s that should be target of a [`get`](Session::get). pub type QueryTarget = zenoh_protocol::network::request::ext::TargetType; @@ -209,6 +209,7 @@ pub struct SessionGetBuilder<'a, 'b, Handler> { pub(crate) source_info: SourceInfo, } +#[zenoh_macros::internal_trait] impl SampleBuilderTrait for SessionGetBuilder<'_, '_, Handler> { #[zenoh_macros::unstable] fn source_info(self, source_info: SourceInfo) -> Self { @@ -244,6 +245,7 @@ impl QoSBuilderTrait for SessionGetBuilder<'_, '_, DefaultHandler> { } } +#[zenoh_macros::internal_trait] impl EncodingBuilderTrait for SessionGetBuilder<'_, '_, Handler> { fn encoding>(self, encoding: T) -> Self { let mut value = self.value.unwrap_or_default(); diff --git a/zenoh/src/api/queryable.rs b/zenoh/src/api/queryable.rs index 61ae0093ea..88c375c11f 100644 --- a/zenoh/src/api/queryable.rs +++ b/zenoh/src/api/queryable.rs @@ -300,6 +300,7 @@ pub struct ReplyBuilder<'a, 'b, T> { attachment: Option, } +#[zenoh_macros::internal_trait] impl TimestampBuilderTrait for ReplyBuilder<'_, '_, T> { fn timestamp>>(self, timestamp: U) -> Self { Self { @@ -309,6 +310,7 @@ impl TimestampBuilderTrait for ReplyBuilder<'_, '_, T> { } } +#[zenoh_macros::internal_trait] impl SampleBuilderTrait for ReplyBuilder<'_, '_, T> { fn attachment>(self, attachment: U) -> Self { let attachment: OptionZBytes = attachment.into(); @@ -344,6 +346,7 @@ impl QoSBuilderTrait for ReplyBuilder<'_, '_, T> { } } +#[zenoh_macros::internal_trait] impl EncodingBuilderTrait for ReplyBuilder<'_, '_, ReplyBuilderPut> { fn encoding>(self, encoding: T) -> Self { Self { @@ -467,6 +470,7 @@ pub struct ReplyErrBuilder<'a> { value: Value, } +#[zenoh_macros::internal_trait] impl EncodingBuilderTrait for ReplyErrBuilder<'_> { fn encoding>(self, encoding: T) -> Self { let mut value = self.value.clone(); diff --git a/zenoh/src/lib.rs b/zenoh/src/lib.rs index 12adb11678..9a3cefa96f 100644 --- a/zenoh/src/lib.rs +++ b/zenoh/src/lib.rs @@ -210,7 +210,6 @@ pub mod sample { pub use crate::api::{ builders::sample::{ SampleBuilder, SampleBuilderAny, SampleBuilderDelete, SampleBuilderPut, - SampleBuilderTrait, TimestampBuilderTrait, }, sample::{Sample, SampleFields, SampleKind, SourceSn}, }; @@ -219,7 +218,6 @@ pub mod sample { /// Payload primitives pub mod bytes { pub use crate::api::{ - builders::sample::EncodingBuilderTrait, bytes::{ Deserialize, OptionZBytes, Serialize, ZBytes, ZBytesIterator, ZBytesReader, ZBytesSliceIterator, ZBytesWriter, ZDeserializeError, ZSerde, @@ -280,7 +278,7 @@ pub mod handlers { pub mod qos { pub use zenoh_protocol::core::CongestionControl; - pub use crate::api::{builders::sample::QoSBuilderTrait, publisher::Priority}; + pub use crate::api::publisher::Priority; } /// Scouting primitives @@ -375,6 +373,11 @@ compile_error!( #[zenoh_macros::internal] pub mod internal { + pub mod traits { + pub use crate::api::builders::sample::{ + EncodingBuilderTrait, QoSBuilderTrait, SampleBuilderTrait, TimestampBuilderTrait, + }; + } pub use zenoh_core::{ zasync_executor_init, zasynclock, zerror, zlock, zread, ztimeout, zwrite, ResolveFuture, }; diff --git a/zenoh/src/net/runtime/adminspace.rs b/zenoh/src/net/runtime/adminspace.rs index d3e2a3c1ad..dc984c2e92 100644 --- a/zenoh/src/net/runtime/adminspace.rs +++ b/zenoh/src/net/runtime/adminspace.rs @@ -44,7 +44,6 @@ use super::{routing::dispatcher::face::Face, Runtime}; use crate::api::plugins::PluginsManager; use crate::{ api::{ - builders::sample::EncodingBuilderTrait, bytes::ZBytes, key_expr::KeyExpr, queryable::{Query, QueryInner}, diff --git a/zenoh/src/prelude.rs b/zenoh/src/prelude.rs index 373d56c65a..7adf400679 100644 --- a/zenoh/src/prelude.rs +++ b/zenoh/src/prelude.rs @@ -30,12 +30,7 @@ mod _prelude { #[zenoh_macros::unstable] pub use crate::api::selector::ZenohParameters; pub use crate::{ - api::{ - builders::sample::{ - EncodingBuilderTrait, QoSBuilderTrait, SampleBuilderTrait, TimestampBuilderTrait, - }, - session::{SessionDeclarations, Undeclarable}, - }, + api::session::{SessionDeclarations, Undeclarable}, config::ValidatedMap, Error as ZError, Resolvable, Resolve, Result as ZResult, };