From ec6e6391cb7233c43080c3569b4988278a5e3dad Mon Sep 17 00:00:00 2001 From: Luca Cominardi Date: Thu, 11 Apr 2024 09:28:35 +0200 Subject: [PATCH] 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(),