From 56241068c7992ff7060103120674360d5aa71dbd Mon Sep 17 00:00:00 2001 From: Luca Cominardi Date: Wed, 10 Apr 2024 16:12:47 +0200 Subject: [PATCH 1/5] Attachment typedef --- zenoh/src/payload.rs | 35 ++++-- zenoh/src/sample/mod.rs | 216 ++----------------------------------- zenoh/tests/attachments.rs | 72 +++++++------ 3 files changed, 73 insertions(+), 250 deletions(-) diff --git a/zenoh/src/payload.rs b/zenoh/src/payload.rs index eac4f58e7c..832a0e0eee 100644 --- a/zenoh/src/payload.rs +++ b/zenoh/src/payload.rs @@ -1092,15 +1092,9 @@ impl TryFrom for SharedMemoryBuf { } // Tuple -impl Serialize<(A, B)> for ZSerde -where - A: Into, - B: Into, -{ - type Output = Payload; - - fn serialize(self, t: (A, B)) -> Self::Output { - let (a, b) = t; +macro_rules! impl_tuple { + ($t:expr) => {{ + let (a, b) = $t; let codec = Zenoh080::new(); let mut buffer: ZBuf = ZBuf::empty(); @@ -1117,6 +1111,29 @@ where } Payload::new(buffer) + }}; +} +impl Serialize<(A, B)> for ZSerde +where + A: Into, + B: Into, +{ + type Output = Payload; + + fn serialize(self, t: (A, B)) -> Self::Output { + impl_tuple!(t) + } +} + +impl Serialize<&(A, B)> for ZSerde +where + for<'a> &'a A: Into, + for<'b> &'b B: Into, +{ + type Output = Payload; + + fn serialize(self, t: &(A, B)) -> Self::Output { + impl_tuple!(t) } } diff --git a/zenoh/src/sample/mod.rs b/zenoh/src/sample/mod.rs index 0ef8462d2a..2429f138ee 100644 --- a/zenoh/src/sample/mod.rs +++ b/zenoh/src/sample/mod.rs @@ -212,226 +212,26 @@ impl From> for SourceInfo { } mod attachment { - #[zenoh_macros::unstable] - use zenoh_buffers::{ - reader::{HasReader, Reader}, - writer::HasWriter, - ZBuf, ZBufReader, ZSlice, - }; - #[zenoh_macros::unstable] - use zenoh_codec::{RCodec, WCodec, Zenoh080}; + use crate::Payload; #[zenoh_macros::unstable] use zenoh_protocol::zenoh::ext::AttachmentType; - /// A builder for [`Attachment`] - #[zenoh_macros::unstable] - #[derive(Debug)] - pub struct AttachmentBuilder { - pub(crate) inner: Vec, - } #[zenoh_macros::unstable] - impl Default for AttachmentBuilder { - fn default() -> Self { - Self::new() - } - } - #[zenoh_macros::unstable] - impl AttachmentBuilder { - pub fn new() -> Self { - Self { inner: Vec::new() } - } - fn _insert(&mut self, key: &[u8], value: &[u8]) { - let codec = Zenoh080; - let mut writer = self.inner.writer(); - codec.write(&mut writer, key).unwrap(); // Infallible, barring alloc failure - codec.write(&mut writer, value).unwrap(); // Infallible, barring alloc failure - } - /// Inserts a key-value pair to the attachment. - /// - /// Note that [`Attachment`] is a list of non-unique key-value pairs: inserting at the same key multiple times leads to both values being transmitted for that key. - pub fn insert + ?Sized, Value: AsRef<[u8]> + ?Sized>( - &mut self, - key: &Key, - value: &Value, - ) { - self._insert(key.as_ref(), value.as_ref()) - } - pub fn build(self) -> Attachment { - Attachment { - inner: self.inner.into(), - } - } - } - #[zenoh_macros::unstable] - impl From for Attachment { - fn from(value: AttachmentBuilder) -> Self { - Attachment { - inner: value.inner.into(), - } - } - } - #[zenoh_macros::unstable] - impl From for Option { - fn from(value: AttachmentBuilder) -> Self { - if value.inner.is_empty() { - None - } else { - Some(value.into()) - } - } - } + pub type Attachment = Payload; - #[zenoh_macros::unstable] - #[derive(Clone)] - pub struct Attachment { - pub(crate) inner: ZBuf, - } - #[zenoh_macros::unstable] - impl Default for Attachment { - fn default() -> Self { - Self::new() - } - } #[zenoh_macros::unstable] impl From for AttachmentType { fn from(this: Attachment) -> Self { - AttachmentType { buffer: this.inner } + AttachmentType { + buffer: this.into(), + } } } + #[zenoh_macros::unstable] impl From> for Attachment { fn from(this: AttachmentType) -> Self { - Attachment { inner: this.buffer } - } - } - #[zenoh_macros::unstable] - impl Attachment { - pub fn new() -> Self { - Self { - inner: ZBuf::empty(), - } - } - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - pub fn len(&self) -> usize { - self.iter().count() - } - pub fn iter(&self) -> AttachmentIterator { - self.into_iter() - } - fn _get(&self, key: &[u8]) -> Option { - self.iter() - .find_map(|(k, v)| (k.as_slice() == key).then_some(v)) - } - pub fn get>(&self, key: &Key) -> Option { - self._get(key.as_ref()) - } - fn _insert(&mut self, key: &[u8], value: &[u8]) { - let codec = Zenoh080; - let mut writer = self.inner.writer(); - codec.write(&mut writer, key).unwrap(); // Infallible, barring alloc failure - codec.write(&mut writer, value).unwrap(); // Infallible, barring alloc failure - } - /// Inserts a key-value pair to the attachment. - /// - /// Note that [`Attachment`] is a list of non-unique key-value pairs: inserting at the same key multiple times leads to both values being transmitted for that key. - /// - /// [`Attachment`] is not very efficient at inserting, so if you wish to perform multiple inserts, it's generally better to [`Attachment::extend`] after performing the inserts on an [`AttachmentBuilder`] - pub fn insert + ?Sized, Value: AsRef<[u8]> + ?Sized>( - &mut self, - key: &Key, - value: &Value, - ) { - self._insert(key.as_ref(), value.as_ref()) - } - fn _extend(&mut self, with: Self) -> &mut Self { - for slice in with.inner.zslices().cloned() { - self.inner.push_zslice(slice); - } - self - } - pub fn extend(&mut self, with: impl Into) -> &mut Self { - let with = with.into(); - self._extend(with) - } - } - #[zenoh_macros::unstable] - pub struct AttachmentIterator<'a> { - reader: ZBufReader<'a>, - } - #[zenoh_macros::unstable] - impl<'a> core::iter::IntoIterator for &'a Attachment { - type Item = (ZSlice, ZSlice); - type IntoIter = AttachmentIterator<'a>; - fn into_iter(self) -> Self::IntoIter { - AttachmentIterator { - reader: self.inner.reader(), - } - } - } - #[zenoh_macros::unstable] - impl core::fmt::Debug for Attachment { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{{")?; - for (key, value) in self { - let key = key.as_slice(); - let value = value.as_slice(); - match core::str::from_utf8(key) { - Ok(key) => write!(f, "\"{key}\": ")?, - Err(_) => { - write!(f, "0x")?; - for byte in key { - write!(f, "{byte:02X}")? - } - } - } - match core::str::from_utf8(value) { - Ok(value) => write!(f, "\"{value}\", ")?, - Err(_) => { - write!(f, "0x")?; - for byte in value { - write!(f, "{byte:02X}")? - } - write!(f, ", ")? - } - } - } - write!(f, "}}") - } - } - #[zenoh_macros::unstable] - impl<'a> core::iter::Iterator for AttachmentIterator<'a> { - type Item = (ZSlice, ZSlice); - fn next(&mut self) -> Option { - let key = Zenoh080.read(&mut self.reader).ok()?; - let value = Zenoh080.read(&mut self.reader).ok()?; - Some((key, value)) - } - fn size_hint(&self) -> (usize, Option) { - ( - (self.reader.remaining() != 0) as usize, - Some(self.reader.remaining() / 2), - ) - } - } - #[zenoh_macros::unstable] - impl<'a> core::iter::FromIterator<(&'a [u8], &'a [u8])> for AttachmentBuilder { - fn from_iter>(iter: T) -> Self { - let codec = Zenoh080; - let mut buffer: Vec = Vec::new(); - let mut writer = buffer.writer(); - for (key, value) in iter { - codec.write(&mut writer, key).unwrap(); // Infallible, barring allocation failures - codec.write(&mut writer, value).unwrap(); // Infallible, barring allocation failures - } - Self { inner: buffer } - } - } - #[zenoh_macros::unstable] - impl<'a> core::iter::FromIterator<(&'a [u8], &'a [u8])> for Attachment { - fn from_iter>(iter: T) -> Self { - AttachmentBuilder::from_iter(iter).into() + this.buffer.into() } } } @@ -468,7 +268,7 @@ impl TryFrom for SampleKind { } #[zenoh_macros::unstable] -pub use attachment::{Attachment, AttachmentBuilder, AttachmentIterator}; +pub use attachment::Attachment; /// Structure with public fields for sample. It's convenient if it's necessary to decompose a sample into its fields. pub struct SampleFields { diff --git a/zenoh/tests/attachments.rs b/zenoh/tests/attachments.rs index 9fb99b7cc0..2a58749701 100644 --- a/zenoh/tests/attachments.rs +++ b/zenoh/tests/attachments.rs @@ -13,20 +13,25 @@ // #[cfg(feature = "unstable")] #[test] -fn pubsub() { +fn attachment_pubsub() { use zenoh::prelude::sync::*; + use zenoh::sample::Attachment; let zenoh = zenoh::open(Config::default()).res().unwrap(); let _sub = zenoh .declare_subscriber("test/attachment") .callback(|sample| { println!("{}", sample.payload().deserialize::().unwrap()); - for (k, v) in sample.attachment().unwrap() { + for (k, v) in sample.attachment().unwrap().iter::<( + [u8; std::mem::size_of::()], + [u8; std::mem::size_of::()], + )>() { assert!(k.iter().rev().zip(v.as_slice()).all(|(k, v)| k == v)) } }) .res() .unwrap(); + let publisher = zenoh.declare_publisher("test/attachment").res().unwrap(); for i in 0..10 { let mut backer = [( @@ -36,55 +41,57 @@ fn pubsub() { for (j, backer) in backer.iter_mut().enumerate() { *backer = ((i * 10 + j).to_le_bytes(), (i * 10 + j).to_be_bytes()) } + zenoh .put("test/attachment", "put") - .attachment(Some( - backer - .iter() - .map(|b| (b.0.as_slice(), b.1.as_slice())) - .collect(), - )) + .attachment(Attachment::from_iter(backer.iter())) .res() .unwrap(); publisher .put("publisher") - .attachment(Some( - backer - .iter() - .map(|b| (b.0.as_slice(), b.1.as_slice())) - .collect(), - )) + .attachment(Attachment::from_iter(backer.iter())) .res() .unwrap(); } } + #[cfg(feature = "unstable")] #[test] -fn queries() { +fn attachment_queries() { use zenoh::{prelude::sync::*, sample::builder::SampleBuilderTrait, sample::Attachment}; let zenoh = zenoh::open(Config::default()).res().unwrap(); let _sub = zenoh .declare_queryable("test/attachment") .callback(|query| { - println!( - "{}", - query - .value() - .map(|q| q.payload.deserialize::().unwrap()) - .unwrap_or_default() - ); - let mut attachment = Attachment::new(); - for (k, v) in query.attachment().unwrap() { + let s = query + .value() + .map(|q| q.payload.deserialize::().unwrap()) + .unwrap_or_default(); + println!("Query value: {}", s); + + let attachment = query.attachment().unwrap(); + println!("Query attachment: {:?}", attachment); + for (k, v) in attachment.iter::<( + [u8; std::mem::size_of::()], + [u8; std::mem::size_of::()], + )>() { assert!(k.iter().rev().zip(v.as_slice()).all(|(k, v)| k == v)); - attachment.insert(&k, &k); } + query .reply( query.key_expr().clone(), query.value().unwrap().payload.clone(), ) - .attachment(attachment) + .attachment(Attachment::from_iter( + attachment + .iter::<( + [u8; std::mem::size_of::()], + [u8; std::mem::size_of::()], + )>() + .map(|(k, _)| (k, k)), + )) .res() .unwrap(); }) @@ -98,20 +105,19 @@ fn queries() { for (j, backer) in backer.iter_mut().enumerate() { *backer = ((i * 10 + j).to_le_bytes(), (i * 10 + j).to_be_bytes()) } + let get = zenoh .get("test/attachment") .payload("query") - .attachment(Some( - backer - .iter() - .map(|b| (b.0.as_slice(), b.1.as_slice())) - .collect(), - )) + .attachment(Attachment::from_iter(backer.iter())) .res() .unwrap(); while let Ok(reply) = get.recv() { let response = reply.sample.as_ref().unwrap(); - for (k, v) in response.attachment().unwrap() { + for (k, v) in response.attachment().unwrap().iter::<( + [u8; std::mem::size_of::()], + [u8; std::mem::size_of::()], + )>() { assert_eq!(k, v) } } From badf14b58e7c1c484277b35b2672847646e5a5f9 Mon Sep 17 00:00:00 2001 From: Luca Cominardi Date: Wed, 10 Apr 2024 16:17:36 +0200 Subject: [PATCH 2/5] Fix io::Write for ZBuf and Payload --- commons/zenoh-buffers/src/zbuf.rs | 8 ++++---- zenoh/src/payload.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/commons/zenoh-buffers/src/zbuf.rs b/commons/zenoh-buffers/src/zbuf.rs index 4a655ce36a..616dbb1b96 100644 --- a/commons/zenoh-buffers/src/zbuf.rs +++ b/commons/zenoh-buffers/src/zbuf.rs @@ -720,12 +720,12 @@ impl BacktrackableWriter for ZBufWriter<'_> { #[cfg(feature = "std")] impl<'a> io::Write for ZBufWriter<'a> { fn write(&mut self, buf: &[u8]) -> io::Result { + if buf.is_empty() { + return Ok(0); + } match ::write(self, buf) { Ok(n) => Ok(n.get()), - Err(_) => Err(io::Error::new( - io::ErrorKind::UnexpectedEof, - "UnexpectedEof", - )), + Err(_) => Err(io::ErrorKind::UnexpectedEof.into()), } } diff --git a/zenoh/src/payload.rs b/zenoh/src/payload.rs index 832a0e0eee..ef701aa0b6 100644 --- a/zenoh/src/payload.rs +++ b/zenoh/src/payload.rs @@ -858,7 +858,7 @@ impl Serialize<&serde_yaml::Value> for ZSerde { fn serialize(self, t: &serde_yaml::Value) -> Self::Output { let mut payload = Payload::empty(); - serde_yaml::to_writer(payload.0.writer(), t)?; + serde_yaml::to_writer(payload.writer(), t)?; Ok(payload) } } From 2780958c8cfe173e0d2bc4dc7e7510c2072781f7 Mon Sep 17 00:00:00 2001 From: Luca Cominardi Date: Wed, 10 Apr 2024 16:42:27 +0200 Subject: [PATCH 3/5] FIx doc --- zenoh/src/payload.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zenoh/src/payload.rs b/zenoh/src/payload.rs index ef701aa0b6..39a8ca8932 100644 --- a/zenoh/src/payload.rs +++ b/zenoh/src/payload.rs @@ -109,7 +109,7 @@ impl Payload { PayloadWriter(self.0.writer()) } - /// Encode an object of type `T` as a [`Value`] using the [`ZSerde`]. + /// Serialize an object of type `T` as a [`Value`] using the [`ZSerde`]. /// /// ```rust /// use zenoh::payload::Payload; @@ -126,7 +126,7 @@ impl Payload { ZSerde.serialize(t) } - /// Decode an object of type `T` from a [`Value`] using the [`ZSerde`]. + /// Deserialize an object of type `T` from a [`Value`] using the [`ZSerde`]. pub fn deserialize<'a, T>(&'a self) -> ZResult where ZSerde: Deserialize<'a, T>, @@ -137,7 +137,7 @@ impl Payload { .map_err(|e| zerror!("{:?}", e).into()) } - /// Decode an object of type `T` from a [`Value`] using the [`ZSerde`]. + /// Infallibly deserialize an object of type `T` from a [`Value`] using the [`ZSerde`]. pub fn into<'a, T>(&'a self) -> T where ZSerde: Deserialize<'a, T, Error = Infallible>, From 3484fa0f7905103f58b25440de84cd5e1e567f60 Mon Sep 17 00:00:00 2001 From: Luca Cominardi Date: Wed, 10 Apr 2024 17:05:22 +0200 Subject: [PATCH 4/5] Add payload serializer test --- zenoh/src/payload.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/zenoh/src/payload.rs b/zenoh/src/payload.rs index 39a8ca8932..796ec39328 100644 --- a/zenoh/src/payload.rs +++ b/zenoh/src/payload.rs @@ -91,6 +91,11 @@ impl Payload { Ok(Payload::new(buf)) } + /// Get a [`PayloadWriter`] implementing [`std::io::Write`] trait. + pub fn writer(&mut self) -> PayloadWriter<'_> { + PayloadWriter(self.0.writer()) + } + /// Get a [`PayloadReader`] implementing [`std::io::Read`] trait. pub fn iter(&self) -> PayloadIterator<'_, T> where @@ -104,11 +109,6 @@ impl Payload { } } - /// Get a [`PayloadWriter`] implementing [`std::io::Write`] trait. - pub fn writer(&mut self) -> PayloadWriter<'_> { - PayloadWriter(self.0.writer()) - } - /// Serialize an object of type `T` as a [`Value`] using the [`ZSerde`]. /// /// ```rust @@ -1419,5 +1419,14 @@ mod tests { println!("Deserialize:\t{:?}\n", p); let o = HashMap::from_iter(p.iter::<(usize, Vec)>()); assert_eq!(hm, o); + + let mut hm: HashMap = HashMap::new(); + hm.insert(String::from("0"), String::from("a")); + hm.insert(String::from("1"), String::from("b")); + println!("Serialize:\t{:?}", hm); + let p = Payload::from_iter(hm.iter()); + println!("Deserialize:\t{:?}\n", p); + let o = HashMap::from_iter(p.iter::<(String, String)>()); + assert_eq!(hm, o); } } From ec6e6391cb7233c43080c3569b4988278a5e3dad Mon Sep 17 00:00:00 2001 From: Luca Cominardi Date: Thu, 11 Apr 2024 09:28:35 +0200 Subject: [PATCH 5/5] OptionPayload for API ergonomicity --- examples/examples/z_pub.rs | 27 +++++------------------ examples/examples/z_sub.rs | 9 +++++++- zenoh/src/payload.rs | 44 +++++++++++++++++++++++++++++++++++++ zenoh/src/publication.rs | 4 +++- zenoh/src/query.rs | 4 +++- zenoh/src/queryable.rs | 4 +++- zenoh/src/sample/builder.rs | 8 ++++--- 7 files changed, 72 insertions(+), 28 deletions(-) diff --git a/examples/examples/z_pub.rs b/examples/examples/z_pub.rs index 8cd3c4edba..68fbf02ca2 100644 --- a/examples/examples/z_pub.rs +++ b/examples/examples/z_pub.rs @@ -35,16 +35,12 @@ async fn main() { tokio::time::sleep(Duration::from_secs(1)).await; let buf = format!("[{idx:4}] {value}"); println!("Putting Data ('{}': '{}')...", &key_expr, buf); - let mut put = publisher.put(buf); - if let Some(attachment) = &attachment { - put = put.attachment(Some( - attachment - .split('&') - .map(|pair| split_once(pair, '=')) - .collect(), - )) - } - put.res().await.unwrap(); + publisher + .put(buf) + .attachment(&attachment) + .res() + .await + .unwrap(); } } @@ -65,17 +61,6 @@ struct Args { common: CommonArgs, } -fn split_once(s: &str, c: char) -> (&[u8], &[u8]) { - let s_bytes = s.as_bytes(); - match s.find(c) { - Some(index) => { - let (l, r) = s_bytes.split_at(index); - (l, &r[1..]) - } - None => (s_bytes, &[]), - } -} - fn parse_args() -> (Config, KeyExpr<'static>, String, Option) { let args = Args::parse(); (args.common.into(), args.key, args.value, args.attach) diff --git a/examples/examples/z_sub.rs b/examples/examples/z_sub.rs index 299f0c8f49..1e19bbff0e 100644 --- a/examples/examples/z_sub.rs +++ b/examples/examples/z_sub.rs @@ -40,12 +40,19 @@ async fn main() { .payload() .deserialize::() .unwrap_or_else(|e| format!("{}", e)); - println!( + print!( ">> [Subscriber] Received {} ('{}': '{}')", sample.kind(), sample.key_expr().as_str(), payload ); + if let Some(att) = sample.attachment() { + let att = att + .deserialize::() + .unwrap_or_else(|e| format!("{}", e)); + print!(" ({})", att); + } + println!(); } } diff --git a/zenoh/src/payload.rs b/zenoh/src/payload.rs index 796ec39328..11a6f0c360 100644 --- a/zenoh/src/payload.rs +++ b/zenoh/src/payload.rs @@ -231,6 +231,50 @@ where } } +/// Wrapper type for API ergonomicity to allow any type `T` to be converted into `Option` where `T` implements `Into`. +#[repr(transparent)] +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct OptionPayload(Option); + +impl From for OptionPayload +where + T: Into, +{ + fn from(value: T) -> Self { + Self(Some(value.into())) + } +} + +impl From> for OptionPayload +where + T: Into, +{ + fn from(mut value: Option) -> Self { + match value.take() { + Some(v) => Self(Some(v.into())), + None => Self(None), + } + } +} + +impl From<&Option> for OptionPayload +where + for<'a> &'a T: Into, +{ + fn from(value: &Option) -> Self { + match value.as_ref() { + Some(v) => Self(Some(v.into())), + None => Self(None), + } + } +} + +impl From for Option { + fn from(value: OptionPayload) -> Self { + value.0 + } +} + /// The default serializer for Zenoh payload. It supports primitives types, such as: vec, int, uint, float, string, bool. /// It also supports common Rust serde values. #[derive(Clone, Copy, Debug)] diff --git a/zenoh/src/publication.rs b/zenoh/src/publication.rs index 4f31c73a24..cdd9e810a6 100644 --- a/zenoh/src/publication.rs +++ b/zenoh/src/publication.rs @@ -14,6 +14,7 @@ //! Publishing primitives. use crate::net::primitives::Primitives; +use crate::payload::OptionPayload; use crate::prelude::*; #[zenoh_macros::unstable] use crate::sample::Attachment; @@ -167,7 +168,8 @@ impl SampleBuilderTrait for PublicationBuilder { } } #[cfg(feature = "unstable")] - fn attachment>>(self, attachment: TA) -> Self { + fn attachment>(self, attachment: TA) -> Self { + let attachment: OptionPayload = attachment.into(); Self { attachment: attachment.into(), ..self diff --git a/zenoh/src/query.rs b/zenoh/src/query.rs index 3a380bd1c9..96b2ccec38 100644 --- a/zenoh/src/query.rs +++ b/zenoh/src/query.rs @@ -14,6 +14,7 @@ //! Query primitives. use crate::handlers::{locked, Callback, DefaultHandler}; +use crate::payload::OptionPayload; use crate::prelude::*; #[zenoh_macros::unstable] use crate::sample::Attachment; @@ -144,7 +145,8 @@ impl SampleBuilderTrait for GetBuilder<'_, '_, Handler> { } #[cfg(feature = "unstable")] - fn attachment>>(self, attachment: T) -> Self { + fn attachment>(self, attachment: T) -> Self { + let attachment: OptionPayload = attachment.into(); Self { attachment: attachment.into(), ..self diff --git a/zenoh/src/queryable.rs b/zenoh/src/queryable.rs index 0ad3a36c07..8d057c592b 100644 --- a/zenoh/src/queryable.rs +++ b/zenoh/src/queryable.rs @@ -17,6 +17,7 @@ use crate::encoding::Encoding; use crate::handlers::{locked, DefaultHandler}; use crate::net::primitives::Primitives; +use crate::payload::OptionPayload; use crate::prelude::*; use crate::sample::builder::SampleBuilder; use crate::sample::QoSBuilder; @@ -308,7 +309,8 @@ impl TimestampBuilderTrait for ReplyBuilder<'_, '_, T> { #[cfg(feature = "unstable")] impl SampleBuilderTrait for ReplyBuilder<'_, '_, T> { #[cfg(feature = "unstable")] - fn attachment>>(self, attachment: U) -> Self { + fn attachment>(self, attachment: U) -> Self { + let attachment: OptionPayload = attachment.into(); Self { attachment: attachment.into(), ..self diff --git a/zenoh/src/sample/builder.rs b/zenoh/src/sample/builder.rs index bad35024ef..79acde33a3 100644 --- a/zenoh/src/sample/builder.rs +++ b/zenoh/src/sample/builder.rs @@ -14,8 +14,9 @@ use std::marker::PhantomData; +use crate::payload::OptionPayload; #[cfg(feature = "unstable")] -use crate::sample::{Attachment, SourceInfo}; +use crate::sample::SourceInfo; use crate::sample::{QoS, QoSBuilder}; use crate::Encoding; use crate::KeyExpr; @@ -51,7 +52,7 @@ pub trait SampleBuilderTrait { fn source_info(self, source_info: SourceInfo) -> Self; /// Attach user-provided data in key-value format #[zenoh_macros::unstable] - fn attachment>>(self, attachment: T) -> Self; + fn attachment>(self, attachment: T) -> Self; } pub trait ValueBuilderTrait { @@ -177,7 +178,8 @@ impl SampleBuilderTrait for SampleBuilder { } #[zenoh_macros::unstable] - fn attachment>>(self, attachment: U) -> Self { + fn attachment>(self, attachment: U) -> Self { + let attachment: OptionPayload = attachment.into(); Self { sample: Sample { attachment: attachment.into(),