diff --git a/Cargo.lock b/Cargo.lock index 015a06ee67..3fc06ee967 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2091,6 +2091,12 @@ dependencies = [ "spin", ] +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + [[package]] name = "libc" version = "0.2.158" @@ -2171,7 +2177,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "674883a98273598ac3aad4301724c56734bea90574c5033af067e8f9fb5eb399" dependencies = [ "prost 0.12.6", - "prost-types", + "prost-types 0.12.6", ] [[package]] @@ -2292,6 +2298,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "multimap" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" + [[package]] name = "nanorand" version = "0.7.0" @@ -2976,6 +2988,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" +dependencies = [ + "proc-macro2", + "syn 2.0.77", +] + [[package]] name = "proc-macro-crate" version = "3.2.0" @@ -3012,12 +3034,33 @@ dependencies = [ [[package]] name = "prost" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2ecbe40f08db5c006b5764a2645f7f3f141ce756412ac9e1dd6087e6d32995" +checksum = "7b0487d90e047de87f984913713b85c601c05609aad5b0df4b4573fbf69aa13f" dependencies = [ "bytes", - "prost-derive 0.13.2", + "prost-derive 0.13.3", +] + +[[package]] +name = "prost-build" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15" +dependencies = [ + "bytes", + "heck", + "itertools 0.13.0", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease", + "prost 0.13.3", + "prost-types 0.13.3", + "regex", + "syn 2.0.77", + "tempfile", ] [[package]] @@ -3035,9 +3078,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac" +checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" dependencies = [ "anyhow", "itertools 0.13.0", @@ -3055,6 +3098,15 @@ dependencies = [ "prost 0.12.6", ] +[[package]] +name = "prost-types" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4759aa0d3a6232fb8dbdb97b61de2c20047c68aca932c7ed76da9d788508d670" +dependencies = [ + "prost 0.13.3", +] + [[package]] name = "quinn" version = "0.11.5" @@ -4803,12 +4855,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" -[[package]] -name = "unwrap-infallible" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "151ac09978d3c2862c4e39b557f4eceee2cc72150bc4cb4f16abf061b6e381fb" - [[package]] name = "unzip-n" version = "0.1.2" @@ -5089,6 +5135,18 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "which" +version = "6.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f" +dependencies = [ + "either", + "home", + "rustix 0.38.37", + "winsafe", +] + [[package]] name = "win-sys" version = "0.3.1" @@ -5368,6 +5426,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "winsafe" +version = "0.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" + [[package]] name = "x509-parser" version = "0.16.0" @@ -5433,7 +5497,6 @@ dependencies = [ "tokio-util", "tracing", "uhlc", - "unwrap-infallible", "vec_map", "zenoh-buffers", "zenoh-codec", @@ -5541,13 +5604,12 @@ version = "1.0.0-dev" dependencies = [ "clap", "futures", - "prost 0.13.2", + "prost 0.13.3", + "prost-build", "rand 0.8.5", - "rustc_version 0.4.1", "serde_json", - "serde_yaml", "tokio", - "unwrap-infallible", + "which", "zenoh", "zenoh-ext", ] @@ -5559,6 +5621,8 @@ dependencies = [ "bincode", "flume", "futures", + "leb128", + "rand 0.8.5", "serde", "tokio", "tracing", diff --git a/Cargo.toml b/Cargo.toml index 2fcaaa9cd5..3f58ffae46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -113,6 +113,7 @@ json5 = "0.4.1" jsonschema = { version = "0.20", default-features = false } keyed-set = "1.0.0" lazy_static = "1.5.0" +leb128 = "0.2" libc = "0.2.158" libloading = "0.8" tracing = "0.1" @@ -176,7 +177,6 @@ tokio-rustls = { version = "0.26.0", default-features = false } thread-priority = "1.1.0" typenum = "1.17.0" uhlc = { version = "0.8.0", default-features = false } # Default features are disabled due to usage in no_std crates -unwrap-infallible = "0.1.5" unzip-n = "0.1.2" url = "2.5.2" urlencoding = "2.1.3" 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 ad96d0b2b0..262abdba95 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 @@ -38,8 +38,8 @@ async fn main() { sample.key_expr().as_str(), sample .payload() - .deserialize::() - .unwrap_or_else(|e| format!("{}", e)) + .try_to_string() + .unwrap_or_else(|e| e.to_string().into()) ); }) .await 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 e82ecba477..9094071028 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 @@ -53,7 +53,7 @@ async fn main() { println!("Sending Query '{get_selector}'..."); let replies = get_session .get(&get_selector) - .payload(idx) + .payload(idx.to_string()) .target(QueryTarget::All) .await .unwrap(); @@ -64,14 +64,14 @@ async fn main() { sample.key_expr().as_str(), sample .payload() - .deserialize::() - .unwrap_or_else(|e| format!("{}", e)) + .try_to_string() + .unwrap_or_else(|e| e.to_string().into()) ), Err(err) => println!( ">> Received (ERROR: '{}')", err.payload() - .deserialize::() - .unwrap_or_else(|e| format!("{}", e)) + .try_to_string() + .unwrap_or_else(|e| e.to_string().into()) ), } } diff --git a/commons/zenoh-buffers/src/zbuf.rs b/commons/zenoh-buffers/src/zbuf.rs index 2d5bcca213..76c06e2765 100644 --- a/commons/zenoh-buffers/src/zbuf.rs +++ b/commons/zenoh-buffers/src/zbuf.rs @@ -53,6 +53,10 @@ impl ZBuf { self.slices.as_mut().iter_mut() } + pub fn into_zslices(self) -> impl Iterator { + self.slices.into_iter() + } + pub fn push_zslice(&mut self, zslice: ZSlice) { if !zslice.is_empty() { self.slices.push(zslice); @@ -404,7 +408,7 @@ impl<'a> io::Seek for ZBufReader<'a> { .fold(0, |acc, s| acc + s.len()) + self.cursor.byte; let current_pos = i64::try_from(current_pos) - .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("{}", e)))?; + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?; let offset = match pos { std::io::SeekFrom::Start(s) => i64::try_from(s).unwrap_or(i64::MAX) - current_pos, diff --git a/examples/Cargo.toml b/examples/Cargo.toml index aa131246f1..62dadccedf 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -36,9 +36,7 @@ clap = { workspace = true, features = ["derive"] } futures = { workspace = true } prost = { workspace = true } serde_json = { workspace = true } -serde_yaml = { workspace = true } tokio = { workspace = true, features = ["rt-multi-thread", "time", "io-std"] } -unwrap-infallible = { workspace = true } zenoh = { workspace = true, default-features = true } zenoh-ext = { workspace = true } @@ -46,7 +44,8 @@ zenoh-ext = { workspace = true } rand = { workspace = true, features = ["default"] } [build-dependencies] -rustc_version = { workspace = true } +prost-build = "0.13" +which = "6" [[example]] name = "z_scout" diff --git a/examples/build.rs b/examples/build.rs new file mode 100644 index 0000000000..ad3169be24 --- /dev/null +++ b/examples/build.rs @@ -0,0 +1,16 @@ +use std::{env, fs::File, io::Write, path::Path}; + +use which::which; + +fn main() -> std::io::Result<()> { + // If protoc is not installed, we cheat because building protoc from source + // with protobuf-src is way too long + if which("protoc").is_err() { + const PROTO: &str = r#"#[derive(Clone, PartialEq, ::prost::Message)] pub struct Entity { #[prost(uint32, tag = "1")] pub id: u32, #[prost(string, tag = "2")] pub name: ::prost::alloc::string::String,}"#; + let out_path = Path::new(&env::var("OUT_DIR").unwrap()).join("example.rs"); + File::create(out_path)?.write_all(PROTO.as_bytes())?; + return Ok(()); + } + prost_build::compile_protos(&["examples/example.proto"], &["examples/"])?; + Ok(()) +} diff --git a/examples/examples/z_bytes.rs b/examples/examples/z_bytes.rs index 8f6e82e944..f9127c1ef8 100644 --- a/examples/examples/z_bytes.rs +++ b/examples/examples/z_bytes.rs @@ -11,163 +11,127 @@ // Contributors: // ZettaScale Zenoh Team, // +use std::collections::HashMap; -use std::{borrow::Cow, collections::HashMap, io::Cursor}; - -use unwrap_infallible::UnwrapInfallible; use zenoh::bytes::ZBytes; fn main() { - // Numeric: u8, u16, u32, u128, usize, i8, i16, i32, i128, isize, f32, f64 - let input = 1234_u32; - let payload = ZBytes::from(input); - let output: u32 = payload.deserialize().unwrap(); - assert_eq!(input, output); - // Corresponding encoding to be used in operations like `.put()`, `.reply()`, etc. - // let encoding = Encoding::ZENOH_UINT32; - - // String - let input = String::from("test"); - let payload = ZBytes::from(&input); - let output: String = payload.deserialize().unwrap(); - assert_eq!(input, output); - // Corresponding encoding to be used in operations like `.put()`, `.reply()`, etc. - // let encoding = Encoding::ZENOH_STRING; - - // Cow - // See [`zenoh::bytes::ZBytes`] documentation for zero-copy behaviour. - let input = Cow::from("test"); - let payload = ZBytes::from(&input); - let output: Cow = payload.deserialize().unwrap(); - assert_eq!(input, output); - // Corresponding encoding to be used in operations like `.put()`, `.reply()`, etc. - // let encoding = Encoding::ZENOH_STRING; - - // Vec: The deserialization should be infallible - let input: Vec = vec![1, 2, 3, 4]; - let payload = ZBytes::from(&input); - let output: Vec = payload.deserialize().unwrap(); - assert_eq!(input, output); - // Deserialization of Vec is infallible. See https://docs.rs/unwrap-infallible/latest/unwrap_infallible/. - let output: Vec = payload.deserialize().unwrap_infallible(); - assert_eq!(input, output); - // Since the deserialization of `Vec` is infallible, then `ZBytes` can be infallibly converted into a `Vec`. - let output: Vec = payload.into(); - assert_eq!(input, output); + // Raw bytes + let input = b"raw bytes".as_slice(); + // raw bytes are copied into ZBytes, or moved in case of Vec + let payload_copy = ZBytes::from(input); + let payload_move = ZBytes::from(input.to_vec()); + assert_eq!(payload_copy, payload_move); + // retrieving raw bytes from ZBytes is infallible + let output = payload_move.to_bytes(); + assert_eq!(input, &*output); // Corresponding encoding to be used in operations like `.put()`, `.reply()`, etc. // let encoding = Encoding::ZENOH_BYTES; - // Cow<[u8]> - // See [`zenoh::bytes::ZBytes`] documentation for zero-copy behaviour. - let input = Cow::from(vec![1, 2, 3, 4]); - let payload = ZBytes::from(&input); - let output: Cow<[u8]> = payload.deserialize().unwrap(); - assert_eq!(input, output); - // Deserialization of `Cow<[u8]>` is infallible. See https://docs.rs/unwrap-infallible/latest/unwrap_infallible/. - let output: Cow<[u8]> = payload.deserialize().unwrap_infallible(); - assert_eq!(input, output); - // Since the deserialization of `Cow<[u8]>` is infallible, then `ZBytes` can be infallibly converted into a `Cow<[u8]>`. - let output: Vec = payload.into(); + // Raw utf8 bytes, i.e. string + let input = "raw bytes"; + // string is copied into ZBytes, or moved in case of String + let payload_copy = ZBytes::from(input); + let payload_move = ZBytes::from(input.to_string()); + assert_eq!(payload_copy, payload_move); + // retrieving utf8 string from ZBytes can fail if the bytes are not utf8 + let output = payload_move.try_to_string().unwrap(); assert_eq!(input, output); // Corresponding encoding to be used in operations like `.put()`, `.reply()`, etc. - // let encoding = Encoding::ZENOH_BYTES; - - // Writer & Reader - // serialization - let mut bytes = ZBytes::empty(); - let mut writer = bytes.writer(); - let i1 = 1234_u32; - let i2 = String::from("test"); - let i3 = vec![1, 2, 3, 4]; - writer.serialize(i1); - writer.serialize(&i2); - writer.serialize(&i3); - // deserialization - let mut reader = bytes.reader(); - let o1: u32 = reader.deserialize().unwrap(); - let o2: String = reader.deserialize().unwrap(); - let o3: Vec = reader.deserialize().unwrap(); - assert_eq!(i1, o1); - assert_eq!(i2, o2); - assert_eq!(i3, o3); - - // Tuple - let input = (1234_u32, String::from("test")); - let payload = ZBytes::serialize(input.clone()); - let output: (u32, String) = payload.deserialize().unwrap(); - assert_eq!(input, output); - - // Iterator - let input: [i32; 4] = [1, 2, 3, 4]; - let payload = ZBytes::from_iter(input.iter()); - for (idx, value) in payload.iter::().enumerate() { - assert_eq!(input[idx], value.unwrap()); - } - - // Iterator RAW - let input: [i32; 4] = [1, 2, 3, 4]; - let payload = ZBytes::from_iter(input.iter()); - for slice in payload.slices() { - println!("{:02x?}", slice); - } - - // HashMap - let mut input: HashMap = HashMap::new(); - input.insert(0, String::from("abc")); - input.insert(1, String::from("def")); - let payload = ZBytes::from(input.clone()); - let output = payload.deserialize::>().unwrap(); - assert_eq!(input, output); + // let encoding = Encoding::ZENOH_STRING; // JSON - let data = r#" - { + let input = serde_json::json!({ "name": "John Doe", "age": 43, "phones": [ "+44 1234567", "+44 2345678" ] - }"#; - let input: serde_json::Value = serde_json::from_str(data).unwrap(); - let payload = ZBytes::try_serialize(input.clone()).unwrap(); - let output: serde_json::Value = payload.deserialize().unwrap(); + }); + let payload = ZBytes::from(serde_json::to_vec(&input).unwrap()); + let output: serde_json::Value = serde_json::from_slice(&payload.to_bytes()).unwrap(); assert_eq!(input, output); // Corresponding encoding to be used in operations like `.put()`, `.reply()`, etc. // let encoding = Encoding::APPLICATION_JSON; - // YAML - let data = r#" - name: "John Doe" - age: 43 - phones: - - "+44 1234567" - - "+44 2345678" - "#; - let input: serde_yaml::Value = serde_yaml::from_str(data).unwrap(); - let payload = ZBytes::try_serialize(input.clone()).unwrap(); - let output: serde_yaml::Value = payload.deserialize().unwrap(); - assert_eq!(input, output); - // Corresponding encoding to be used in operations like `.put()`, `.reply()`, etc. - // let encoding = Encoding::APPLICATION_YAML; - - // Protobuf - use prost::Message; - #[derive(Message, Eq, PartialEq)] - struct EntityInfo { - #[prost(uint32)] - id: u32, - #[prost(string)] - name: String, + // Protobuf (see example.proto) + mod example { + include!(concat!(env!("OUT_DIR"), "/example.rs")); } - let input = EntityInfo { + use prost::Message; + let input = example::Entity { id: 1234, name: String::from("John Doe"), }; let payload = ZBytes::from(input.encode_to_vec()); - let output = - EntityInfo::decode(Cursor::new(payload.deserialize::>().unwrap())).unwrap(); + let output = example::Entity::decode(&*payload.to_bytes()).unwrap(); assert_eq!(input, output); // Corresponding encoding to be used in operations like `.put()`, `.reply()`, etc. // let encoding = Encoding::APPLICATION_PROTOBUF; + + // zenoh-ext serialization + { + use zenoh_ext::{z_deserialize, z_serialize, VarInt}; + + // Numeric types: u8, u16, u32, u128, i8, i16, i32, i128, f32, f64 + let input = 1234_u32; + let payload = z_serialize(&input); + let output: u32 = z_deserialize(&payload).unwrap(); + assert_eq!(input, output); + + // Varint LEB128 + let input = VarInt(42usize); + let payload = z_serialize(&input); + let output: VarInt = z_deserialize(&payload).unwrap(); + assert_eq!(input, output); + + // Vec + let input = vec![0.0f32, 1.5, 42.0]; + let payload = z_serialize(&input); + let output: Vec = z_deserialize(&payload).unwrap(); + assert_eq!(input, output); + + // HashMap + let mut input: HashMap = HashMap::new(); + input.insert(0, String::from("abc")); + input.insert(1, String::from("def")); + let payload = z_serialize(&input); + let output: HashMap = z_deserialize(&payload).unwrap(); + assert_eq!(input, output); + + // Tuple + let input = (0.42f64, "string".to_string()); + let payload = z_serialize(&input); + let output: (f64, String) = z_deserialize(&payload).unwrap(); + assert_eq!(input, output); + + // Array (handled as variable-length sequence, not as tuple) + let input = [0.0f32, 1.5, 42.0]; + let payload = z_serialize(&input); + let output: [f32; 3] = z_deserialize(&payload).unwrap(); + assert_eq!(input, output); + // can also be deserialized as a vec + let output: Vec = z_deserialize(&payload).unwrap(); + assert_eq!(input.as_slice(), output); + + // Look at Serialize/Deserialize documentation for the exhaustive + // list of provided implementations + } + + // Writer/reader + use std::io::{Read, Write}; + let input1 = &[0u8, 1]; + let input2 = ZBytes::from([2, 3]); + let mut writer = ZBytes::writer(); + writer.write_all(&[0u8, 1]).unwrap(); + writer.append(input2.clone()); + let zbytes = writer.finish(); + assert_eq!(*zbytes.to_bytes(), [0u8, 1, 2, 3]); + let mut reader = zbytes.reader(); + let mut buf = [0; 2]; + reader.read_exact(&mut buf).unwrap(); + assert_eq!(buf, *input1); + reader.read_exact(&mut buf).unwrap(); + assert_eq!(buf, *input2.to_bytes()); } diff --git a/examples/examples/z_bytes_shm.rs b/examples/examples/z_bytes_shm.rs index 1db1680be7..e7ec89fa8e 100644 --- a/examples/examples/z_bytes_shm.rs +++ b/examples/examples/z_bytes_shm.rs @@ -13,10 +13,7 @@ // use zenoh::{ bytes::ZBytes, - shm::{ - zshm, zshmmut, PosixShmProviderBackend, ShmProviderBuilder, ZShm, ZShmMut, - POSIX_PROTOCOL_ID, - }, + shm::{zshmmut, PosixShmProviderBackend, ShmProviderBuilder, ZShm, ZShmMut, POSIX_PROTOCOL_ID}, Wait, }; @@ -62,7 +59,7 @@ fn main() { // branch to illustrate immutable access to SHM data { // deserialize ZBytes as an immutably borrowed zshm (ZBytes -> &zshm) - let borrowed_shm_buf: &zshm = payload.deserialize().unwrap(); + let borrowed_shm_buf = payload.as_shm().unwrap(); // immutable API let _data: &[u8] = borrowed_shm_buf; @@ -82,7 +79,7 @@ fn main() { // branch to illustrate mutable access to SHM data { // deserialize ZBytes as mutably borrowed zshm (ZBytes -> &mut zshm) - let borrowed_shm_buf: &mut zshm = payload.deserialize_mut().unwrap(); + let borrowed_shm_buf = payload.as_shm_mut().unwrap(); // immutable API let _data: &[u8] = borrowed_shm_buf; diff --git a/examples/examples/z_get.rs b/examples/examples/z_get.rs index 7966d5938a..864f870099 100644 --- a/examples/examples/z_get.rs +++ b/examples/examples/z_get.rs @@ -49,8 +49,8 @@ async fn main() { // Refer to z_bytes.rs to see how to deserialize different types of message let payload = sample .payload() - .deserialize::() - .unwrap_or_else(|e| format!("{}", e)); + .try_to_string() + .unwrap_or_else(|e| e.to_string().into()); println!( ">> Received ('{}': '{}')", sample.key_expr().as_str(), @@ -60,8 +60,8 @@ async fn main() { Err(err) => { let payload = err .payload() - .deserialize::() - .unwrap_or_else(|e| format!("{}", e)); + .try_to_string() + .unwrap_or_else(|e| e.to_string().into()); println!(">> Received (ERROR: '{}')", payload); } } diff --git a/examples/examples/z_get_liveliness.rs b/examples/examples/z_get_liveliness.rs index b0c4006e13..6ee00822f2 100644 --- a/examples/examples/z_get_liveliness.rs +++ b/examples/examples/z_get_liveliness.rs @@ -40,8 +40,8 @@ async fn main() { Err(err) => { let payload = err .payload() - .deserialize::() - .unwrap_or_else(|e| format!("{}", e)); + .try_to_string() + .unwrap_or_else(|e| e.to_string().into()); println!(">> Received (ERROR: '{}')", payload); } } diff --git a/examples/examples/z_get_shm.rs b/examples/examples/z_get_shm.rs index 5c4a4f17fe..8633d51581 100644 --- a/examples/examples/z_get_shm.rs +++ b/examples/examples/z_get_shm.rs @@ -17,8 +17,7 @@ use clap::Parser; use zenoh::{ query::{QueryTarget, Selector}, shm::{ - zshm, BlockOn, GarbageCollect, PosixShmProviderBackend, ShmProviderBuilder, - POSIX_PROTOCOL_ID, + BlockOn, GarbageCollect, PosixShmProviderBackend, ShmProviderBuilder, POSIX_PROTOCOL_ID, }, Config, Wait, }; @@ -78,16 +77,16 @@ async fn main() { match reply.result() { Ok(sample) => { print!(">> Received ('{}': ", sample.key_expr().as_str()); - match sample.payload().deserialize::<&zshm>() { - Ok(payload) => println!("'{}')", String::from_utf8_lossy(payload),), - Err(e) => println!("'Not a ShmBufInner: {:?}')", e), + match sample.payload().as_shm() { + Some(payload) => println!("'{}')", String::from_utf8_lossy(payload)), + None => println!("'Not a ShmBufInner')"), } } Err(err) => { let payload = err .payload() - .deserialize::() - .unwrap_or_else(|e| format!("{}", e)); + .try_to_string() + .unwrap_or_else(|e| e.to_string().into()); println!(">> Received (ERROR: '{}')", payload); } } diff --git a/examples/examples/z_pub.rs b/examples/examples/z_pub.rs index 4472aa9f6a..25d6eacdee 100644 --- a/examples/examples/z_pub.rs +++ b/examples/examples/z_pub.rs @@ -39,7 +39,7 @@ async fn main() { publisher .put(buf) .encoding(Encoding::TEXT_PLAIN) // Optionally set the encoding metadata - .attachment(&attachment) // Optionally add an attachment + .attachment(attachment.clone()) // Optionally add an attachment .await .unwrap(); } diff --git a/examples/examples/z_pull.rs b/examples/examples/z_pull.rs index c677b545b8..d24935af9e 100644 --- a/examples/examples/z_pull.rs +++ b/examples/examples/z_pull.rs @@ -43,8 +43,8 @@ async fn main() { Ok(sample) => { let payload = sample .payload() - .deserialize::() - .unwrap_or_else(|e| format!("{}", e)); + .try_to_string() + .unwrap_or_else(|e| e.to_string().into()); println!( ">> [Subscriber] Pulled {} ('{}': '{}')... performing a computation of {:#?}", sample.kind(), @@ -67,8 +67,8 @@ async fn main() { // Ok(Some(sample)) => { // let payload = sample // .payload() - // .deserialize::() - // .unwrap_or_else(|e| format!("{}", e)); + // .try_to_string() + // .unwrap_or_else(|e| e.to_string().into()); // println!( // ">> [Subscriber] Pulled {} ('{}': '{}')", // sample.kind(), diff --git a/examples/examples/z_put_float.rs b/examples/examples/z_put_float.rs index df17470911..176e626586 100644 --- a/examples/examples/z_put_float.rs +++ b/examples/examples/z_put_float.rs @@ -14,6 +14,7 @@ use clap::Parser; use zenoh::{key_expr::KeyExpr, Config}; use zenoh_examples::CommonArgs; +use zenoh_ext::z_serialize; #[tokio::main] async fn main() { @@ -26,7 +27,8 @@ async fn main() { let session = zenoh::open(config).await.unwrap(); println!("Putting Float ('{key_expr}': '{payload}')..."); - session.put(&key_expr, payload).await.unwrap(); + // you must have imported `zenoh_ext::ZBytesExt` to use `ZBytes::serialize` + session.put(&key_expr, z_serialize(&payload)).await.unwrap(); session.close().await.unwrap(); } diff --git a/examples/examples/z_queryable.rs b/examples/examples/z_queryable.rs index b3b5ca9bf0..c7d81d81f1 100644 --- a/examples/examples/z_queryable.rs +++ b/examples/examples/z_queryable.rs @@ -43,8 +43,8 @@ async fn main() { Some(query_payload) => { // Refer to z_bytes.rs to see how to deserialize different types of message let deserialized_payload = query_payload - .deserialize::() - .unwrap_or_else(|e| format!("{}", e)); + .try_to_string() + .unwrap_or_else(|e| e.to_string().into()); println!( ">> [Queryable ] Received Query '{}' with payload '{}'", query.selector(), diff --git a/examples/examples/z_queryable_shm.rs b/examples/examples/z_queryable_shm.rs index db00ddb118..7153e999e6 100644 --- a/examples/examples/z_queryable_shm.rs +++ b/examples/examples/z_queryable_shm.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + // // Copyright (c) 2023 ZettaScale Technology // @@ -16,8 +18,7 @@ use zenoh::{ bytes::ZBytes, key_expr::KeyExpr, shm::{ - zshm, BlockOn, GarbageCollect, PosixShmProviderBackend, ShmProviderBuilder, - POSIX_PROTOCOL_ID, + BlockOn, GarbageCollect, PosixShmProviderBackend, ShmProviderBuilder, POSIX_PROTOCOL_ID, }, Config, Wait, }; @@ -126,7 +127,7 @@ fn parse_args() -> (Config, KeyExpr<'static>, String, bool) { (args.common.into(), args.key, args.payload, args.complete) } -fn handle_bytes(bytes: &ZBytes) -> (&str, String) { +fn handle_bytes(bytes: &ZBytes) -> (&str, Cow) { // Determine buffer type for indication purpose let bytes_type = { // if Zenoh is built without SHM support, the only buffer type it can receive is RAW @@ -144,9 +145,9 @@ fn handle_bytes(bytes: &ZBytes) -> (&str, String) { // if Zenoh is built with SHM support and with SHM API we can detect the exact buffer type #[cfg(all(feature = "shared-memory", feature = "unstable"))] - match bytes.deserialize::<&zshm>() { - Ok(_) => "SHM", - Err(_) => "RAW", + match bytes.as_shm() { + Some(_) => "SHM", + None => "RAW", } }; @@ -157,8 +158,8 @@ fn handle_bytes(bytes: &ZBytes) -> (&str, String) { // // Refer to z_bytes.rs to see how to deserialize different types of message let bytes_string = bytes - .deserialize::() - .unwrap_or_else(|e| format!("{}", e)); + .try_to_string() + .unwrap_or_else(|e| e.to_string().into()); (bytes_type, bytes_string) } diff --git a/examples/examples/z_storage.rs b/examples/examples/z_storage.rs index 9f6f50b16f..c0560d573b 100644 --- a/examples/examples/z_storage.rs +++ b/examples/examples/z_storage.rs @@ -51,7 +51,7 @@ async fn main() { select!( sample = subscriber.recv_async() => { let sample = sample.unwrap(); - let payload = sample.payload().deserialize::().unwrap_or_else(|e| format!("{}", e)); + let payload = sample.payload().try_to_string().unwrap_or_else(|e| e.to_string().into()); println!(">> [Subscriber] Received {} ('{}': '{}')", sample.kind(), sample.key_expr().as_str(),payload); match sample.kind() { SampleKind::Delete => stored.remove(&sample.key_expr().to_string()), diff --git a/examples/examples/z_sub.rs b/examples/examples/z_sub.rs index 26fc768737..71eba72533 100644 --- a/examples/examples/z_sub.rs +++ b/examples/examples/z_sub.rs @@ -33,8 +33,8 @@ async fn main() { // Refer to z_bytes.rs to see how to deserialize different types of message let payload = sample .payload() - .deserialize::() - .unwrap_or_else(|e| format!("{}", e)); + .try_to_string() + .unwrap_or_else(|e| e.to_string().into()); print!( ">> [Subscriber] Received {} ('{}': '{}')", @@ -43,9 +43,7 @@ async fn main() { payload ); if let Some(att) = sample.attachment() { - let att = att - .deserialize::() - .unwrap_or_else(|e| format!("{}", e)); + let att = att.try_to_string().unwrap_or_else(|e| e.to_string().into()); print!(" ({})", att); } println!(); diff --git a/examples/examples/z_sub_shm.rs b/examples/examples/z_sub_shm.rs index a4660485dc..f49b0628bf 100644 --- a/examples/examples/z_sub_shm.rs +++ b/examples/examples/z_sub_shm.rs @@ -11,9 +11,9 @@ // Contributors: // ZettaScale Zenoh Team, // +use std::borrow::Cow; + use clap::Parser; -#[cfg(all(feature = "shared-memory", feature = "unstable"))] -use zenoh::shm::zshm; use zenoh::{bytes::ZBytes, config::Config, key_expr::KeyExpr}; use zenoh_examples::CommonArgs; @@ -54,13 +54,11 @@ async fn main() { // // Try to get a mutable reference to the SHM buffer. If this subscriber is the only subscriber // // holding a reference to the SHM buffer, then it will be able to get a mutable reference to it. // // With the mutable reference at hand, it's possible to mutate in place the SHM buffer content. - // - // use zenoh::shm::zshmmut; // while let Ok(mut sample) = subscriber.recv_async().await { // let kind = sample.kind(); // let key_expr = sample.key_expr().to_string(); - // match sample.payload_mut().deserialize_mut::<&mut zshmmut>() { + // match sample.payload_mut().as_shm_mut() { // Ok(payload) => println!( // ">> [Subscriber] Received {} ('{}': '{:02x?}')", // kind, key_expr, payload @@ -86,7 +84,7 @@ fn parse_args() -> (Config, KeyExpr<'static>) { (args.common.into(), args.key) } -fn handle_bytes(bytes: &ZBytes) -> (&str, String) { +fn handle_bytes(bytes: &ZBytes) -> (&str, Cow) { // Determine buffer type for indication purpose let bytes_type = { // if Zenoh is built without SHM support, the only buffer type it can receive is RAW @@ -104,9 +102,9 @@ fn handle_bytes(bytes: &ZBytes) -> (&str, String) { // if Zenoh is built with SHM support and with SHM API we can detect the exact buffer type #[cfg(all(feature = "shared-memory", feature = "unstable"))] - match bytes.deserialize::<&zshm>() { - Ok(_) => "SHM", - Err(_) => "RAW", + match bytes.as_shm() { + Some(_) => "SHM", + None => "RAW", } }; @@ -117,8 +115,8 @@ fn handle_bytes(bytes: &ZBytes) -> (&str, String) { // // Refer to z_bytes.rs to see how to deserialize different types of message let bytes_string = bytes - .deserialize::() - .unwrap_or_else(|e| format!("{}", e)); + .try_to_string() + .unwrap_or_else(|e| e.to_string().into()); (bytes_type, bytes_string) } diff --git a/plugins/zenoh-plugin-example/src/lib.rs b/plugins/zenoh-plugin-example/src/lib.rs index 9fc53c1c80..f930c4312b 100644 --- a/plugins/zenoh-plugin-example/src/lib.rs +++ b/plugins/zenoh-plugin-example/src/lib.rs @@ -14,7 +14,6 @@ #![recursion_limit = "256"] use std::{ - borrow::Cow, collections::HashMap, convert::TryFrom, future::Future, @@ -196,7 +195,7 @@ async fn run(runtime: Runtime, selector: KeyExpr<'_>, flag: Arc) { // on sample received by the Subscriber sample = sub.recv_async() => { let sample = sample.unwrap(); - let payload = sample.payload().deserialize::>().unwrap_or_else(|e| Cow::from(e.to_string())); + let payload = sample.payload().try_to_string().unwrap_or_else(|e| e.to_string().into()); info!("Received data ('{}': '{}')", sample.key_expr(), payload); stored.insert(sample.key_expr().to_string(), sample); }, diff --git a/plugins/zenoh-plugin-rest/build.rs b/plugins/zenoh-plugin-rest/build.rs index c3964a1fa1..383c7765cf 100644 --- a/plugins/zenoh-plugin-rest/build.rs +++ b/plugins/zenoh-plugin-rest/build.rs @@ -31,7 +31,7 @@ fn main() { let config = std::fs::read_to_string("config.json5").unwrap(); let config: serde_json::Value = serde_json::from_str(&config).unwrap(); if let Err(es) = validator.validate(&config) { - let es = es.map(|e| format!("{}", e)).collect::>().join("\n"); + let es = es.map(|e| e.to_string()).collect::>().join("\n"); panic!("config.json5 schema validation error: {}", es); }; } diff --git a/plugins/zenoh-plugin-rest/src/lib.rs b/plugins/zenoh-plugin-rest/src/lib.rs index fad758c536..6fe5512af4 100644 --- a/plugins/zenoh-plugin-rest/src/lib.rs +++ b/plugins/zenoh-plugin-rest/src/lib.rs @@ -120,33 +120,30 @@ pub fn base64_encode(data: &[u8]) -> String { } fn payload_to_json(payload: &ZBytes, encoding: &Encoding) -> serde_json::Value { - match payload.is_empty() { - // If the value is empty return a JSON null - true => serde_json::Value::Null, - // if it is not check the encoding - false => { - match encoding { - // If it is a JSON try to deserialize as json, if it fails fallback to base64 - &Encoding::APPLICATION_JSON | &Encoding::TEXT_JSON | &Encoding::TEXT_JSON5 => { - payload - .deserialize::() - .unwrap_or_else(|e| { - tracing::warn!("Encoding is JSON but data is not JSON, converting to base64, Error: {e:?}"); - serde_json::Value::String(base64_encode(&Cow::from(payload))) - }) - } - &Encoding::TEXT_PLAIN | &Encoding::ZENOH_STRING => serde_json::Value::String( - payload - .deserialize::() - .unwrap_or_else(|e| { - tracing::warn!("Encoding is String but data is not String, converting to base64, Error: {e:?}"); - base64_encode(&Cow::from(payload)) - }), - ), - // otherwise convert to JSON string - _ => serde_json::Value::String(base64_encode(&Cow::from(payload))), - } + if payload.is_empty() { + return serde_json::Value::Null; + } + match encoding { + // If it is a JSON try to deserialize as json, if it fails fallback to base64 + &Encoding::APPLICATION_JSON | &Encoding::TEXT_JSON | &Encoding::TEXT_JSON5 => { + let bytes = payload.to_bytes(); + serde_json::from_slice(&bytes).unwrap_or_else(|e| { + tracing::warn!( + "Encoding is JSON but data is not JSON, converting to base64, Error: {e:?}" + ); + serde_json::Value::String(base64_encode(&bytes)) + }) } + &Encoding::TEXT_PLAIN | &Encoding::ZENOH_STRING => serde_json::Value::String( + String::from_utf8(payload.to_bytes().into_owned()).unwrap_or_else(|e| { + tracing::warn!( + "Encoding is String but data is not String, converting to base64, Error: {e:?}" + ); + base64_encode(e.as_bytes()) + }), + ), + // otherwise convert to JSON string + _ => serde_json::Value::String(base64_encode(&payload.to_bytes())), } } @@ -189,10 +186,7 @@ fn sample_to_html(sample: &Sample) -> String { format!( "
{}
\n
{}
\n", sample.key_expr().as_str(), - sample - .payload() - .deserialize::>() - .unwrap_or_default() + sample.payload().try_to_string().unwrap_or_default() ) } @@ -202,7 +196,7 @@ fn result_to_html(sample: Result<&Sample, &ReplyError>) -> String { Err(err) => { format!( "
ERROR
\n
{}
\n", - err.payload().deserialize::>().unwrap_or_default() + err.payload().try_to_string().unwrap_or_default() ) } } @@ -228,18 +222,12 @@ async fn to_raw_response(results: flume::Receiver) -> Response { Ok(sample) => response( StatusCode::Ok, Cow::from(sample.encoding()).as_ref(), - &sample - .payload() - .deserialize::>() - .unwrap_or_default(), + &sample.payload().try_to_string().unwrap_or_default(), ), Err(value) => response( StatusCode::Ok, Cow::from(value.encoding()).as_ref(), - &value - .payload() - .deserialize::>() - .unwrap_or_default(), + &value.payload().try_to_string().unwrap_or_default(), ), }, Err(_) => response(StatusCode::Ok, "", ""), diff --git a/plugins/zenoh-plugin-storage-manager/build.rs b/plugins/zenoh-plugin-storage-manager/build.rs index c97b852362..baf246012d 100644 --- a/plugins/zenoh-plugin-storage-manager/build.rs +++ b/plugins/zenoh-plugin-storage-manager/build.rs @@ -27,7 +27,7 @@ fn main() { let config = std::fs::read_to_string("config.json5").unwrap(); let config: serde_json::Value = serde_json::from_str(&config).unwrap(); if let Err(es) = validator.validate(&config) { - let es = es.map(|e| format!("{}", e)).collect::>().join("\n"); + let es = es.map(|e| e.to_string()).collect::>().join("\n"); panic!("config.json5 schema validation error: {}", es); }; } diff --git a/plugins/zenoh-plugin-storage-manager/src/replication/aligner.rs b/plugins/zenoh-plugin-storage-manager/src/replication/aligner.rs index b957fc50f6..c4f49ee154 100644 --- a/plugins/zenoh-plugin-storage-manager/src/replication/aligner.rs +++ b/plugins/zenoh-plugin-storage-manager/src/replication/aligner.rs @@ -12,10 +12,7 @@ // ZettaScale Zenoh Team, // -use std::{ - borrow::Cow, - collections::{HashMap, HashSet}, -}; +use std::collections::{HashMap, HashSet}; use serde::{Deserialize, Serialize}; use tokio::task::JoinHandle; @@ -93,17 +90,16 @@ impl Replication { } }; - let alignment_query = - match bincode::deserialize::(&attachment.into::>()) { - Ok(alignment) => alignment, - Err(e) => { - tracing::error!( - "Failed to deserialize `attachment` of received Query into \ + let alignment_query = match bincode::deserialize::(&attachment.to_bytes()) { + Ok(alignment) => alignment, + Err(e) => { + tracing::error!( + "Failed to deserialize `attachment` of received Query into \ AlignmentQuery: {e:?}" - ); - return; - } - }; + ); + return; + } + }; match alignment_query { AlignmentQuery::Discovery => { @@ -430,17 +426,18 @@ impl Replication { tracing::debug!("Skipping reply without attachment"); continue; } - Some(attachment) => match bincode::deserialize::( - &attachment.into::>(), - ) { - Err(e) => { - tracing::error!( + Some(attachment) => { + match bincode::deserialize::(&attachment.to_bytes()) + { + Err(e) => { + tracing::error!( "Failed to deserialize attachment as AlignmentReply: {e:?}" ); - continue; + continue; + } + Ok(alignment_reply) => alignment_reply, } - Ok(alignment_reply) => alignment_reply, - }, + } }; replication @@ -766,7 +763,7 @@ async fn reply_to_query(query: &Query, reply: AlignmentReply, value: Option( - &sample.payload().into::>(), - ) { - Ok(other_digest) => other_digest, - Err(e) => { - tracing::warn!( - "Failed to deserialize Payload as Digest: {e:?}. Skipping." - ); - return; - } - }; + let other_digest = + match bincode::deserialize::(&sample.payload().to_bytes()) { + Ok(other_digest) => other_digest, + Err(e) => { + tracing::warn!( + "Failed to deserialize Payload as Digest: {e:?}. Skipping." + ); + return; + } + }; tracing::debug!("Replication digest received"); diff --git a/plugins/zenoh-plugin-storage-manager/src/storages_mgt/service.rs b/plugins/zenoh-plugin-storage-manager/src/storages_mgt/service.rs index e96320051f..8ae3d77634 100644 --- a/plugins/zenoh-plugin-storage-manager/src/storages_mgt/service.rs +++ b/plugins/zenoh-plugin-storage-manager/src/storages_mgt/service.rs @@ -263,23 +263,24 @@ impl StorageService { // there might be the case that the actual update was outdated due to a wild card // update, but not stored yet in the storage. get the relevant wild // card entry and use that value and timestamp to update the storage - let sample_to_store: Sample = if let Some(update) = - self.overriding_wild_update(&k, sample_timestamp).await - { - match update.kind { - SampleKind::Put => SampleBuilder::put(k.clone(), update.data.value.payload()) - .encoding(update.data.value.encoding().clone()) - .timestamp(update.data.timestamp) - .into(), - SampleKind::Delete => SampleBuilder::delete(k.clone()) - .timestamp(update.data.timestamp) - .into(), - } - } else { - SampleBuilder::from(sample.clone()) - .keyexpr(k.clone()) - .into() - }; + let sample_to_store: Sample = + if let Some(update) = self.overriding_wild_update(&k, sample_timestamp).await { + match update.kind { + SampleKind::Put => { + SampleBuilder::put(k.clone(), update.data.value.payload().clone()) + .encoding(update.data.value.encoding().clone()) + .timestamp(update.data.timestamp) + .into() + } + SampleKind::Delete => SampleBuilder::delete(k.clone()) + .timestamp(update.data.timestamp) + .into(), + } + } else { + SampleBuilder::from(sample.clone()) + .keyexpr(k.clone()) + .into() + }; // A Sample that is to be stored **must** have a Timestamp. In theory, the Sample // generated should have a Timestamp and, in theory, this check is @@ -328,7 +329,7 @@ impl StorageService { .put( stripped_key.clone(), Value::new( - sample_to_store.payload(), + sample_to_store.payload().clone(), sample_to_store.encoding().clone(), ), sample_to_store_timestamp, @@ -649,7 +650,7 @@ fn serialize_update(update: &Update) -> String { kind, data: StoredData { value, timestamp }, } = update; - let zbuf: ZBuf = value.payload().into(); + let zbuf: ZBuf = value.payload().clone().into(); let result = ( kind.to_string(), diff --git a/plugins/zenoh-plugin-storage-manager/tests/operations.rs b/plugins/zenoh-plugin-storage-manager/tests/operations.rs index c3ddf67d2e..e65cd92035 100644 --- a/plugins/zenoh-plugin-storage-manager/tests/operations.rs +++ b/plugins/zenoh-plugin-storage-manager/tests/operations.rs @@ -16,7 +16,7 @@ // 1. normal case, just some wild card puts and deletes on existing keys and ensure it works // 2. check for dealing with out of order updates -use std::{borrow::Cow, str::FromStr, thread::sleep}; +use std::{str::FromStr, thread::sleep}; use tokio::runtime::Runtime; use zenoh::{ @@ -107,7 +107,7 @@ async fn test_updates_in_order() { // expects exactly one sample let data = get_data(&session, "operation/test/a").await; assert_eq!(data.len(), 1); - assert_eq!(data[0].payload().deserialize::>().unwrap(), "1"); + assert_eq!(data[0].payload().try_to_string().unwrap(), "1"); put_data( &session, @@ -122,7 +122,7 @@ async fn test_updates_in_order() { // expects exactly one sample let data = get_data(&session, "operation/test/b").await; assert_eq!(data.len(), 1); - assert_eq!(data[0].payload().deserialize::>().unwrap(), "2"); + assert_eq!(data[0].payload().try_to_string().unwrap(), "2"); delete_data( &session, @@ -140,7 +140,7 @@ async fn test_updates_in_order() { // expects exactly one sample let data = get_data(&session, "operation/test/b").await; assert_eq!(data.len(), 1); - assert_eq!(data[0].payload().deserialize::>().unwrap(), "2"); + assert_eq!(data[0].payload().try_to_string().unwrap(), "2"); assert_eq!(data[0].key_expr().as_str(), "operation/test/b"); drop(storage); diff --git a/plugins/zenoh-plugin-storage-manager/tests/wildcard.rs b/plugins/zenoh-plugin-storage-manager/tests/wildcard.rs index b4c7ddd8f2..856a4adade 100644 --- a/plugins/zenoh-plugin-storage-manager/tests/wildcard.rs +++ b/plugins/zenoh-plugin-storage-manager/tests/wildcard.rs @@ -16,7 +16,7 @@ // 1. normal case, just some wild card puts and deletes on existing keys and ensure it works // 2. check for dealing with out of order updates -use std::{borrow::Cow, str::FromStr, thread::sleep}; +use std::{str::FromStr, thread::sleep}; // use std::collections::HashMap; use tokio::runtime::Runtime; @@ -120,7 +120,7 @@ async fn test_wild_card_in_order() { let data = get_data(&session, "wild/test/*").await; assert_eq!(data.len(), 1); assert_eq!(data[0].key_expr().as_str(), "wild/test/a"); - assert_eq!(data[0].payload().deserialize::>().unwrap(), "2"); + assert_eq!(data[0].payload().try_to_string().unwrap(), "2"); put_data( &session, @@ -137,20 +137,8 @@ async fn test_wild_card_in_order() { assert_eq!(data.len(), 2); assert!(["wild/test/a", "wild/test/b"].contains(&data[0].key_expr().as_str())); assert!(["wild/test/a", "wild/test/b"].contains(&data[1].key_expr().as_str())); - assert!(["2", "3"].contains( - &data[0] - .payload() - .deserialize::>() - .unwrap() - .as_ref() - )); - assert!(["2", "3"].contains( - &data[1] - .payload() - .deserialize::>() - .unwrap() - .as_ref() - )); + assert!(["2", "3"].contains(&data[0].payload().try_to_string().unwrap().as_ref())); + assert!(["2", "3"].contains(&data[1].payload().try_to_string().unwrap().as_ref())); put_data( &session, @@ -167,8 +155,8 @@ async fn test_wild_card_in_order() { assert_eq!(data.len(), 2); assert!(["wild/test/a", "wild/test/b"].contains(&data[0].key_expr().as_str())); assert!(["wild/test/a", "wild/test/b"].contains(&data[1].key_expr().as_str())); - assert_eq!(data[0].payload().deserialize::>().unwrap(), "4"); - assert_eq!(data[1].payload().deserialize::>().unwrap(), "4"); + assert_eq!(data[0].payload().try_to_string().unwrap(), "4"); + assert_eq!(data[1].payload().try_to_string().unwrap(), "4"); delete_data( &session, diff --git a/zenoh-ext/Cargo.toml b/zenoh-ext/Cargo.toml index 4b06a97264..d69db67f1c 100644 --- a/zenoh-ext/Cargo.toml +++ b/zenoh-ext/Cargo.toml @@ -33,11 +33,11 @@ shared-memory = ["zenoh/shared-memory"] [dependencies] tokio = { workspace = true, features = [ - "rt", - "sync", - "time", - "macros", - "io-std", + "rt", + "sync", + "time", + "macros", + "io-std", ] } bincode = { workspace = true } zenoh-util = { workspace = true } @@ -45,12 +45,14 @@ flume = { workspace = true } futures = { workspace = true } tracing = { workspace = true } serde = { workspace = true, features = ["default"] } +leb128 = { workspace = true } zenoh = { workspace = true, features = ["unstable", "internal"], default-features = false } zenoh-macros = { workspace = true } [dev-dependencies] zenoh = { workspace = true, features = ["unstable"], default-features = true } zenoh-config = { workspace = true } +rand = { workspace = true } [package.metadata.docs.rs] features = ["unstable"] diff --git a/zenoh-ext/examples/examples/z_query_sub.rs b/zenoh-ext/examples/examples/z_query_sub.rs index 0d01cb20c7..2e8c832670 100644 --- a/zenoh-ext/examples/examples/z_query_sub.rs +++ b/zenoh-ext/examples/examples/z_query_sub.rs @@ -51,8 +51,8 @@ async fn main() { while let Ok(sample) = subscriber.recv_async().await { let payload = sample .payload() - .deserialize::() - .unwrap_or_else(|e| format!("{}", e)); + .try_to_string() + .unwrap_or_else(|e| e.to_string().into()); println!( ">> [Subscriber] Received {} ('{}': '{}')", sample.kind(), diff --git a/zenoh-ext/src/lib.rs b/zenoh-ext/src/lib.rs index 659afa006d..8741571663 100644 --- a/zenoh-ext/src/lib.rs +++ b/zenoh-ext/src/lib.rs @@ -14,12 +14,18 @@ pub mod group; mod publication_cache; mod querying_subscriber; +mod serialization; mod session_ext; mod subscriber_ext; + pub use publication_cache::{PublicationCache, PublicationCacheBuilder}; pub use querying_subscriber::{ FetchingSubscriber, FetchingSubscriberBuilder, QueryingSubscriberBuilder, }; +pub use serialization::{ + z_deserialize, z_serialize, Deserialize, Serialize, VarInt, ZDeserializeError, ZDeserializer, + ZReadIter, ZSerializer, +}; pub use session_ext::SessionExt; pub use subscriber_ext::{SubscriberBuilderExt, SubscriberForward}; use zenoh::{internal::zerror, query::Reply, sample::Sample, Result as ZResult}; diff --git a/zenoh-ext/src/serialization.rs b/zenoh-ext/src/serialization.rs new file mode 100644 index 0000000000..b24d56c4e8 --- /dev/null +++ b/zenoh-ext/src/serialization.rs @@ -0,0 +1,720 @@ +use std::{ + borrow::Cow, + collections::{BTreeMap, BTreeSet, HashMap, HashSet}, + fmt, + hash::Hash, + io::{Read, Write}, + marker::PhantomData, + mem::MaybeUninit, + ops::{Deref, DerefMut}, + str::FromStr, +}; + +use zenoh::{ + bytes::{Encoding, ZBytes, ZBytesReader, ZBytesWriter}, + time::{Timestamp, TimestampId, NTP64}, +}; + +#[derive(Debug)] +pub struct ZDeserializeError; +impl fmt::Display for ZDeserializeError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "deserialization error") + } +} +impl std::error::Error for ZDeserializeError {} + +fn default_serialize_n(slice: &[T], serializer: &mut ZSerializer) { + for t in slice { + t.serialize(serializer) + } +} + +pub trait Serialize { + fn serialize(&self, serializer: &mut ZSerializer); + #[doc(hidden)] + fn serialize_n(slice: &[Self], serializer: &mut ZSerializer) + where + Self: Sized, + { + default_serialize_n(slice, serializer); + } +} +impl Serialize for &T { + fn serialize(&self, serializer: &mut ZSerializer) { + T::serialize(*self, serializer) + } +} + +fn default_deserialize_n( + in_place: &mut [T], + deserializer: &mut ZDeserializer, +) -> Result<(), ZDeserializeError> { + for t in in_place { + *t = T::deserialize(deserializer)?; + } + Ok(()) +} + +fn default_deserialize_n_uninit<'a, T: Deserialize>( + in_place: &'a mut [MaybeUninit], + deserializer: &mut ZDeserializer, +) -> Result<&'a mut [T], ZDeserializeError> { + for t in in_place.iter_mut() { + t.write(T::deserialize(deserializer)?); + } + // SAFETY: all members of the slices have been initialized + Ok(unsafe { &mut *(in_place as *mut [MaybeUninit] as *mut [T]) }) +} + +pub trait Deserialize: Sized { + fn deserialize(deserializer: &mut ZDeserializer) -> Result; + #[doc(hidden)] + fn deserialize_n( + in_place: &mut [Self], + deserializer: &mut ZDeserializer, + ) -> Result<(), ZDeserializeError> { + default_deserialize_n(in_place, deserializer) + } + #[doc(hidden)] + fn deserialize_n_uninit<'a>( + in_place: &'a mut [MaybeUninit], + deserializer: &mut ZDeserializer, + ) -> Result<&'a mut [Self], ZDeserializeError> { + default_deserialize_n_uninit(in_place, deserializer) + } +} + +pub fn z_serialize(t: &T) -> ZBytes { + let mut serializer = ZSerializer::new(); + serializer.serialize(t); + serializer.finish() +} + +pub fn z_deserialize(zbytes: &ZBytes) -> Result { + let mut deserializer = ZDeserializer::new(zbytes); + let t = T::deserialize(&mut deserializer)?; + if !deserializer.done() { + return Err(ZDeserializeError); + } + Ok(t) +} + +#[derive(Debug)] +pub struct ZSerializer(ZBytesWriter); + +impl ZSerializer { + pub fn new() -> Self { + Self(ZBytes::writer()) + } + + pub fn serialize(&mut self, t: T) { + t.serialize(self) + } + + pub fn serialize_iter>(&mut self, iter: I) + where + I::IntoIter: ExactSizeIterator, + { + let iter = iter.into_iter(); + self.serialize(VarInt(iter.len())); + for t in iter { + t.serialize(self); + } + } + + pub fn finish(self) -> ZBytes { + self.0.finish() + } +} + +impl Default for ZSerializer { + fn default() -> Self { + Self::new() + } +} + +impl From for ZBytes { + fn from(value: ZSerializer) -> Self { + value.finish() + } +} + +#[derive(Debug)] +pub struct ZDeserializer<'a>(ZBytesReader<'a>); + +impl<'a> ZDeserializer<'a> { + pub fn new(zbytes: &'a ZBytes) -> Self { + Self(zbytes.reader()) + } + + pub fn done(&self) -> bool { + self.0.is_empty() + } + + pub fn deserialize(&mut self) -> Result { + T::deserialize(self) + } + + pub fn deserialize_iter<'b, T: Deserialize>( + &'b mut self, + ) -> Result, ZDeserializeError> { + let len = >::deserialize(self)?.0; + Ok(ZReadIter { + deserializer: self, + len, + _phantom: PhantomData, + }) + } + + pub fn deserialize_n( + &mut self, + in_place: &mut [T], + ) -> Result<(), ZDeserializeError> { + T::deserialize_n(in_place, self) + } + + pub fn deserialize_n_uninit<'b, T: Deserialize>( + &mut self, + in_place: &'b mut [MaybeUninit], + ) -> Result<&'b mut [T], ZDeserializeError> { + T::deserialize_n_uninit(in_place, self) + } +} + +pub struct ZReadIter<'a, 'b, T: Deserialize> { + deserializer: &'b mut ZDeserializer<'a>, + len: usize, + _phantom: PhantomData, +} + +impl Iterator for ZReadIter<'_, '_, T> { + type Item = Result; + fn next(&mut self) -> Option { + if self.len == 0 { + return None; + } + self.len -= 1; + Some(T::deserialize(self.deserializer)) + } + + fn size_hint(&self) -> (usize, Option) { + (self.len, Some(self.len)) + } +} + +impl ExactSizeIterator for ZReadIter<'_, '_, T> {} + +impl Drop for ZReadIter<'_, '_, T> { + fn drop(&mut self) { + self.by_ref().for_each(drop); + } +} + +impl Serialize for ZBytes { + fn serialize(&self, serializer: &mut ZSerializer) { + serializer.serialize(VarInt(self.len())); + serializer.0.append(self.clone()); + } +} + +macro_rules! impl_num { + ($($ty:ty),* $(,)?) => {$( + impl Serialize for $ty { + fn serialize(&self, serializer: &mut ZSerializer) { + serializer.0.write_all(&(*self).to_le_bytes()).unwrap(); + } + fn serialize_n(slice: &[Self], serializer: &mut ZSerializer) where Self: Sized { + if cfg!(target_endian = "little") || std::mem::size_of::() == 1 { + // SAFETY: transmuting numeric types to their little endian bytes is safe + serializer.0.write_all(unsafe { slice.align_to().1 }).unwrap(); + } else { + default_serialize_n(slice, serializer) + } + } + } + impl Deserialize for $ty { + fn deserialize(deserializer: &mut ZDeserializer) -> Result { + let mut buf = [0; { std::mem::size_of::() }]; + deserializer.0.read_exact(&mut buf).or(Err(ZDeserializeError))?; + Ok(<$ty>::from_le_bytes(buf)) + } + fn deserialize_n(in_place: &mut [Self], deserializer: &mut ZDeserializer) -> Result<(), ZDeserializeError> { + let size = std::mem::size_of::(); + if cfg!(target_endian = "little") || size == 1 { + // SAFETY: transmuting numeric types to their little endian bytes is safe + let buf = unsafe {in_place.align_to_mut().1}; + deserializer.0.read_exact(buf).or(Err(ZDeserializeError))?; + Ok(()) + } else { + default_deserialize_n(in_place, deserializer) + } + } + fn deserialize_n_uninit<'a>(in_place: &'a mut [MaybeUninit], deserializer: &mut ZDeserializer) -> Result<&'a mut [Self], ZDeserializeError> { + if cfg!(target_endian = "little") || std::mem::size_of::() == 1 { + // need to initialize the slice because of std::io::Read interface + in_place.fill(MaybeUninit::new(Self::default())); + // SAFETY: all members of the slices have been initialized + let initialized = unsafe { &mut *(in_place as *mut [MaybeUninit] as *mut [Self]) }; + Self::deserialize_n(initialized, deserializer)?; + Ok(initialized) + } else { + default_deserialize_n_uninit(in_place, deserializer) + } + } + } + )*}; +} +impl_num!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, f32, f64); + +impl Serialize for bool { + fn serialize(&self, serializer: &mut ZSerializer) { + (*self as u8).serialize(serializer); + } +} +impl Deserialize for bool { + fn deserialize(deserializer: &mut ZDeserializer) -> Result { + match u8::deserialize(deserializer)? { + 0 => Ok(false), + 1 => Ok(true), + _ => Err(ZDeserializeError), + } + } +} + +fn serialize_slice(slice: &[T], serializer: &mut ZSerializer) { + serializer.serialize(VarInt(slice.len())); + T::serialize_n(slice, serializer); +} + +fn deserialize_slice( + deserializer: &mut ZDeserializer, +) -> Result, ZDeserializeError> { + let len = >::deserialize(deserializer)?.0; + let mut vec = Vec::with_capacity(len); + let slice = T::deserialize_n_uninit(&mut vec.spare_capacity_mut()[..len], deserializer)?; + let (slice_ptr, slice_len) = (slice.as_ptr(), slice.len()); + assert_eq!((slice_ptr, slice_len), (vec.as_ptr(), len)); + // SAFETY: assertion checks the returned slice is vector's one, and it's returned initialized + unsafe { vec.set_len(len) }; + Ok(vec.into_boxed_slice()) +} + +impl Serialize for [T] { + fn serialize(&self, serializer: &mut ZSerializer) { + serialize_slice(self, serializer); + } +} +impl Serialize for [T; N] { + fn serialize(&self, serializer: &mut ZSerializer) { + serialize_slice(self.as_slice(), serializer); + } +} +impl<'a, T: Serialize + 'a> Serialize for Cow<'a, [T]> +where + [T]: ToOwned, +{ + fn serialize(&self, serializer: &mut ZSerializer) { + serialize_slice(self, serializer); + } +} +impl Serialize for Box<[T]> { + fn serialize(&self, serializer: &mut ZSerializer) { + serialize_slice(self, serializer); + } +} +impl Deserialize for Box<[T]> { + fn deserialize(deserializer: &mut ZDeserializer) -> Result { + deserialize_slice(deserializer) + } +} +impl Serialize for Vec { + fn serialize(&self, serializer: &mut ZSerializer) { + serialize_slice(self, serializer) + } +} +impl Deserialize for [T; N] { + fn deserialize(deserializer: &mut ZDeserializer) -> Result { + if >::deserialize(deserializer)?.0 != N { + return Err(ZDeserializeError); + } + let mut array = std::array::from_fn(|_| MaybeUninit::uninit()); + let slice = T::deserialize_n_uninit(&mut array, deserializer)?; + let (slice_ptr, slice_len) = (slice.as_ptr(), slice.len()); + assert_eq!((slice_ptr, slice_len), (array.as_ptr().cast::(), N)); + // SAFETY: assertion checks the returned slice is array's one, and it's returned initialized + Ok(array.map(|t| unsafe { t.assume_init() })) + } +} +impl Deserialize for Vec { + fn deserialize(deserializer: &mut ZDeserializer) -> Result { + Ok(deserialize_slice(deserializer)?.into_vec()) + } +} +impl Serialize for HashSet { + fn serialize(&self, serializer: &mut ZSerializer) { + serializer.serialize_iter(self); + } +} +impl Deserialize for HashSet { + fn deserialize(deserializer: &mut ZDeserializer) -> Result { + deserializer.deserialize_iter()?.collect() + } +} +impl Serialize for BTreeSet { + fn serialize(&self, serializer: &mut ZSerializer) { + serializer.serialize_iter(self); + } +} +impl Deserialize for BTreeSet { + fn deserialize(deserializer: &mut ZDeserializer) -> Result { + deserializer.deserialize_iter()?.collect() + } +} +impl Serialize for HashMap { + fn serialize(&self, serializer: &mut ZSerializer) { + serializer.serialize_iter(self); + } +} +impl Deserialize for HashMap { + fn deserialize(deserializer: &mut ZDeserializer) -> Result { + deserializer.deserialize_iter()?.collect() + } +} +impl Serialize for BTreeMap { + fn serialize(&self, serializer: &mut ZSerializer) { + serializer.serialize_iter(self); + } +} +impl Deserialize for BTreeMap { + fn deserialize(deserializer: &mut ZDeserializer) -> Result { + deserializer.deserialize_iter()?.collect() + } +} +impl Serialize for str { + fn serialize(&self, serializer: &mut ZSerializer) { + self.as_bytes().serialize(serializer); + } +} +impl Serialize for Cow<'_, str> { + fn serialize(&self, serializer: &mut ZSerializer) { + self.as_bytes().serialize(serializer); + } +} +impl Serialize for String { + fn serialize(&self, serializer: &mut ZSerializer) { + self.as_bytes().serialize(serializer); + } +} +impl Deserialize for String { + fn deserialize(deserializer: &mut ZDeserializer) -> Result { + String::from_utf8(Deserialize::deserialize(deserializer)?).or(Err(ZDeserializeError)) + } +} + +macro_rules! impl_tuple { + ($($ty:ident/$i:tt),* $(,)?) => { + impl_tuple!(@;$($ty/$i),*); + }; + (@$($ty:ident/$i:tt),*; $next:ident/$next_i:tt $(, $remain:ident/$remain_i:tt)*) => { + impl_tuple!(@@$($ty/$i),*); + impl_tuple!(@$($ty/$i,)* $next/$next_i; $($remain/$remain_i),*); + }; + (@$($ty:ident/$i:tt),*;) => { + impl_tuple!(@@$($ty/$i),*); + }; + (@@$($ty:ident/$i:tt),* $(,)?) => { + #[allow(unused)] + impl<$($ty: Serialize),*> Serialize for ($($ty,)*) { + fn serialize(&self, serializer: &mut ZSerializer) { + $(self.$i.serialize(serializer);)* + } + } + #[allow(unused)] + impl<$($ty: Deserialize),*> Deserialize for ($($ty,)*) { + fn deserialize(deserializer: &mut ZDeserializer) -> Result { + Ok(($($ty::deserialize(deserializer)?,)*)) + } + } + }; +} +impl_tuple!( + T0 / 0, + T1 / 1, + T2 / 2, + T3 / 3, + T4 / 4, + T5 / 5, + T6 / 6, + T7 / 7, + T8 / 8, + T9 / 9, + T10 / 10, + T11 / 11, + T12 / 12, + T13 / 13, + T14 / 14, + T15 / 15, +); + +#[repr(transparent)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct VarInt(pub T); +impl VarInt { + pub fn from_ref(int: &T) -> &Self { + // SAFETY: `VarInt` is `repr(transparent)` + unsafe { &*(int as *const T as *const Self) } + } + pub fn from_mut(int: &mut T) -> &mut Self { + // SAFETY: `VarInt` is `repr(transparent)` + unsafe { &mut *(int as *mut T as *mut Self) } + } + pub fn slice_from_ref(slice: &[T]) -> &[Self] { + // SAFETY: `VarInt` is `repr(transparent)` + unsafe { &*(slice as *const [T] as *const [Self]) } + } + pub fn slice_from_mut(slice: &mut [T]) -> &mut [Self] { + // SAFETY: `VarInt` is `repr(transparent)` + unsafe { &mut *(slice as *mut [T] as *mut [Self]) } + } + pub fn slice_into_ref(slice: &[Self]) -> &[T] { + // SAFETY: `VarInt` is `repr(transparent)` + unsafe { &*(slice as *const [Self] as *const [T]) } + } + pub fn slice_into_mut(slice: &mut [Self]) -> &mut [T] { + // SAFETY: `VarInt` is `repr(transparent)` + unsafe { &mut *(slice as *mut [Self] as *mut [T]) } + } +} +impl Deref for VarInt { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for VarInt { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl From for VarInt { + fn from(value: T) -> Self { + Self(value) + } +} +impl AsRef for VarInt { + fn as_ref(&self) -> &T { + self + } +} +impl AsMut for VarInt { + fn as_mut(&mut self) -> &mut T { + self + } +} + +macro_rules! impl_varint { + ($($u:ty: $i:ty),* $(,)?) => {$( + impl From> for $u { + fn from(value: VarInt<$u>) -> Self { + value.0 + } + } + impl From> for $i { + fn from(value: VarInt<$i>) -> Self { + value.0 + } + } + impl Serialize for VarInt<$u> { + fn serialize(&self, serializer: &mut ZSerializer) { + leb128::write::unsigned(&mut serializer.0, self.0 as u64).unwrap(); + } + } + impl Serialize for VarInt<$i> { + fn serialize(&self, serializer: &mut ZSerializer) { + let zigzag = (self.0 >> (std::mem::size_of::<$i>() * 8 - 1)) as $u ^ (self.0 << 1) as $u; + VarInt(zigzag).serialize(serializer); + } + } + impl Deserialize for VarInt<$u> { + fn deserialize(deserializer: &mut ZDeserializer) -> Result { + let n = leb128::read::unsigned(&mut deserializer.0).or(Err(ZDeserializeError))?; + Ok(VarInt(<$u>::try_from(n).or(Err(ZDeserializeError))?)) + } + } + impl Deserialize for VarInt<$i> { + fn deserialize(deserializer: &mut ZDeserializer) -> Result { + let zigzag = >::deserialize(deserializer)?.0; + Ok(VarInt((zigzag >> 1) as $i ^ -((zigzag & 1) as $i))) + } + } + )*}; +} +impl_varint!(u8: i8, u16: i16, u32: i32, u64: i64, usize: isize); + +// +// Serialization/deseialization for zenoh types +// + +impl Serialize for NTP64 { + fn serialize(&self, serializer: &mut ZSerializer) { + let time = self.as_u64(); + time.serialize(serializer); + } +} + +impl Deserialize for NTP64 { + fn deserialize(deserializer: &mut ZDeserializer) -> Result { + let time = u64::deserialize(deserializer)?; + Ok(NTP64(time)) + } +} + +impl Serialize for TimestampId { + fn serialize(&self, serializer: &mut ZSerializer) { + self.to_le_bytes().serialize(serializer); + } +} + +impl Deserialize for TimestampId { + fn deserialize(deserializer: &mut ZDeserializer) -> Result { + let id = Vec::::deserialize(deserializer)?; + let id = id.as_slice().try_into().map_err(|_| ZDeserializeError)?; + Ok(id) + } +} + +impl Serialize for Timestamp { + fn serialize(&self, serializer: &mut ZSerializer) { + self.get_time().serialize(serializer); + self.get_id().serialize(serializer); + } +} + +impl Deserialize for Timestamp { + fn deserialize(deserializer: &mut ZDeserializer) -> Result { + let time = NTP64::deserialize(deserializer)?; + let id = TimestampId::deserialize(deserializer)?; + Ok(Timestamp::new(time, id)) + } +} + +impl Serialize for Encoding { + fn serialize(&self, serializer: &mut ZSerializer) { + self.to_string().serialize(serializer); + } +} + +impl Deserialize for zenoh::bytes::Encoding { + fn deserialize(deserializer: &mut ZDeserializer) -> Result { + let encoding = String::deserialize(deserializer)?; + Encoding::from_str(&encoding).map_err(|_| ZDeserializeError) + } +} + +#[cfg(test)] +mod tests { + use std::{collections::HashMap, ops::Range, str::FromStr}; + + use rand::{thread_rng, Rng}; + use zenoh::{ + bytes::Encoding, + time::{Timestamp, TimestampId}, + }; + + use crate::{z_deserialize, z_serialize, VarInt}; + + macro_rules! serialize_deserialize { + ($ty:ty, $expr:expr) => { + let expr: &$ty = &$expr; + let payload = z_serialize(expr); + let output = z_deserialize::<$ty>(&payload).unwrap(); + assert_eq!(*expr, output); + }; + } + + const RANDOM_TESTS: Range = 0..1_000; + + #[test] + fn numeric_serialization() { + macro_rules! test_int { + ($($ty:ty),* $(,)?) => {$( + serialize_deserialize!($ty, <$ty>::MIN); + serialize_deserialize!($ty, <$ty>::MAX); + let mut rng = thread_rng(); + for _ in RANDOM_TESTS { + serialize_deserialize!($ty, rng.gen::<$ty>()); + } + )*}; + } + test_int!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, f32, f64); + } + + #[test] + fn varint_serialization() { + macro_rules! test_varint { + ($($ty:ty),* $(,)?) => {$( + serialize_deserialize!(VarInt<$ty>, VarInt(<$ty>::MIN)); + serialize_deserialize!(VarInt<$ty>, VarInt(<$ty>::MAX)); + let mut rng = thread_rng(); + for _ in RANDOM_TESTS { + serialize_deserialize!(VarInt<$ty>, VarInt(rng.gen::<$ty>())); + } + )*}; + } + test_varint!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize); + } + + #[test] + fn primitive_slice_serialization() { + let vec = vec![42.0f64, 0.15]; + serialize_deserialize!(Vec, vec); + let payload = z_serialize(vec.as_slice()); + assert_eq!(vec, z_deserialize::>(&payload).unwrap()) + } + + #[test] + fn slice_serialization() { + let vec = vec!["abc".to_string(), "def".to_string()]; + serialize_deserialize!(Vec, vec); + let payload = z_serialize(vec.as_slice()); + assert_eq!(vec, z_deserialize::>(&payload).unwrap()) + } + + #[test] + fn string_serialization() { + let s = "serialization".to_string(); + serialize_deserialize!(String, s); + let payload = z_serialize(s.as_str()); + assert_eq!(s, z_deserialize::(&payload).unwrap()) + } + + #[test] + fn tuple_serialization() { + serialize_deserialize!( + (VarInt, f32, String), + (VarInt(42), 42.0f32, "42".to_string()) + ); + } + + #[test] + fn hashmap_serialization() { + let mut map = HashMap::new(); + map.insert("hello".to_string(), "world".to_string()); + serialize_deserialize!(HashMap, map); + } + + #[test] + fn timestamp_serialization() { + use std::time::{SystemTime, UNIX_EPOCH}; + let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().into(); + serialize_deserialize!(Timestamp, Timestamp::new(now, TimestampId::rand())); + } + + #[test] + fn encoding_serialization() { + serialize_deserialize!(Encoding, Encoding::TEXT_JSON); + serialize_deserialize!(Encoding, Encoding::from_str("text/plain;foobar").unwrap()); + } +} diff --git a/zenoh-ext/src/session_ext.rs b/zenoh-ext/src/session_ext.rs index facf0ebed1..a1dcb11f94 100644 --- a/zenoh-ext/src/session_ext.rs +++ b/zenoh-ext/src/session_ext.rs @@ -17,7 +17,7 @@ use zenoh::{key_expr::KeyExpr, session::Session, Error}; use super::PublicationCacheBuilder; /// Some extensions to the [`zenoh::Session`](zenoh::Session) -pub trait SessionExt<'s, 'a> { +pub trait SessionExt { // REVIEW(fuzzypixelz): this doc test is the only one to use the programmatic configuration API.. /// Examples: /// ``` @@ -36,8 +36,8 @@ pub trait SessionExt<'s, 'a> { /// }).await; /// # } /// ``` - fn declare_publication_cache<'b, 'c, TryIntoKeyExpr>( - &'s self, + fn declare_publication_cache<'a, 'b, 'c, TryIntoKeyExpr>( + &'a self, pub_key_expr: TryIntoKeyExpr, ) -> PublicationCacheBuilder<'a, 'b, 'c> where @@ -45,8 +45,8 @@ pub trait SessionExt<'s, 'a> { >>::Error: Into; } -impl<'a> SessionExt<'a, 'a> for Session { - fn declare_publication_cache<'b, 'c, TryIntoKeyExpr>( +impl SessionExt for Session { + fn declare_publication_cache<'a, 'b, 'c, TryIntoKeyExpr>( &'a self, pub_key_expr: TryIntoKeyExpr, ) -> PublicationCacheBuilder<'a, 'b, 'c> diff --git a/zenoh/Cargo.toml b/zenoh/Cargo.toml index d7c5f447b9..b1bc3e5fb8 100644 --- a/zenoh/Cargo.toml +++ b/zenoh/Cargo.toml @@ -32,25 +32,25 @@ maintenance = { status = "actively-developed" } auth_pubkey = ["zenoh-transport/auth_pubkey"] auth_usrpwd = ["zenoh-transport/auth_usrpwd"] default = [ - "auth_pubkey", - "auth_usrpwd", - "transport_multilink", - "transport_compression", - "transport_quic", - "transport_tcp", - "transport_tls", - "transport_udp", - "transport_unixsock-stream", - "transport_ws", + "auth_pubkey", + "auth_usrpwd", + "transport_multilink", + "transport_compression", + "transport_quic", + "transport_tcp", + "transport_tls", + "transport_udp", + "transport_unixsock-stream", + "transport_ws", ] internal = ["zenoh-keyexpr/internal", "zenoh-config/internal"] plugins = [] runtime_plugins = ["plugins"] shared-memory = [ - "zenoh-shm", - "zenoh-protocol/shared-memory", - "zenoh-transport/shared-memory", - "zenoh-buffers/shared-memory", + "zenoh-shm", + "zenoh-protocol/shared-memory", + "zenoh-transport/shared-memory", + "zenoh-buffers/shared-memory", ] stats = ["zenoh-transport/stats", "zenoh-protocol/stats"] transport_multilink = ["zenoh-transport/transport_multilink"] @@ -91,7 +91,6 @@ serde-pickle = { workspace = true } serde_yaml = { workspace = true } socket2 = { workspace = true } uhlc = { workspace = true, features = ["default"] } -unwrap-infallible = { workspace = true } vec_map = { workspace = true } zenoh-buffers = { workspace = true, features = ["std"] } zenoh-codec = { workspace = true } diff --git a/zenoh/src/api/admin.rs b/zenoh/src/api/admin.rs index f7bcc06419..b6071f97f8 100644 --- a/zenoh/src/api/admin.rs +++ b/zenoh/src/api/admin.rs @@ -27,7 +27,6 @@ use zenoh_transport::{ }; use super::{ - bytes::ZBytes, encoding::Encoding, key_expr::KeyExpr, queryable::Query, @@ -68,13 +67,11 @@ pub(crate) fn on_admin_query(session: &WeakSession, query: Query) { if let Ok(zid) = keyexpr::new(&zid) { let key_expr = *KE_PREFIX / own_zid / *KE_SESSION / *KE_TRANSPORT_UNICAST / zid; if query.key_expr().intersects(&key_expr) { - if let Ok(value) = serde_json::value::to_value(peer.clone()) { - match ZBytes::try_from(value) { - Ok(zbuf) => { - let _ = query.reply(key_expr, zbuf).wait(); - } - Err(e) => tracing::debug!("Admin query error: {}", e), + match serde_json::to_vec(&peer) { + Ok(bytes) => { + let _ = query.reply(key_expr, bytes).wait(); } + Err(e) => tracing::debug!("Admin query error: {}", e), } } @@ -90,13 +87,11 @@ pub(crate) fn on_admin_query(session: &WeakSession, query: Query) { / *KE_LINK / lid; if query.key_expr().intersects(&key_expr) { - if let Ok(value) = serde_json::value::to_value(link) { - match ZBytes::try_from(value) { - Ok(zbuf) => { - let _ = query.reply(key_expr, zbuf).wait(); - } - Err(e) => tracing::debug!("Admin query error: {}", e), + match serde_json::to_vec(&link) { + Ok(bytes) => { + let _ = query.reply(key_expr, bytes).wait(); } + Err(e) => tracing::debug!("Admin query error: {}", e), } } } diff --git a/zenoh/src/api/builders/publisher.rs b/zenoh/src/api/builders/publisher.rs index 9db37fa36a..a8ccc5022f 100644 --- a/zenoh/src/api/builders/publisher.rs +++ b/zenoh/src/api/builders/publisher.rs @@ -228,7 +228,7 @@ impl Wait for PublicationBuilder, PublicationBuilderDel fn wait(self) -> ::To { self.publisher.session.0.resolve_put( &self.publisher.key_expr?, - ZBytes::empty(), + ZBytes::new(), SampleKind::Delete, Encoding::ZENOH_BYTES, self.publisher.congestion_control, @@ -459,7 +459,7 @@ impl Wait for PublicationBuilder<&Publisher<'_>, PublicationBuilderDelete> { fn wait(self) -> ::To { self.publisher.session.resolve_put( &self.publisher.key_expr, - ZBytes::empty(), + ZBytes::new(), SampleKind::Delete, Encoding::ZENOH_BYTES, self.publisher.congestion_control, diff --git a/zenoh/src/api/builders/sample.rs b/zenoh/src/api/builders/sample.rs index cb7ada9e4f..ebec624626 100644 --- a/zenoh/src/api/builders/sample.rs +++ b/zenoh/src/api/builders/sample.rs @@ -115,7 +115,7 @@ impl SampleBuilder { Self { sample: Sample { key_expr: key_expr.into(), - payload: ZBytes::empty(), + payload: ZBytes::new(), kind: SampleKind::Delete, encoding: Encoding::default(), timestamp: None, diff --git a/zenoh/src/api/bytes.rs b/zenoh/src/api/bytes.rs index cd7196c233..519faa3409 100644 --- a/zenoh/src/api/bytes.rs +++ b/zenoh/src/api/bytes.rs @@ -13,34 +13,14 @@ // //! ZBytes primitives. -use std::{ - borrow::Cow, collections::HashMap, convert::Infallible, fmt::Debug, marker::PhantomData, - str::Utf8Error, string::FromUtf8Error, sync::Arc, -}; +use std::{borrow::Cow, fmt::Debug, mem, str::Utf8Error}; -use uhlc::Timestamp; -use unwrap_infallible::UnwrapInfallible; use zenoh_buffers::{ buffer::{Buffer, SplitBuffer}, reader::{HasReader, Reader}, - writer::HasWriter, - ZBuf, ZBufReader, ZBufWriter, ZSlice, ZSliceBuffer, -}; -use zenoh_codec::{RCodec, WCodec, Zenoh080}; -use zenoh_protocol::{ - core::{Encoding as EncodingProto, Parameters}, - zenoh::ext::AttachmentType, + ZBuf, ZBufReader, ZSlice, ZSliceBuffer, }; -#[cfg(feature = "shared-memory")] -use zenoh_shm::{ - api::buffer::{ - zshm::{zshm, ZShm}, - zshmmut::{zshmmut, ZShmMut}, - }, - ShmBufInner, -}; - -use super::{encoding::Encoding, value::Value}; +use zenoh_protocol::zenoh::ext::AttachmentType; /// Wrapper type for API ergonomicity to allow any type `T` to be converted into `Option` where `T` implements `Into`. #[repr(transparent)] @@ -86,167 +66,38 @@ impl From for Option { } } -/// Trait to encode a type `T` into a [`ZBytes`]. -pub trait Serialize { - type Output; - - /// The implementer should take care of serializing the type `T` into a [`ZBytes`]. - /// If [`Encoding`] metadata is important in a given system, the caller should take care - /// of setting the proprer [`Encoding`] value when calling functions like [`crate::Session::put`]. - fn serialize(self, t: T) -> Self::Output; -} - -pub trait Deserialize { - type Input<'a>; - type Error; - - /// The implementer should take care of deserializing a [`ZBytes`] into the type `T`. - /// If [`Encoding`] metadata is required in a given system, the caller should take care of checking the proprer - /// [`Encoding`] value (e.g. [`crate::sample::Sample::encoding`]) to select the right type `T` to deserialize into. - fn deserialize(self, t: Self::Input<'_>) -> Result; -} - /// ZBytes contains the serialized bytes of user data. /// -/// `ZBytes` provides convenient methods to the user for serialization/deserialization based on the default Zenoh serializer [`ZSerde`]. -/// -/// **NOTE 1:** Zenoh semantic and protocol take care of sending and receiving bytes without restricting the actual data types. -/// -/// **NOTE 2:** [`ZSerde`] is the default serializer/deserializer provided for convenience to the users to deal with primitives data types via -/// a simple out-of-the-box encoding. That is, [`ZSerde`] is provided as a facilitator for simple use cases that need to send/receive data -/// over Zenoh, and doing so potentially to/from different programming languages. Make simple use cases simple and provide freedom for more -/// advanced use cases. -/// -/// **NOTE 3:** [`ZSerde`] is **NOT** by any means the only serializer/deserializer users can use nor a limitation to the types supported by Zenoh. -/// [`ZSerde`] does not have the ambition nor the plan to be a full alternative of more complete seriliazation libraries like *serde*, *protobuf*, -/// *bincode*, *flatbuffers*, etc. Users are free and encouraged to use any serializer/deserializer of their choice that better suits their use case. -/// -/// `ZBytes` can be used to serialize a single type: -/// ```rust -/// use zenoh::bytes::ZBytes; -/// -/// let start = String::from("abc"); -/// let bytes = ZBytes::serialize(start.clone()); -/// let end: String = bytes.deserialize().unwrap(); -/// assert_eq!(start, end); -/// ``` -/// -/// A tuple of serializable types: -/// ```rust -/// use zenoh::bytes::ZBytes; -/// -/// let start = (String::from("abc"), String::from("def")); -/// let bytes = ZBytes::serialize(start.clone()); -/// let end: (String, String) = bytes.deserialize().unwrap(); -/// assert_eq!(start, end); -/// -/// let start = (1_u8, 3.14_f32, String::from("abc")); -/// let bytes = ZBytes::serialize(start.clone()); -/// let end: (u8, f32, String) = bytes.deserialize().unwrap(); -/// assert_eq!(start, end); -/// `````` -/// -/// An iterator of serializable types: -/// ```rust -/// use zenoh::bytes::ZBytes; -/// -/// let start = vec![String::from("abc"), String::from("def")]; -/// let bytes = ZBytes::from_iter(start.iter()); -/// -/// let mut i = 0; -/// let mut iter = bytes.iter::(); -/// while let Some(Ok(t)) = iter.next() { -/// assert_eq!(start[i], t); -/// i += 1; -/// } -/// ``` -/// -/// A writer and a reader of serializable types: +/// `ZBytes` can be converted from/to raw bytes: /// ```rust +/// use std::borrow::Cow; /// use zenoh::bytes::ZBytes; /// -/// #[derive(Debug, PartialEq)] -/// struct Foo { -/// one: usize, -/// two: String, -/// three: Vec, -/// } -/// -/// let start = Foo { -/// one: 42, -/// two: String::from("Forty-Two"), -/// three: vec![42u8; 42], -/// }; -/// -/// let mut bytes = ZBytes::empty(); -/// let mut writer = bytes.writer(); -/// -/// writer.serialize(&start.one); -/// writer.serialize(&start.two); -/// writer.serialize(&start.three); -/// -/// let mut reader = bytes.reader(); -/// let end = Foo { -/// one: reader.deserialize().unwrap(), -/// two: reader.deserialize().unwrap(), -/// three: reader.deserialize().unwrap(), -/// }; -/// assert_eq!(start, end); +/// let buf = b"some raw bytes"; +/// let payload = ZBytes::from(buf); +/// assert_eq!(payload.to_bytes(), buf.as_slice()); /// ``` /// -/// **NOTE 4:** `ZBytes` may store data in non-contiguous regions of memory. +/// `ZBytes` may store data in non-contiguous regions of memory. /// The typical case for `ZBytes` to store data in different memory regions is when data is received fragmented from the network. -/// The user then can decided to use [`ZBytes::deserialize`], [`ZBytes::reader`], [`ZBytes::into`], or [`ZBytes::slices`] depending -/// on their needs. /// -/// To directly access raw data as contiguous slice it is preferred to convert `ZBytes` into a [`std::borrow::Cow<[u8]>`]. +/// To directly access raw data as contiguous slice it is preferred to convert `ZBytes` into a [`std::borrow::Cow<[u8]>`] using [`to_bytes`](Self::to_bytes). /// If `ZBytes` contains all the data in a single memory location, this is guaranteed to be zero-copy. This is the common case for small messages. /// If `ZBytes` contains data scattered in different memory regions, this operation will do an allocation and a copy. This is the common case for large messages. /// -/// Example: -/// ```rust -/// use std::borrow::Cow; -/// use zenoh::bytes::ZBytes; -/// -/// let buf: Vec = vec![0, 1, 2, 3]; -/// let bytes = ZBytes::from(buf.clone()); -/// let deser: Cow<[u8]> = bytes.into(); -/// assert_eq!(buf.as_slice(), deser.as_ref()); -/// ``` -/// -/// It is also possible to iterate over the raw data that may be scattered on different memory regions. +/// It is also possible to iterate over the raw data that may be scattered on different memory regions using [`slices`](Self::slices). /// Please note that no guarantee is provided on the internal memory layout of [`ZBytes`] nor on how many slices a given [`ZBytes`] will be composed of. /// The only provided guarantee is on the bytes order that is preserved. -/// -/// Example: -/// ```rust -/// use zenoh::bytes::ZBytes; -/// -/// let buf: Vec = vec![0, 1, 2, 3]; -/// let bytes = ZBytes::from(buf.clone()); -/// for slice in bytes.slices() { -/// println!("{:02x?}", slice); -/// } -/// ``` #[repr(transparent)] #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct ZBytes(ZBuf); impl ZBytes { /// Create an empty ZBytes. - pub const fn empty() -> Self { + pub const fn new() -> Self { Self(ZBuf::empty()) } - /// Create a [`ZBytes`] from any type `T` that implements [`Into`]. - #[doc(hidden)] - pub fn new(t: T) -> Self - where - T: Into, - { - Self(t.into()) - } - /// Returns whether the [`ZBytes`] is empty or not. pub fn is_empty(&self) -> bool { self.0.is_empty() @@ -257,6 +108,17 @@ impl ZBytes { self.0.len() } + pub fn to_bytes(&self) -> Cow<[u8]> { + self.0.contiguous() + } + + pub fn try_to_string(&self) -> Result, Utf8Error> { + Ok(match self.to_bytes() { + Cow::Borrowed(s) => std::str::from_utf8(s)?.into(), + Cow::Owned(v) => String::from_utf8(v).map_err(|err| err.utf8_error())?.into(), + }) + } + /// Get a [`ZBytesReader`] implementing [`std::io::Read`] trait. /// /// See [`ZBytesWriter`] on how to chain the deserialization of different types from a single [`ZBytes`]. @@ -271,37 +133,16 @@ impl ZBytes { { let mut buf: Vec = vec![]; reader.read_to_end(&mut buf)?; - Ok(ZBytes::new(buf)) + Ok(buf.into()) } /// Get a [`ZBytesWriter`] implementing [`std::io::Write`] trait. /// /// See [`ZBytesWriter`] on how to chain the serialization of different types into a single [`ZBytes`]. - pub fn writer(&mut self) -> ZBytesWriter<'_> { - ZBytesWriter(self.0.writer()) - } - - /// Get a [`ZBytesIterator`] that deserializes a sequence of `T`. - /// - /// Example: - /// ```rust - /// use zenoh::bytes::ZBytes; - /// - /// let list: Vec = vec![1.1, 2.2, 3.3]; - /// let mut zbs = ZBytes::from_iter(list.iter()); - /// - /// for (index, elem) in zbs.iter::().enumerate() { - /// assert_eq!(list[index], elem.unwrap()); - /// } - /// ``` - pub fn iter(&self) -> ZBytesIterator<'_, T> - where - for<'b> ZSerde: Deserialize = &'b ZBytes>, - for<'b> >::Error: Debug, - { - ZBytesIterator { - reader: self.0.reader(), - _t: PhantomData::, + pub fn writer() -> ZBytesWriter { + ZBytesWriter { + zbuf: ZBuf::empty(), + vec: Vec::new(), } } @@ -312,28 +153,26 @@ impl ZBytes { /// Please note that no guarantee is provided on the internal memory layout of [`ZBytes`]. /// The only provided guarantee is on the bytes order that is preserved. /// - /// Please note that [`ZBytes::iter`] will perform deserialization while iterating while [`ZBytes::slices`] will not. - /// /// ```rust /// use std::io::Write; /// use zenoh::bytes::ZBytes; /// /// let buf1: Vec = vec![1, 2, 3]; /// let buf2: Vec = vec![4, 5, 6, 7, 8]; - /// let mut zbs = ZBytes::empty(); - /// let mut writer = zbs.writer(); + /// let mut writer = ZBytes::writer(); /// writer.write(&buf1); /// writer.write(&buf2); + /// let zbytes = writer.finish(); /// /// // Access the raw content - /// for slice in zbs.slices() { + /// for slice in zbytes.slices() { /// println!("{:02x?}", slice); /// } /// /// // Concatenate input in a single vector /// let buf: Vec = buf1.into_iter().chain(buf2.into_iter()).collect(); /// // Concatenate raw bytes in a single vector - /// let out: Vec = zbs.slices().fold(Vec::new(), |mut b, x| { b.extend_from_slice(x); b }); + /// let out: Vec = zbytes.slices().fold(Vec::new(), |mut b, x| { b.extend_from_slice(x); b }); /// // The previous line is the equivalent of /// // let out: Vec = zbs.into(); /// assert_eq!(buf, out); @@ -348,178 +187,43 @@ impl ZBytes { /// let buf1: Vec = vec![1, 2, 3]; /// let buf2: Vec = vec![4, 5, 6, 7, 8]; /// - /// let mut zbs = ZBytes::empty(); - /// let mut writer = zbs.writer(); + /// let mut writer = ZBytes::writer(); /// writer.append(ZBytes::from(buf1.clone())); /// writer.append(ZBytes::from(buf2.clone())); + /// let zbytes = writer.finish(); /// - /// let mut iter = zbs.slices(); + /// let mut iter = zbytes.slices(); /// assert_eq!(buf1.as_slice(), iter.next().unwrap()); /// assert_eq!(buf2.as_slice(), iter.next().unwrap()); /// ``` pub fn slices(&self) -> ZBytesSliceIterator<'_> { ZBytesSliceIterator(self.0.slices()) } +} +#[cfg(all(feature = "unstable", feature = "shared-memory"))] +const _: () = { + use zenoh_shm::{api::buffer::zshm::zshm, ShmBufInner}; + impl ZBytes { + pub fn as_shm(&self) -> Option<&zshm> { + let mut zslices = self.0.zslices(); + let buf = zslices.next()?.downcast_ref::(); + buf.map(Into::into).filter(|_| zslices.next().is_none()) + } - /// Serialize an object of type `T` as a [`ZBytes`] using the [`ZSerde`]. - /// - /// ```rust - /// use zenoh::bytes::ZBytes; - /// - /// let start = String::from("abc"); - /// let bytes = ZBytes::serialize(start.clone()); - /// let end: String = bytes.deserialize().unwrap(); - /// assert_eq!(start, end); - /// ``` - pub fn serialize(t: T) -> Self - where - ZSerde: Serialize, - { - ZSerde.serialize(t) - } - - /// Try serializing an object of type `T` as a [`ZBytes`] using the [`ZSerde`]. - /// - /// ```rust - /// use serde_json::Value; - /// use zenoh::bytes::ZBytes; - /// - /// // Some JSON input data as a &str. Maybe this comes from the user. - /// let data = r#" - /// { - /// "name": "John Doe", - /// "age": 43, - /// "phones": [ - /// "+44 1234567", - /// "+44 2345678" - /// ] - /// }"#; - /// - /// // Parse the string of data into serde_json::Value. - /// let start: Value = serde_json::from_str(data).unwrap(); - /// // The serialization of a serde_json::Value is faillable (see `serde_json::to_string()`). - /// let bytes = ZBytes::try_serialize(start.clone()).unwrap(); - /// let end: Value = bytes.deserialize().unwrap(); - /// assert_eq!(start, end); - /// ``` - pub fn try_serialize(t: T) -> Result - where - ZSerde: Serialize>, - { - ZSerde.serialize(t) - } - - /// Deserialize an object of type `T` using [`ZSerde`]. - /// - /// See [`ZBytes::serialize`] and [`ZBytes::try_serialize`] for the examples. - /// - /// See [`ZBytes::into`] for infallible conversion, e.g. to get raw bytes. - pub fn deserialize<'a, T>(&'a self) -> Result>::Error> - where - ZSerde: Deserialize = &'a ZBytes>, - >::Error: Debug, - { - ZSerde.deserialize(self) - } - - /// Deserialize an object of type `T` using [`ZSerde`]. - pub fn deserialize_mut<'a, T>(&'a mut self) -> Result>::Error> - where - ZSerde: Deserialize = &'a mut ZBytes>, - >::Error: Debug, - { - ZSerde.deserialize(self) - } - - /// Infallibly deserialize an object of type `T` using [`ZSerde`]. - /// - /// To directly access raw data as contiguous slice it is preferred to convert `ZBytes` into a [`std::borrow::Cow<[u8]>`](`std::borrow::Cow`). - /// If [`ZBytes`] contains all the data in a single memory location, then it is guaranteed to be zero-copy. This is the common case for small messages. - /// If [`ZBytes`] contains data scattered in different memory regions, this operation will do an allocation and a copy. This is the common case for large messages. - /// - /// ```rust - /// use std::borrow::Cow; - /// use zenoh::bytes::ZBytes; - /// - /// let buf: Vec = vec![0, 1, 2, 3]; - /// let bytes = ZBytes::from(buf.clone()); - /// let deser: Cow<[u8]> = bytes.into(); - /// assert_eq!(buf.as_slice(), deser.as_ref()); - /// ``` - /// - /// An alternative is to convert `ZBytes` into a [`std::vec::Vec`]. - /// Converting to [`std::vec::Vec`] will always allocate and make a copy. - /// - /// ```rust - /// use std::borrow::Cow; - /// use zenoh::bytes::ZBytes; - /// - /// let buf: Vec = vec![0, 1, 2, 3]; - /// let bytes = ZBytes::from(buf.clone()); - /// let deser: Vec = bytes.into(); - /// assert_eq!(buf.as_slice(), deser.as_slice()); - /// ``` - /// - /// If you want to be sure that no copy is performed at all, then you should use [`ZBytes::slices`]. - /// Please note that in this case data may not be contiguous in memory and it is the responsibility of the user to properly parse the raw slices. - pub fn into<'a, T>(&'a self) -> T - where - ZSerde: Deserialize = &'a ZBytes, Error = Infallible>, - >::Error: Debug, - { - ZSerde.deserialize(self).unwrap_infallible() - } - - /// Infallibly deserialize an object of type `T` using the [`ZSerde`]. - pub fn into_mut<'a, T>(&'a mut self) -> T - where - ZSerde: Deserialize = &'a mut ZBytes, Error = Infallible>, - >::Error: Debug, - { - ZSerde.deserialize(self).unwrap_infallible() + pub fn as_shm_mut(&mut self) -> Option<&mut zshm> { + let mut zslices = self.0.zslices_mut(); + // SAFETY: ShmBufInner cannot change the size of the slice + let buf = unsafe { zslices.next()?.downcast_mut::() }; + buf.map(Into::into).filter(|_| zslices.next().is_none()) + } } -} +}; -/// A reader that implements [`std::io::Read`] trait to deserialize from a [`ZBytes`]. See [`ZBytesWriter`] for an example. +/// A reader that implements [`std::io::Read`] trait to deserialize from a [`ZBytes`]. #[repr(transparent)] #[derive(Debug)] pub struct ZBytesReader<'a>(ZBufReader<'a>); -#[derive(Debug)] -pub struct ReadError; - -#[derive(Debug)] -pub enum ZReadOrDeserializeError -where - T: TryFrom, - >::Error: Debug, -{ - Read(ReadError), - Deserialize(>::Error), -} - -impl std::fmt::Display for ZReadOrDeserializeError -where - T: Debug, - T: TryFrom, - >::Error: Debug, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - ZReadOrDeserializeError::Read(_) => f.write_str("Read error"), - ZReadOrDeserializeError::Deserialize(e) => f.write_fmt(format_args!("{:?}", e)), - } - } -} - -impl std::error::Error for ZReadOrDeserializeError -where - T: Debug, - T: TryFrom, - >::Error: Debug, -{ -} - impl ZBytesReader<'_> { /// Returns the number of bytes that can still be read pub fn remaining(&self) -> usize { @@ -530,21 +234,6 @@ impl ZBytesReader<'_> { pub fn is_empty(&self) -> bool { self.remaining() == 0 } - - /// Deserialize an object of type `T` from a [`ZBytesReader`] using the [`ZSerde`]. - /// See [`ZBytesWriter::serialize`] for an example. - pub fn deserialize(&mut self) -> Result>::Error> - where - for<'a> ZSerde: Deserialize = &'a ZBytes>, - >::Error: Debug, - { - let codec = Zenoh080::new(); - let abuf: ZBuf = codec.read(&mut self.0).unwrap(); - let apld = ZBytes::new(abuf); - - let a = ZSerde.deserialize(&apld)?; - Ok(a) - } } impl std::io::Read for ZBytesReader<'_> { @@ -560,103 +249,16 @@ impl std::io::Seek for ZBytesReader<'_> { } /// A writer that implements [`std::io::Write`] trait to serialize into a [`ZBytes`]. -/// -/// Example: -/// ```rust -/// use zenoh::bytes::ZBytes; -/// -/// #[derive(Debug, PartialEq)] -/// struct Foo { -/// one: usize, -/// two: String, -/// three: Vec, -/// } -/// -/// let start = Foo { -/// one: 42, -/// two: String::from("Forty-Two"), -/// three: vec![42u8; 42], -/// }; -/// -/// let mut bytes = ZBytes::empty(); -/// let mut writer = bytes.writer(); -/// -/// writer.serialize(&start.one); -/// writer.serialize(&start.two); -/// writer.serialize(&start.three); -/// -/// let mut reader = bytes.reader(); -/// let end = Foo { -/// one: reader.deserialize().unwrap(), -/// two: reader.deserialize().unwrap(), -/// three: reader.deserialize().unwrap(), -/// }; -/// assert_eq!(start, end); -/// ``` -#[repr(transparent)] #[derive(Debug)] -pub struct ZBytesWriter<'a>(ZBufWriter<'a>); - -impl ZBytesWriter<'_> { - fn write(&mut self, bytes: &ZBuf) { - let codec = Zenoh080::new(); - // SAFETY: we are serializing slices on a ZBuf, so serialization will never - // fail unless we run out of memory. In that case, Rust memory allocator - // will panic before the serializer has any chance to fail. - unsafe { codec.write(&mut self.0, bytes).unwrap_unchecked() }; - } - - /// Serialize a type `T` on the [`ZBytes`]. For simmetricity, every serialization - /// operation preserves type boundaries by preprending the length of the serialized data. - /// This allows calling [`ZBytesReader::deserialize`] in the same order to retrieve the original type. - /// - /// Example: - /// ``` - /// use zenoh::bytes::ZBytes; - /// - /// // serialization - /// let mut bytes = ZBytes::empty(); - /// let mut writer = bytes.writer(); - /// let i1 = 1234_u32; - /// let i2 = String::from("test"); - /// let i3 = vec![1, 2, 3, 4]; - /// writer.serialize(i1); - /// writer.serialize(&i2); - /// writer.serialize(&i3); - /// // deserialization - /// let mut reader = bytes.reader(); - /// let o1: u32 = reader.deserialize().unwrap(); - /// let o2: String = reader.deserialize().unwrap(); - /// let o3: Vec = reader.deserialize().unwrap(); - /// assert_eq!(i1, o1); - /// assert_eq!(i2, o2); - /// assert_eq!(i3, o3); - /// ``` - pub fn serialize(&mut self, t: T) - where - ZSerde: Serialize, - { - let tpld = ZSerde.serialize(t); - self.write(&tpld.0); - } - - /// Try to serialize a type `T` on the [`ZBytes`]. Serialization works - /// in the same way as [`ZBytesWriter::serialize`]. - pub fn try_serialize(&mut self, t: T) -> Result<(), E> - where - ZSerde: Serialize>, - { - let tpld = ZSerde.serialize(t)?; - self.write(&tpld.0); - Ok(()) - } +pub struct ZBytesWriter { + zbuf: ZBuf, + vec: Vec, +} +impl ZBytesWriter { /// Append a [`ZBytes`] to this [`ZBytes`] by taking ownership. /// This allows to compose a [`ZBytes`] out of multiple [`ZBytes`] that may point to different memory regions. /// Said in other terms, it allows to create a linear view on different memory regions without copy. - /// Please note that `append` does not preserve any boundaries as done in [`ZBytesWriter::serialize`], meaning - /// that [`ZBytesReader::deserialize`] will not be able to deserialize the types in the same seriliazation order. - /// You will need to decide how to deserialize data yourself. /// /// Example: /// ``` @@ -666,30 +268,41 @@ impl ZBytesWriter<'_> { /// let two = ZBytes::from(vec![2, 3, 4, 5]); /// let three = ZBytes::from(vec![6, 7]); /// - /// let mut bytes = ZBytes::empty(); - /// let mut writer = bytes.writer(); + /// let mut writer = ZBytes::writer(); /// // Append data without copying by passing ownership /// writer.append(one); /// writer.append(two); /// writer.append(three); + /// let zbytes = writer.finish(); /// - /// // deserialization - /// let mut out: Vec = bytes.into(); - /// assert_eq!(out, vec![0u8, 1, 2, 3, 4, 5, 6, 7]); + /// assert_eq!(zbytes.to_bytes(), vec![0u8, 1, 2, 3, 4, 5, 6, 7]); /// ``` - pub fn append(&mut self, b: ZBytes) { - use zenoh_buffers::writer::Writer; - for s in b.0.zslices() { - // SAFETY: we are writing a ZSlice on a ZBuf, this is infallible because we are just pushing a ZSlice to - // the list of available ZSlices. - unsafe { self.0.write_zslice(s).unwrap_unchecked() } + pub fn append(&mut self, zbytes: ZBytes) { + if !self.vec.is_empty() { + self.zbuf.push_zslice(mem::take(&mut self.vec).into()); + } + for zslice in zbytes.0.into_zslices() { + self.zbuf.push_zslice(zslice); + } + } + + pub fn finish(mut self) -> ZBytes { + if !self.vec.is_empty() { + self.zbuf.push_zslice(self.vec.into()); } + ZBytes(self.zbuf) } } -impl std::io::Write for ZBytesWriter<'_> { +impl From for ZBytes { + fn from(value: ZBytesWriter) -> Self { + value.finish() + } +} + +impl std::io::Write for ZBytesWriter { fn write(&mut self, buf: &[u8]) -> std::io::Result { - std::io::Write::write(&mut self.0, buf) + std::io::Write::write(&mut self.vec, buf) } fn flush(&mut self) -> std::io::Result<()> { @@ -697,7 +310,7 @@ impl std::io::Write for ZBytesWriter<'_> { } } -/// An iterator that implements [`std::iter::Iterator`] trait to iterate on [`&[u8]`]. +/// An iterator to iterate on raw bytes slices contained in a [`ZBytes`]. /// /// Example: /// ```rust @@ -706,25 +319,24 @@ impl std::io::Write for ZBytesWriter<'_> { /// /// let buf1: Vec = vec![1, 2, 3]; /// let buf2: Vec = vec![4, 5, 6, 7, 8]; -/// let mut zbs = ZBytes::empty(); -/// let mut writer = zbs.writer(); +/// let mut writer = ZBytes::writer(); /// writer.write(&buf1); /// writer.write(&buf2); +/// let mut zbytes = writer.finish(); /// /// // Access the raw content -/// for slice in zbs.slices() { +/// for slice in zbytes.slices() { /// println!("{:02x?}", slice); /// } /// /// // Concatenate input in a single vector /// let buf: Vec = buf1.into_iter().chain(buf2.into_iter()).collect(); /// // Concatenate raw bytes in a single vector -/// let out: Vec = zbs.slices().fold(Vec::new(), |mut b, x| { b.extend_from_slice(x); b }); +/// let out: Vec = zbytes.slices().fold(Vec::new(), |mut b, x| { b.extend_from_slice(x); b }); /// // The previous line is the equivalent of /// // let out: Vec = zbs.into(); /// assert_eq!(buf, out); /// ``` -#[repr(transparent)] #[derive(Debug)] pub struct ZBytesSliceIterator<'a>(ZBytesSliceIteratorInner<'a>); @@ -740,2616 +352,116 @@ impl<'a> Iterator for ZBytesSliceIterator<'a> { } } -/// An iterator that implements [`std::iter::Iterator`] trait to iterate on values `T` in a [`ZBytes`]. -/// Note that [`ZBytes`] contains a serialized version of `T` and iterating over a [`ZBytes`] performs lazy deserialization. -/// -/// Example: -/// ```rust -/// use zenoh::bytes::ZBytes; -/// -/// let list: Vec = vec![1.1, 2.2, 3.3]; -/// let mut zbs = ZBytes::from_iter(list.iter()); -/// -/// for (index, elem) in zbs.iter::().enumerate() { -/// assert_eq!(list[index], elem.unwrap()); -/// } -/// ``` -#[repr(transparent)] -#[derive(Debug)] -pub struct ZBytesIterator<'a, T> { - reader: ZBufReader<'a>, - _t: PhantomData, -} - -impl Iterator for ZBytesIterator<'_, T> -where - for<'a> ZSerde: Deserialize = &'a ZBytes>, - >::Error: Debug, -{ - type Item = Result>::Error>; - - fn next(&mut self) -> Option { - let codec = Zenoh080::new(); - - let kbuf: ZBuf = codec.read(&mut self.reader).ok()?; - let kpld = ZBytes::new(kbuf); - - Some(ZSerde.deserialize(&kpld)) - } -} - -impl FromIterator for ZBytes -where - ZSerde: Serialize, -{ - fn from_iter>(iter: T) -> Self { - let mut bytes = ZBytes::empty(); - let mut writer = bytes.writer(); - for t in iter { - writer.serialize(t); - } - - ZBytes::new(bytes) +impl From for ZBytes { + fn from(value: ZBuf) -> Self { + Self(value) } } - -/// The default serializer for [`ZBytes`]. It supports primitives types, such as: `Vec`, `uX`, `iX`, `fX`, `String`, `bool`. -/// It also supports common Rust serde values like [`serde_json::Value`]. See [`ZBytes`] for examples. -/// -/// **NOTE 1:** Zenoh semantic and protocol take care of sending and receiving bytes without restricting the actual data types. -/// -/// **NOTE 2:** [`ZSerde`] is the default serializer/deserializer provided for convenience to the users to deal with primitives data types via -/// a simple out-of-the-box encoding. That is, [`ZSerde`] is provided as a facilitator for simple use cases that need to send/receive data -/// over Zenoh, and doing so potentially to/from different programming languages. Make simple use cases simple and provide freedom for more -/// advanced use cases. -/// -/// **NOTE 3:** [`ZSerde`] is **NOT** by any means the only serializer/deserializer users can use nor a limitation to the types supported by Zenoh. -/// [`ZSerde`] does not have the ambition nor the plan to be a full alternative of more complete seriliazation libraries like *serde*, *protobuf*, -/// *bincode*, *flatbuffers*, etc. Users are free and encouraged to use any serializer/deserializer of their choice that better suits their use case. -#[derive(Clone, Copy, Debug)] -pub struct ZSerde; - -#[derive(Debug, Clone, Copy)] -pub struct ZDeserializeError; - -impl std::fmt::Display for ZDeserializeError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str("Deserialize error") +impl From for ZBuf { + fn from(value: ZBytes) -> Self { + value.0 } } - -impl std::error::Error for ZDeserializeError {} - -// ZBytes -impl Serialize for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: ZBytes) -> Self::Output { - t +impl From<[u8; N]> for ZBytes { + fn from(value: [u8; N]) -> Self { + Self(value.into()) } } - -impl From<&ZBytes> for ZBytes { - fn from(t: &ZBytes) -> Self { - ZSerde.serialize(t) +impl From<&[u8; N]> for ZBytes { + fn from(value: &[u8; N]) -> Self { + value.to_vec().into() } } - -impl From<&mut ZBytes> for ZBytes { - fn from(t: &mut ZBytes) -> Self { - ZSerde.serialize(t) +impl From> for ZBytes { + fn from(value: Vec) -> Self { + Self(value.into()) } } - -impl Serialize<&ZBytes> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: &ZBytes) -> Self::Output { - t.clone() +impl From<&Vec> for ZBytes { + fn from(value: &Vec) -> Self { + value.clone().into() } } - -impl Serialize<&mut ZBytes> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: &mut ZBytes) -> Self::Output { - t.clone() +impl From<&[u8]> for ZBytes { + fn from(value: &[u8]) -> Self { + value.to_vec().into() } } - -impl Deserialize for ZSerde { - type Input<'a> = &'a ZBytes; - type Error = Infallible; - - fn deserialize(self, v: Self::Input<'_>) -> Result { - Ok(v.clone()) +impl From> for ZBytes { + fn from(value: Cow<'_, [u8]>) -> Self { + value.into_owned().into() } } - -// ZBuf -#[doc(hidden)] -impl Serialize for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: ZBuf) -> Self::Output { - ZBytes::new(t) +impl From<&Cow<'_, [u8]>> for ZBytes { + fn from(value: &Cow<'_, [u8]>) -> Self { + value.clone().into() } } - -#[doc(hidden)] -impl From for ZBytes { - fn from(t: ZBuf) -> Self { - ZSerde.serialize(t) +impl From for ZBytes { + fn from(value: String) -> Self { + value.into_bytes().into() } } - -#[doc(hidden)] -impl Serialize<&ZBuf> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: &ZBuf) -> Self::Output { - ZBytes::new(t.clone()) +impl From<&String> for ZBytes { + fn from(value: &String) -> Self { + value.clone().into() } } - -#[doc(hidden)] -impl From<&ZBuf> for ZBytes { - fn from(t: &ZBuf) -> Self { - ZSerde.serialize(t) +impl From<&str> for ZBytes { + fn from(value: &str) -> Self { + value.as_bytes().into() } } - -#[doc(hidden)] -impl Serialize<&mut ZBuf> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: &mut ZBuf) -> Self::Output { - ZBytes::new(t.clone()) +impl From> for ZBytes { + fn from(value: Cow<'_, str>) -> Self { + value.into_owned().into() } } - -#[doc(hidden)] -impl From<&mut ZBuf> for ZBytes { - fn from(t: &mut ZBuf) -> Self { - ZSerde.serialize(t) - } -} - -#[doc(hidden)] -impl Deserialize for ZSerde { - type Input<'a> = &'a ZBytes; - type Error = Infallible; - - fn deserialize(self, v: Self::Input<'_>) -> Result { - Ok(v.0.clone()) - } -} - -#[doc(hidden)] -impl From for ZBuf { - fn from(value: ZBytes) -> Self { - value.0 - } -} - -#[doc(hidden)] -impl From<&ZBytes> for ZBuf { - fn from(value: &ZBytes) -> Self { - ZSerde.deserialize(value).unwrap_infallible() - } -} - -#[doc(hidden)] -impl From<&mut ZBytes> for ZBuf { - fn from(value: &mut ZBytes) -> Self { - ZSerde.deserialize(&*value).unwrap_infallible() - } -} - -// ZSlice -#[doc(hidden)] -impl Serialize for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: ZSlice) -> Self::Output { - ZBytes::new(t) - } -} - -#[doc(hidden)] -impl From for ZBytes { - fn from(t: ZSlice) -> Self { - ZSerde.serialize(t) - } -} - -#[doc(hidden)] -impl Serialize<&ZSlice> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: &ZSlice) -> Self::Output { - ZBytes::new(t.clone()) - } -} - -#[doc(hidden)] -impl From<&ZSlice> for ZBytes { - fn from(t: &ZSlice) -> Self { - ZSerde.serialize(t) - } -} - -#[doc(hidden)] -impl Serialize<&mut ZSlice> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: &mut ZSlice) -> Self::Output { - ZBytes::new(t.clone()) - } -} - -#[doc(hidden)] -impl From<&mut ZSlice> for ZBytes { - fn from(t: &mut ZSlice) -> Self { - ZSerde.serialize(t) - } -} - -#[doc(hidden)] -impl Deserialize for ZSerde { - type Input<'a> = &'a ZBytes; - type Error = Infallible; - - fn deserialize(self, v: Self::Input<'_>) -> Result { - Ok(v.0.to_zslice()) - } -} - -#[doc(hidden)] -impl From for ZSlice { - fn from(value: ZBytes) -> Self { - ZBuf::from(value).to_zslice() - } -} - -#[doc(hidden)] -impl From<&ZBytes> for ZSlice { - fn from(value: &ZBytes) -> Self { - ZSerde.deserialize(value).unwrap_infallible() - } -} - -#[doc(hidden)] -impl From<&mut ZBytes> for ZSlice { - fn from(value: &mut ZBytes) -> Self { - ZSerde.deserialize(&*value).unwrap_infallible() - } -} - -// [u8; N] -impl Serialize<[u8; N]> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: [u8; N]) -> Self::Output { - ZBytes::new(t) - } -} - -impl From<[u8; N]> for ZBytes { - fn from(t: [u8; N]) -> Self { - ZSerde.serialize(t) - } -} - -impl Serialize<&[u8; N]> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: &[u8; N]) -> Self::Output { - ZBytes::new(*t) - } -} - -impl From<&[u8; N]> for ZBytes { - fn from(t: &[u8; N]) -> Self { - ZSerde.serialize(t) - } -} - -impl Serialize<&mut [u8; N]> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: &mut [u8; N]) -> Self::Output { - ZBytes::new(*t) - } -} - -impl From<&mut [u8; N]> for ZBytes { - fn from(t: &mut [u8; N]) -> Self { - ZSerde.serialize(*t) - } -} - -impl Deserialize<[u8; N]> for ZSerde { - type Input<'a> = &'a ZBytes; - type Error = ZDeserializeError; - - fn deserialize(self, v: Self::Input<'_>) -> Result<[u8; N], Self::Error> { - use std::io::Read; - - if v.0.len() != N { - return Err(ZDeserializeError); - } - let mut dst = [0u8; N]; - let mut reader = v.reader(); - reader.read_exact(&mut dst).map_err(|_| ZDeserializeError)?; - Ok(dst) - } -} - -impl TryFrom for [u8; N] { - type Error = ZDeserializeError; - - fn try_from(value: ZBytes) -> Result { - ZSerde.deserialize(&value) - } -} - -impl TryFrom<&ZBytes> for [u8; N] { - type Error = ZDeserializeError; - - fn try_from(value: &ZBytes) -> Result { - ZSerde.deserialize(value) - } -} - -impl TryFrom<&mut ZBytes> for [u8; N] { - type Error = ZDeserializeError; - - fn try_from(value: &mut ZBytes) -> Result { - ZSerde.deserialize(&*value) - } -} - -// Vec -impl Serialize> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: Vec) -> Self::Output { - ZBytes::new(t) - } -} - -impl From> for ZBytes { - fn from(t: Vec) -> Self { - ZSerde.serialize(t) - } -} - -impl Serialize<&Vec> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: &Vec) -> Self::Output { - ZBytes::new(t.clone()) - } -} - -impl From<&Vec> for ZBytes { - fn from(t: &Vec) -> Self { - ZSerde.serialize(t) - } -} - -impl Serialize<&mut Vec> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: &mut Vec) -> Self::Output { - ZBytes::new(t.clone()) - } -} - -impl From<&mut Vec> for ZBytes { - fn from(t: &mut Vec) -> Self { - ZSerde.serialize(t) - } -} - -impl Deserialize> for ZSerde { - type Input<'a> = &'a ZBytes; - type Error = Infallible; - - fn deserialize(self, v: Self::Input<'_>) -> Result, Self::Error> { - Ok(v.0.contiguous().to_vec()) - } -} - -impl From for Vec { - fn from(value: ZBytes) -> Self { - ZSerde.deserialize(&value).unwrap_infallible() - } -} - -impl From<&ZBytes> for Vec { - fn from(value: &ZBytes) -> Self { - ZSerde.deserialize(value).unwrap_infallible() - } -} - -impl From<&mut ZBytes> for Vec { - fn from(value: &mut ZBytes) -> Self { - ZSerde.deserialize(&*value).unwrap_infallible() - } -} - -// &[u8] -impl Serialize<&[u8]> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: &[u8]) -> Self::Output { - ZBytes::new(t.to_vec()) - } -} - -impl From<&[u8]> for ZBytes { - fn from(t: &[u8]) -> Self { - ZSerde.serialize(t) - } -} - -impl Serialize<&mut [u8]> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: &mut [u8]) -> Self::Output { - ZSerde.serialize(&*t) - } -} - -impl From<&mut [u8]> for ZBytes { - fn from(t: &mut [u8]) -> Self { - ZSerde.serialize(t) - } -} - -// Cow<[u8]> -impl<'a> Serialize> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: Cow<'a, [u8]>) -> Self::Output { - ZBytes::new(t.to_vec()) - } -} - -impl From> for ZBytes { - fn from(t: Cow<'_, [u8]>) -> Self { - ZSerde.serialize(t) - } -} - -impl<'a> Serialize<&Cow<'a, [u8]>> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: &Cow<'a, [u8]>) -> Self::Output { - ZBytes::new(t.to_vec()) - } -} - -impl From<&Cow<'_, [u8]>> for ZBytes { - fn from(t: &Cow<'_, [u8]>) -> Self { - ZSerde.serialize(t) - } -} - -impl<'a> Serialize<&mut Cow<'a, [u8]>> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: &mut Cow<'a, [u8]>) -> Self::Output { - ZSerde.serialize(&*t) - } -} - -impl From<&mut Cow<'_, [u8]>> for ZBytes { - fn from(t: &mut Cow<'_, [u8]>) -> Self { - ZSerde.serialize(t) - } -} - -impl<'a> Deserialize> for ZSerde { - type Input<'b> = &'a ZBytes; - type Error = Infallible; - - fn deserialize(self, v: Self::Input<'a>) -> Result, Self::Error> { - Ok(v.0.contiguous()) - } -} - -impl From for Cow<'static, [u8]> { - fn from(v: ZBytes) -> Self { - match v.0.contiguous() { - Cow::Borrowed(s) => Cow::Owned(s.to_vec()), - Cow::Owned(s) => Cow::Owned(s), - } - } -} - -impl<'a> From<&'a ZBytes> for Cow<'a, [u8]> { - fn from(value: &'a ZBytes) -> Self { - ZSerde.deserialize(value).unwrap_infallible() - } -} - -impl<'a> From<&'a mut ZBytes> for Cow<'a, [u8]> { - fn from(value: &'a mut ZBytes) -> Self { - ZSerde.deserialize(&*value).unwrap_infallible() - } -} - -// String -impl Serialize for ZSerde { - type Output = ZBytes; - - fn serialize(self, s: String) -> Self::Output { - ZBytes::new(s.into_bytes()) - } -} - -impl From for ZBytes { - fn from(t: String) -> Self { - ZSerde.serialize(t) - } -} - -impl Serialize<&String> for ZSerde { - type Output = ZBytes; - - fn serialize(self, s: &String) -> Self::Output { - ZBytes::new(s.clone().into_bytes()) - } -} - -impl From<&String> for ZBytes { - fn from(t: &String) -> Self { - ZSerde.serialize(t) - } -} - -impl Serialize<&mut String> for ZSerde { - type Output = ZBytes; - - fn serialize(self, s: &mut String) -> Self::Output { - ZSerde.serialize(&*s) - } -} - -impl From<&mut String> for ZBytes { - fn from(t: &mut String) -> Self { - ZSerde.serialize(t) - } -} - -impl Deserialize for ZSerde { - type Input<'a> = &'a ZBytes; - type Error = FromUtf8Error; - - fn deserialize(self, v: Self::Input<'_>) -> Result { - let v: Vec = ZSerde.deserialize(v).unwrap_infallible(); - String::from_utf8(v) - } -} - -impl TryFrom for String { - type Error = FromUtf8Error; - - fn try_from(value: ZBytes) -> Result { - ZSerde.deserialize(&value) - } -} - -impl TryFrom<&ZBytes> for String { - type Error = FromUtf8Error; - - fn try_from(value: &ZBytes) -> Result { - ZSerde.deserialize(value) - } -} - -impl TryFrom<&mut ZBytes> for String { - type Error = FromUtf8Error; - - fn try_from(value: &mut ZBytes) -> Result { - ZSerde.deserialize(&*value) - } -} - -// &str -impl Serialize<&str> for ZSerde { - type Output = ZBytes; - - fn serialize(self, s: &str) -> Self::Output { - ZSerde.serialize(s.to_string()) - } -} - -impl From<&str> for ZBytes { - fn from(t: &str) -> Self { - ZSerde.serialize(t) - } -} - -impl Serialize<&mut str> for ZSerde { - type Output = ZBytes; - - fn serialize(self, s: &mut str) -> Self::Output { - ZSerde.serialize(&*s) - } -} - -impl From<&mut str> for ZBytes { - fn from(t: &mut str) -> Self { - ZSerde.serialize(t) - } -} - -impl<'a> Serialize> for ZSerde { - type Output = ZBytes; - - fn serialize(self, s: Cow<'a, str>) -> Self::Output { - Self.serialize(s.to_string()) - } -} - -impl From> for ZBytes { - fn from(t: Cow<'_, str>) -> Self { - ZSerde.serialize(t) - } -} - -impl<'a> Serialize<&Cow<'a, str>> for ZSerde { - type Output = ZBytes; - - fn serialize(self, s: &Cow<'a, str>) -> Self::Output { - ZSerde.serialize(s.to_string()) - } -} - -impl From<&Cow<'_, str>> for ZBytes { - fn from(t: &Cow<'_, str>) -> Self { - ZSerde.serialize(t) - } -} - -impl<'a> Serialize<&mut Cow<'a, str>> for ZSerde { - type Output = ZBytes; - - fn serialize(self, s: &mut Cow<'a, str>) -> Self::Output { - ZSerde.serialize(&*s) - } -} - -impl From<&mut Cow<'_, str>> for ZBytes { - fn from(t: &mut Cow<'_, str>) -> Self { - ZSerde.serialize(t) - } -} - -/// See [`Deserialize>`] for guarantees on copies. -impl<'a> Deserialize> for ZSerde { - type Input<'b> = &'a ZBytes; - type Error = Utf8Error; - - fn deserialize(self, v: Self::Input<'a>) -> Result, Self::Error> { - Cow::try_from(v) - } -} - -impl TryFrom for Cow<'static, str> { - type Error = Utf8Error; - - fn try_from(v: ZBytes) -> Result { - Ok(match Cow::<[u8]>::from(v) { - Cow::Borrowed(s) => core::str::from_utf8(s)?.into(), - Cow::Owned(s) => String::from_utf8(s).map_err(|err| err.utf8_error())?.into(), - }) - } -} - -impl<'a> TryFrom<&'a ZBytes> for Cow<'a, str> { - type Error = Utf8Error; - - fn try_from(v: &'a ZBytes) -> Result { - Ok(match Cow::<[u8]>::from(v) { - Cow::Borrowed(s) => core::str::from_utf8(s)?.into(), - Cow::Owned(s) => String::from_utf8(s).map_err(|err| err.utf8_error())?.into(), - }) - } -} - -impl<'a> TryFrom<&'a mut ZBytes> for Cow<'a, str> { - type Error = Utf8Error; - - fn try_from(v: &'a mut ZBytes) -> Result { - Ok(match Cow::<[u8]>::from(v) { - Cow::Borrowed(s) => core::str::from_utf8(s)?.into(), - Cow::Owned(s) => String::from_utf8(s).map_err(|err| err.utf8_error())?.into(), - }) - } -} - -// - Impl Serialize/Deserialize for numbers -macro_rules! impl_num { - ($t:ty) => { - impl Serialize<$t> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: $t) -> Self::Output { - let bs = t.to_le_bytes(); - let mut end = 1; - if t != 0 as $t { - end += bs.iter().rposition(|b| *b != 0).unwrap_or(bs.len() - 1); - }; - // SAFETY: - // - 0 is a valid start index because bs is guaranteed to always have a length greater or equal than 1 - // - end is a valid end index because is bounded between 0 and bs.len() - ZBytes::new(unsafe { ZSlice::new(Arc::new(bs), 0, end).unwrap_unchecked() }) - } - } - - impl From<$t> for ZBytes { - fn from(t: $t) -> Self { - ZSerde.serialize(t) - } - } - - impl Serialize<&$t> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: &$t) -> Self::Output { - Self.serialize(*t) - } - } - - impl From<&$t> for ZBytes { - fn from(t: &$t) -> Self { - ZSerde.serialize(t) - } - } - - impl Serialize<&mut $t> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: &mut $t) -> Self::Output { - Self.serialize(*t) - } - } - - impl From<&mut $t> for ZBytes { - fn from(t: &mut $t) -> Self { - ZSerde.serialize(t) - } - } - - impl Deserialize<$t> for ZSerde { - type Input<'a> = &'a ZBytes; - type Error = ZDeserializeError; - - fn deserialize(self, v: Self::Input<'_>) -> Result<$t, Self::Error> { - use std::io::Read; - - let mut r = v.reader(); - let mut bs = (0 as $t).to_le_bytes(); - if v.len() > bs.len() { - return Err(ZDeserializeError); - } - r.read_exact(&mut bs[..v.len()]) - .map_err(|_| ZDeserializeError)?; - let t = <$t>::from_le_bytes(bs); - Ok(t) - } - } - - impl TryFrom for $t { - type Error = ZDeserializeError; - - fn try_from(value: ZBytes) -> Result { - ZSerde.deserialize(&value) - } - } - - impl TryFrom<&ZBytes> for $t { - type Error = ZDeserializeError; - - fn try_from(value: &ZBytes) -> Result { - ZSerde.deserialize(value) - } - } - - impl TryFrom<&mut ZBytes> for $t { - type Error = ZDeserializeError; - - fn try_from(value: &mut ZBytes) -> Result { - ZSerde.deserialize(&*value) - } - } - }; -} - -// Zenoh unsigned integers -impl_num!(u8); -impl_num!(u16); -impl_num!(u32); -impl_num!(u64); -impl_num!(u128); -impl_num!(usize); - -// Zenoh signed integers -impl_num!(i8); -impl_num!(i16); -impl_num!(i32); -impl_num!(i64); -impl_num!(i128); -impl_num!(isize); - -// Zenoh floats -impl_num!(f32); -impl_num!(f64); - -// Zenoh bool -impl Serialize for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: bool) -> Self::Output { - // SAFETY: casting a bool into an integer is well-defined behaviour. - // 0 is false, 1 is true: https://doc.rust-lang.org/std/primitive.bool.html - ZBytes::new(ZBuf::from((t as u8).to_le_bytes())) - } -} - -impl From for ZBytes { - fn from(t: bool) -> Self { - ZSerde.serialize(t) - } -} - -impl Serialize<&bool> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: &bool) -> Self::Output { - ZSerde.serialize(*t) - } -} - -impl From<&bool> for ZBytes { - fn from(t: &bool) -> Self { - ZSerde.serialize(t) - } -} - -impl Serialize<&mut bool> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: &mut bool) -> Self::Output { - ZSerde.serialize(*t) - } -} - -impl From<&mut bool> for ZBytes { - fn from(t: &mut bool) -> Self { - ZSerde.serialize(t) - } -} - -impl Deserialize for ZSerde { - type Input<'a> = &'a ZBytes; - type Error = ZDeserializeError; - - fn deserialize(self, v: Self::Input<'_>) -> Result { - let p = v.deserialize::().map_err(|_| ZDeserializeError)?; - match p { - 0 => Ok(false), - 1 => Ok(true), - _ => Err(ZDeserializeError), - } - } -} - -impl TryFrom for bool { - type Error = ZDeserializeError; - - fn try_from(value: ZBytes) -> Result { - ZSerde.deserialize(&value) - } -} - -impl TryFrom<&ZBytes> for bool { - type Error = ZDeserializeError; - - fn try_from(value: &ZBytes) -> Result { - ZSerde.deserialize(value) - } -} - -impl TryFrom<&mut ZBytes> for bool { - type Error = ZDeserializeError; - - fn try_from(value: &mut ZBytes) -> Result { - ZSerde.deserialize(&*value) - } -} - -// Zenoh char -impl Serialize for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: char) -> Self::Output { - // We can convert char to u32 and encode it as such - // See https://doc.rust-lang.org/std/primitive.char.html#method.from_u32 - ZSerde.serialize(t as u32) - } -} - -impl From for ZBytes { - fn from(t: char) -> Self { - ZSerde.serialize(t) - } -} - -impl Serialize<&char> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: &char) -> Self::Output { - ZSerde.serialize(*t) - } -} - -impl From<&char> for ZBytes { - fn from(t: &char) -> Self { - ZSerde.serialize(t) - } -} - -impl Serialize<&mut char> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: &mut char) -> Self::Output { - ZSerde.serialize(*t) - } -} - -impl From<&mut char> for ZBytes { - fn from(t: &mut char) -> Self { - ZSerde.serialize(t) - } -} - -impl Deserialize for ZSerde { - type Input<'a> = &'a ZBytes; - type Error = ZDeserializeError; - - fn deserialize(self, v: Self::Input<'_>) -> Result { - let c = v.deserialize::()?; - let c = char::try_from(c).map_err(|_| ZDeserializeError)?; - Ok(c) - } -} - -impl TryFrom for char { - type Error = ZDeserializeError; - - fn try_from(value: ZBytes) -> Result { - ZSerde.deserialize(&value) - } -} - -impl TryFrom<&ZBytes> for char { - type Error = ZDeserializeError; - - fn try_from(value: &ZBytes) -> Result { - ZSerde.deserialize(value) - } -} - -impl TryFrom<&mut ZBytes> for char { - type Error = ZDeserializeError; - - fn try_from(value: &mut ZBytes) -> Result { - ZSerde.deserialize(&*value) - } -} - -// - Zenoh advanced types serializer/deserializer -// Parameters -impl Serialize> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: Parameters<'_>) -> Self::Output { - Self.serialize(t.as_str()) - } -} - -impl From> for ZBytes { - fn from(t: Parameters<'_>) -> Self { - ZSerde.serialize(t) - } -} - -impl Serialize<&Parameters<'_>> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: &Parameters<'_>) -> Self::Output { - Self.serialize(t.as_str()) - } -} - -impl<'s> From<&'s Parameters<'s>> for ZBytes { - fn from(t: &'s Parameters<'s>) -> Self { - ZSerde.serialize(t) - } -} - -impl Serialize<&mut Parameters<'_>> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: &mut Parameters<'_>) -> Self::Output { - Self.serialize(t.as_str()) - } -} - -impl<'s> From<&'s mut Parameters<'s>> for ZBytes { - fn from(t: &'s mut Parameters<'s>) -> Self { - ZSerde.serialize(&*t) - } -} - -impl<'a> Deserialize> for ZSerde { - type Input<'b> = &'a ZBytes; - type Error = ZDeserializeError; - - fn deserialize(self, v: Self::Input<'a>) -> Result, Self::Error> { - let s = v - .deserialize::>() - .map_err(|_| ZDeserializeError)?; - Ok(Parameters::from(s)) - } -} - -impl TryFrom for Parameters<'static> { - type Error = ZDeserializeError; - - fn try_from(v: ZBytes) -> Result { - let s = v.deserialize::>().map_err(|_| ZDeserializeError)?; - Ok(Parameters::from(s.into_owned())) - } -} - -impl<'s> TryFrom<&'s ZBytes> for Parameters<'s> { - type Error = ZDeserializeError; - - fn try_from(value: &'s ZBytes) -> Result { - ZSerde.deserialize(value) - } -} - -impl<'s> TryFrom<&'s mut ZBytes> for Parameters<'s> { - type Error = ZDeserializeError; - - fn try_from(value: &'s mut ZBytes) -> Result { - ZSerde.deserialize(&*value) - } -} - -// Timestamp -impl Serialize for ZSerde { - type Output = ZBytes; - - fn serialize(self, s: Timestamp) -> Self::Output { - ZSerde.serialize(&s) - } -} - -impl From for ZBytes { - fn from(t: Timestamp) -> Self { - ZSerde.serialize(t) - } -} - -impl Serialize<&Timestamp> for ZSerde { - type Output = ZBytes; - - fn serialize(self, s: &Timestamp) -> Self::Output { - let codec = Zenoh080::new(); - let mut buffer = ZBuf::empty(); - let mut writer = buffer.writer(); - // SAFETY: we are serializing slices on a ZBuf, so serialization will never - // fail unless we run out of memory. In that case, Rust memory allocator - // will panic before the serializer has any chance to fail. - unsafe { - codec.write(&mut writer, s).unwrap_unchecked(); - } - ZBytes::from(buffer) - } -} - -impl From<&Timestamp> for ZBytes { - fn from(t: &Timestamp) -> Self { - ZSerde.serialize(t) - } -} - -impl Serialize<&mut Timestamp> for ZSerde { - type Output = ZBytes; - - fn serialize(self, s: &mut Timestamp) -> Self::Output { - ZSerde.serialize(&*s) - } -} - -impl From<&mut Timestamp> for ZBytes { - fn from(t: &mut Timestamp) -> Self { - ZSerde.serialize(t) - } -} - -impl Deserialize for ZSerde { - type Input<'a> = &'a ZBytes; - type Error = ReadError; - - fn deserialize(self, v: Self::Input<'_>) -> Result { - let codec = Zenoh080::new(); - let mut reader = v.0.reader(); - let e: Timestamp = codec.read(&mut reader).map_err(|_| ReadError)?; - Ok(e) - } -} - -impl TryFrom for Timestamp { - type Error = ReadError; - - fn try_from(value: ZBytes) -> Result { - ZSerde.deserialize(&value) - } -} - -impl TryFrom<&ZBytes> for Timestamp { - type Error = ReadError; - - fn try_from(value: &ZBytes) -> Result { - ZSerde.deserialize(value) - } -} - -impl TryFrom<&mut ZBytes> for Timestamp { - type Error = ReadError; - - fn try_from(value: &mut ZBytes) -> Result { - ZSerde.deserialize(&*value) - } -} - -// Encoding -impl Serialize for ZSerde { - type Output = ZBytes; - - fn serialize(self, s: Encoding) -> Self::Output { - let e: EncodingProto = s.into(); - let codec = Zenoh080::new(); - let mut buffer = ZBuf::empty(); - let mut writer = buffer.writer(); - // SAFETY: we are serializing slices on a ZBuf, so serialization will never - // fail unless we run out of memory. In that case, Rust memory allocator - // will panic before the serializer has any chance to fail. - unsafe { - codec.write(&mut writer, &e).unwrap_unchecked(); - } - ZBytes::from(buffer) - } -} - -impl From for ZBytes { - fn from(t: Encoding) -> Self { - ZSerde.serialize(t) - } -} - -impl Serialize<&Encoding> for ZSerde { - type Output = ZBytes; - - fn serialize(self, s: &Encoding) -> Self::Output { - ZSerde.serialize(s.clone()) - } -} - -impl From<&Encoding> for ZBytes { - fn from(t: &Encoding) -> Self { - ZSerde.serialize(t) - } -} - -impl Serialize<&mut Encoding> for ZSerde { - type Output = ZBytes; - - fn serialize(self, s: &mut Encoding) -> Self::Output { - ZSerde.serialize(&*s) - } -} - -impl From<&mut Encoding> for ZBytes { - fn from(t: &mut Encoding) -> Self { - ZSerde.serialize(t) - } -} - -impl Deserialize for ZSerde { - type Input<'a> = &'a ZBytes; - type Error = ReadError; - - fn deserialize(self, v: Self::Input<'_>) -> Result { - let codec = Zenoh080::new(); - let mut reader = v.0.reader(); - let e: EncodingProto = codec.read(&mut reader).map_err(|_| ReadError)?; - Ok(e.into()) - } -} - -impl TryFrom for Encoding { - type Error = ReadError; - - fn try_from(value: ZBytes) -> Result { - ZSerde.deserialize(&value) - } -} - -impl TryFrom<&ZBytes> for Encoding { - type Error = ReadError; - - fn try_from(value: &ZBytes) -> Result { - ZSerde.deserialize(value) - } -} - -impl TryFrom<&mut ZBytes> for Encoding { - type Error = ReadError; - - fn try_from(value: &mut ZBytes) -> Result { - ZSerde.deserialize(&*value) - } -} - -// Value -impl Serialize for ZSerde { - type Output = ZBytes; - - fn serialize(self, s: Value) -> Self::Output { - ZSerde.serialize((s.payload(), s.encoding())) - } -} - -impl From for ZBytes { - fn from(t: Value) -> Self { - ZSerde.serialize(t) - } -} - -impl Serialize<&Value> for ZSerde { - type Output = ZBytes; - - fn serialize(self, s: &Value) -> Self::Output { - ZSerde.serialize(s.clone()) - } -} - -impl From<&Value> for ZBytes { - fn from(t: &Value) -> Self { - ZSerde.serialize(t) - } -} - -impl Serialize<&mut Value> for ZSerde { - type Output = ZBytes; - - fn serialize(self, s: &mut Value) -> Self::Output { - ZSerde.serialize(&*s) - } -} - -impl From<&mut Value> for ZBytes { - fn from(t: &mut Value) -> Self { - ZSerde.serialize(t) - } -} - -impl Deserialize for ZSerde { - type Input<'a> = &'a ZBytes; - type Error = ZReadOrDeserializeErrorTuple2; - - fn deserialize(self, v: Self::Input<'_>) -> Result { - let (payload, encoding) = v.deserialize::<(ZBytes, Encoding)>()?; - Ok(Value::new(payload, encoding)) - } -} - -impl TryFrom for Value { - type Error = ZReadOrDeserializeErrorTuple2; - - fn try_from(value: ZBytes) -> Result { - ZSerde.deserialize(&value) - } -} - -impl TryFrom<&ZBytes> for Value { - type Error = ZReadOrDeserializeErrorTuple2; - - fn try_from(value: &ZBytes) -> Result { - ZSerde.deserialize(value) - } -} - -impl TryFrom<&mut ZBytes> for Value { - type Error = ZReadOrDeserializeErrorTuple2; - - fn try_from(value: &mut ZBytes) -> Result { - ZSerde.deserialize(&*value) - } -} - -// JSON -impl Serialize for ZSerde { - type Output = Result; - - fn serialize(self, t: serde_json::Value) -> Self::Output { - ZSerde.serialize(&t) - } -} - -impl TryFrom for ZBytes { - type Error = serde_json::Error; - - fn try_from(value: serde_json::Value) -> Result { - ZSerde.serialize(&value) - } -} - -impl Serialize<&serde_json::Value> for ZSerde { - type Output = Result; - - fn serialize(self, t: &serde_json::Value) -> Self::Output { - let mut bytes = ZBytes::empty(); - serde_json::to_writer(bytes.writer(), t)?; - Ok(bytes) - } -} - -impl TryFrom<&serde_json::Value> for ZBytes { - type Error = serde_json::Error; - - fn try_from(value: &serde_json::Value) -> Result { - ZSerde.serialize(value) - } -} - -impl Serialize<&mut serde_json::Value> for ZSerde { - type Output = Result; - - fn serialize(self, t: &mut serde_json::Value) -> Self::Output { - let mut bytes = ZBytes::empty(); - serde_json::to_writer(bytes.writer(), t)?; - Ok(bytes) - } -} - -impl TryFrom<&mut serde_json::Value> for ZBytes { - type Error = serde_json::Error; - - fn try_from(value: &mut serde_json::Value) -> Result { - ZSerde.serialize(&*value) - } -} - -impl Deserialize for ZSerde { - type Input<'a> = &'a ZBytes; - type Error = serde_json::Error; - - fn deserialize(self, v: Self::Input<'_>) -> Result { - serde_json::from_reader(v.reader()) - } -} - -impl TryFrom for serde_json::Value { - type Error = serde_json::Error; - - fn try_from(value: ZBytes) -> Result { - ZSerde.deserialize(&value) - } -} - -impl TryFrom<&ZBytes> for serde_json::Value { - type Error = serde_json::Error; - - fn try_from(value: &ZBytes) -> Result { - ZSerde.deserialize(value) - } -} - -impl TryFrom<&mut ZBytes> for serde_json::Value { - type Error = serde_json::Error; - - fn try_from(value: &mut ZBytes) -> Result { - ZSerde.deserialize(&*value) - } -} - -// Yaml -impl Serialize for ZSerde { - type Output = Result; - - fn serialize(self, t: serde_yaml::Value) -> Self::Output { - Self.serialize(&t) - } -} - -impl TryFrom for ZBytes { - type Error = serde_yaml::Error; - - fn try_from(value: serde_yaml::Value) -> Result { - ZSerde.serialize(value) - } -} - -impl Serialize<&serde_yaml::Value> for ZSerde { - type Output = Result; - - fn serialize(self, t: &serde_yaml::Value) -> Self::Output { - let mut bytes = ZBytes::empty(); - serde_yaml::to_writer(bytes.writer(), t)?; - Ok(bytes) - } -} - -impl TryFrom<&serde_yaml::Value> for ZBytes { - type Error = serde_yaml::Error; - - fn try_from(value: &serde_yaml::Value) -> Result { - ZSerde.serialize(value) - } -} - -impl Serialize<&mut serde_yaml::Value> for ZSerde { - type Output = Result; - - fn serialize(self, t: &mut serde_yaml::Value) -> Self::Output { - let mut bytes = ZBytes::empty(); - serde_yaml::to_writer(bytes.writer(), t)?; - Ok(bytes) - } -} - -impl TryFrom<&mut serde_yaml::Value> for ZBytes { - type Error = serde_yaml::Error; - - fn try_from(value: &mut serde_yaml::Value) -> Result { - ZSerde.serialize(value) - } -} - -impl Deserialize for ZSerde { - type Input<'a> = &'a ZBytes; - type Error = serde_yaml::Error; - - fn deserialize(self, v: Self::Input<'_>) -> Result { - serde_yaml::from_reader(v.reader()) - } -} - -impl TryFrom for serde_yaml::Value { - type Error = serde_yaml::Error; - - fn try_from(value: ZBytes) -> Result { - ZSerde.deserialize(&value) - } -} - -impl TryFrom<&ZBytes> for serde_yaml::Value { - type Error = serde_yaml::Error; - - fn try_from(value: &ZBytes) -> Result { - ZSerde.deserialize(value) - } -} - -impl TryFrom<&mut ZBytes> for serde_yaml::Value { - type Error = serde_yaml::Error; - - fn try_from(value: &mut ZBytes) -> Result { - ZSerde.deserialize(&*value) - } -} - -// CBOR -impl Serialize for ZSerde { - type Output = Result; - - fn serialize(self, t: serde_cbor::Value) -> Self::Output { - Self.serialize(&t) - } -} - -impl TryFrom for ZBytes { - type Error = serde_cbor::Error; - - fn try_from(value: serde_cbor::Value) -> Result { - ZSerde.serialize(value) - } -} - -impl Serialize<&serde_cbor::Value> for ZSerde { - type Output = Result; - - fn serialize(self, t: &serde_cbor::Value) -> Self::Output { - let mut bytes = ZBytes::empty(); - serde_cbor::to_writer(bytes.0.writer(), t)?; - Ok(bytes) - } -} - -impl TryFrom<&serde_cbor::Value> for ZBytes { - type Error = serde_cbor::Error; - - fn try_from(value: &serde_cbor::Value) -> Result { - ZSerde.serialize(value) - } -} - -impl Serialize<&mut serde_cbor::Value> for ZSerde { - type Output = Result; - - fn serialize(self, t: &mut serde_cbor::Value) -> Self::Output { - ZSerde.serialize(&*t) - } -} - -impl TryFrom<&mut serde_cbor::Value> for ZBytes { - type Error = serde_cbor::Error; - - fn try_from(value: &mut serde_cbor::Value) -> Result { - ZSerde.serialize(value) - } -} - -impl Deserialize for ZSerde { - type Input<'a> = &'a ZBytes; - type Error = serde_cbor::Error; - - fn deserialize(self, v: Self::Input<'_>) -> Result { - serde_cbor::from_reader(v.reader()) - } -} - -impl TryFrom for serde_cbor::Value { - type Error = serde_cbor::Error; - - fn try_from(value: ZBytes) -> Result { - ZSerde.deserialize(&value) - } -} - -impl TryFrom<&ZBytes> for serde_cbor::Value { - type Error = serde_cbor::Error; - - fn try_from(value: &ZBytes) -> Result { - ZSerde.deserialize(value) - } -} - -impl TryFrom<&mut ZBytes> for serde_cbor::Value { - type Error = serde_cbor::Error; - - fn try_from(value: &mut ZBytes) -> Result { - ZSerde.deserialize(&*value) - } -} - -// Pickle -impl Serialize for ZSerde { - type Output = Result; - - fn serialize(self, t: serde_pickle::Value) -> Self::Output { - Self.serialize(&t) - } -} - -impl TryFrom for ZBytes { - type Error = serde_pickle::Error; - - fn try_from(value: serde_pickle::Value) -> Result { - ZSerde.serialize(value) - } -} - -impl Serialize<&serde_pickle::Value> for ZSerde { - type Output = Result; - - fn serialize(self, t: &serde_pickle::Value) -> Self::Output { - let mut bytes = ZBytes::empty(); - serde_pickle::value_to_writer( - &mut bytes.0.writer(), - t, - serde_pickle::SerOptions::default(), - )?; - Ok(bytes) - } -} - -impl TryFrom<&serde_pickle::Value> for ZBytes { - type Error = serde_pickle::Error; - - fn try_from(value: &serde_pickle::Value) -> Result { - ZSerde.serialize(value) - } -} - -impl Serialize<&mut serde_pickle::Value> for ZSerde { - type Output = Result; - - fn serialize(self, t: &mut serde_pickle::Value) -> Self::Output { - ZSerde.serialize(&*t) - } -} - -impl TryFrom<&mut serde_pickle::Value> for ZBytes { - type Error = serde_pickle::Error; - - fn try_from(value: &mut serde_pickle::Value) -> Result { - ZSerde.serialize(value) - } -} - -impl Deserialize for ZSerde { - type Input<'a> = &'a ZBytes; - type Error = serde_pickle::Error; - - fn deserialize(self, v: Self::Input<'_>) -> Result { - serde_pickle::value_from_reader(v.reader(), serde_pickle::DeOptions::default()) - } -} - -impl TryFrom for serde_pickle::Value { - type Error = serde_pickle::Error; - - fn try_from(value: ZBytes) -> Result { - ZSerde.deserialize(&value) - } -} - -impl TryFrom<&ZBytes> for serde_pickle::Value { - type Error = serde_pickle::Error; - - fn try_from(value: &ZBytes) -> Result { - ZSerde.deserialize(value) - } -} - -impl TryFrom<&mut ZBytes> for serde_pickle::Value { - type Error = serde_pickle::Error; - - fn try_from(value: &mut ZBytes) -> Result { - ZSerde.deserialize(&*value) - } -} - -// bytes::Bytes - -// Define a transparent wrapper type to get around Rust's orphan rule. -// This allows to use bytes::Bytes directly as supporting buffer of a -// ZSlice resulting in zero-copy and zero-alloc bytes::Bytes serialization. -#[repr(transparent)] -#[derive(Debug)] -struct BytesWrap(bytes::Bytes); - -impl ZSliceBuffer for BytesWrap { - fn as_slice(&self) -> &[u8] { - &self.0 - } - - fn as_any(&self) -> &dyn std::any::Any { - self - } - - fn as_any_mut(&mut self) -> &mut dyn std::any::Any { - self - } -} - -impl Serialize for ZSerde { - type Output = ZBytes; - - fn serialize(self, s: bytes::Bytes) -> Self::Output { - ZBytes::new(BytesWrap(s)) - } -} - -impl From for ZBytes { - fn from(t: bytes::Bytes) -> Self { - ZSerde.serialize(t) - } -} - -impl Deserialize for ZSerde { - type Input<'a> = &'a ZBytes; - type Error = Infallible; - - fn deserialize(self, v: Self::Input<'_>) -> Result { - // bytes::Bytes can be constructed only by passing ownership to the constructor. - // Thereofore, here we are forced to allocate a vector and copy the whole ZBytes - // content since bytes::Bytes does not support anything else than Box (and its - // variants like Vec and String). - let v: Vec = ZSerde.deserialize(v).unwrap_infallible(); - Ok(bytes::Bytes::from(v)) - } -} - -impl TryFrom for bytes::Bytes { - type Error = Infallible; - - fn try_from(value: ZBytes) -> Result { - ZSerde.deserialize(&value) - } -} - -impl TryFrom<&ZBytes> for bytes::Bytes { - type Error = Infallible; - - fn try_from(value: &ZBytes) -> Result { - ZSerde.deserialize(value) - } -} - -impl TryFrom<&mut ZBytes> for bytes::Bytes { - type Error = Infallible; - - fn try_from(value: &mut ZBytes) -> Result { - ZSerde.deserialize(&*value) - } -} - -// Shared memory conversion -#[cfg(feature = "shared-memory")] -impl Serialize for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: ZShm) -> Self::Output { - let slice: ZSlice = t.into(); - ZBytes::new(slice) - } -} - -#[cfg(feature = "shared-memory")] -impl From for ZBytes { - fn from(t: ZShm) -> Self { - ZSerde.serialize(t) - } -} - -// Shared memory conversion -#[cfg(feature = "shared-memory")] -impl Serialize for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: ZShmMut) -> Self::Output { - let slice: ZSlice = t.into(); - ZBytes::new(slice) - } -} - -#[cfg(feature = "shared-memory")] -impl From for ZBytes { - fn from(t: ZShmMut) -> Self { - ZSerde.serialize(t) - } -} - -#[cfg(feature = "shared-memory")] -impl<'a> Deserialize<&'a zshm> for ZSerde { - type Input<'b> = &'a ZBytes; - type Error = ZDeserializeError; - - fn deserialize(self, v: Self::Input<'a>) -> Result<&'a zshm, Self::Error> { - // A ZShm is expected to have only one slice - let mut zslices = v.0.zslices(); - if let Some(zs) = zslices.next() { - if let Some(shmb) = zs.downcast_ref::() { - return Ok(shmb.into()); - } - } - Err(ZDeserializeError) - } -} - -#[cfg(feature = "shared-memory")] -impl<'a> TryFrom<&'a ZBytes> for &'a zshm { - type Error = ZDeserializeError; - - fn try_from(value: &'a ZBytes) -> Result { - ZSerde.deserialize(value) - } -} - -#[cfg(feature = "shared-memory")] -impl<'a> TryFrom<&'a mut ZBytes> for &'a mut zshm { - type Error = ZDeserializeError; - - fn try_from(value: &'a mut ZBytes) -> Result { - ZSerde.deserialize(value) - } -} - -#[cfg(feature = "shared-memory")] -impl<'a> Deserialize<&'a mut zshm> for ZSerde { - type Input<'b> = &'a mut ZBytes; - type Error = ZDeserializeError; - - fn deserialize(self, v: Self::Input<'a>) -> Result<&'a mut zshm, Self::Error> { - // A ZSliceShmBorrowMut is expected to have only one slice - let mut zslices = v.0.zslices_mut(); - if let Some(zs) = zslices.next() { - // SAFETY: ShmBufInner cannot change the size of the slice - if let Some(shmb) = unsafe { zs.downcast_mut::() } { - return Ok(shmb.into()); - } - } - Err(ZDeserializeError) - } -} - -#[cfg(feature = "shared-memory")] -impl<'a> Deserialize<&'a mut zshmmut> for ZSerde { - type Input<'b> = &'a mut ZBytes; - type Error = ZDeserializeError; - - fn deserialize(self, v: Self::Input<'a>) -> Result<&'a mut zshmmut, Self::Error> { - // A ZSliceShmBorrowMut is expected to have only one slice - let mut zslices = v.0.zslices_mut(); - if let Some(zs) = zslices.next() { - // SAFETY: ShmBufInner cannot change the size of the slice - if let Some(shmb) = unsafe { zs.downcast_mut::() } { - return shmb.try_into().map_err(|_| ZDeserializeError); - } - } - Err(ZDeserializeError) - } -} - -#[cfg(feature = "shared-memory")] -impl<'a> TryFrom<&'a mut ZBytes> for &'a mut zshmmut { - type Error = ZDeserializeError; - - fn try_from(value: &'a mut ZBytes) -> Result { - ZSerde.deserialize(value) - } -} - -// Tuple (a, b) -macro_rules! impl_tuple2 { - ($t:expr) => {{ - let (a, b) = $t; - - let codec = Zenoh080::new(); - let mut buffer: ZBuf = ZBuf::empty(); - let mut writer = buffer.writer(); - let apld: ZBytes = a.into(); - let bpld: ZBytes = b.into(); - - // SAFETY: we are serializing slices on a ZBuf, so serialization will never - // fail unless we run out of memory. In that case, Rust memory allocator - // will panic before the serializer has any chance to fail. - unsafe { - codec.write(&mut writer, &apld.0).unwrap_unchecked(); - codec.write(&mut writer, &bpld.0).unwrap_unchecked(); - } - - ZBytes::new(buffer) - }}; -} - -impl Serialize<(A, B)> for ZSerde -where - A: Into, - B: Into, -{ - type Output = ZBytes; - - fn serialize(self, t: (A, B)) -> Self::Output { - impl_tuple2!(t) - } -} - -impl Serialize<&(A, B)> for ZSerde -where - for<'a> &'a A: Into, - for<'b> &'b B: Into, -{ - type Output = ZBytes; - - fn serialize(self, t: &(A, B)) -> Self::Output { - impl_tuple2!(t) - } -} - -impl From<(A, B)> for ZBytes -where - A: Into, - B: Into, -{ - fn from(value: (A, B)) -> Self { - ZSerde.serialize(value) - } -} - -#[derive(Debug)] -pub enum ZReadOrDeserializeErrorTuple2 -where - A: TryFrom, - >::Error: Debug, - B: TryFrom, - >::Error: Debug, -{ - One(ZReadOrDeserializeError), - Two(ZReadOrDeserializeError), -} - -impl std::fmt::Display for ZReadOrDeserializeErrorTuple2 -where - A: Debug, - A: TryFrom, - >::Error: Debug, - B: Debug, - B: TryFrom, - >::Error: Debug, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - ZReadOrDeserializeErrorTuple2::One(e) => { - f.write_fmt(format_args!("1st tuple element: {}", e)) - } - ZReadOrDeserializeErrorTuple2::Two(e) => { - f.write_fmt(format_args!("2nd tuple element: {}", e)) - } - } - } -} - -impl std::error::Error for ZReadOrDeserializeErrorTuple2 -where - A: Debug, - A: TryFrom, - >::Error: Debug, - B: Debug, - B: TryFrom, - >::Error: Debug, -{ -} - -impl Deserialize<(A, B)> for ZSerde -where - A: TryFrom, - >::Error: Debug, - B: TryFrom, - >::Error: Debug, -{ - type Input<'a> = &'a ZBytes; - type Error = ZReadOrDeserializeErrorTuple2; - - fn deserialize(self, bytes: Self::Input<'_>) -> Result<(A, B), Self::Error> { - let codec = Zenoh080::new(); - let mut reader = bytes.0.reader(); - - let abuf: ZBuf = codec.read(&mut reader).map_err(|_| { - ZReadOrDeserializeErrorTuple2::One(ZReadOrDeserializeError::Read(ReadError)) - })?; - let apld = ZBytes::new(abuf); - let a = A::try_from(apld).map_err(|e| { - ZReadOrDeserializeErrorTuple2::One(ZReadOrDeserializeError::Deserialize(e)) - })?; - - let bbuf: ZBuf = codec.read(&mut reader).map_err(|_| { - ZReadOrDeserializeErrorTuple2::Two(ZReadOrDeserializeError::Read(ReadError)) - })?; - let bpld = ZBytes::new(bbuf); - let b = B::try_from(bpld).map_err(|e| { - ZReadOrDeserializeErrorTuple2::Two(ZReadOrDeserializeError::Deserialize(e)) - })?; - - Ok((a, b)) - } -} - -impl TryFrom for (A, B) -where - A: TryFrom, - >::Error: Debug, - B: TryFrom, - >::Error: Debug, -{ - type Error = ZReadOrDeserializeErrorTuple2; - - fn try_from(value: ZBytes) -> Result { - ZSerde.deserialize(&value) - } -} - -impl TryFrom<&ZBytes> for (A, B) -where - A: TryFrom, - >::Error: Debug, - B: TryFrom, - >::Error: Debug, -{ - type Error = ZReadOrDeserializeErrorTuple2; - - fn try_from(value: &ZBytes) -> Result { - ZSerde.deserialize(value) - } -} - -impl TryFrom<&mut ZBytes> for (A, B) -where - A: TryFrom, - >::Error: Debug, - B: TryFrom, - >::Error: Debug, -{ - type Error = ZReadOrDeserializeErrorTuple2; - - fn try_from(value: &mut ZBytes) -> Result { - ZSerde.deserialize(&*value) - } -} - -// Tuple (a, b, c) -macro_rules! impl_tuple3 { - ($t:expr) => {{ - let (a, b, c) = $t; - - let codec = Zenoh080::new(); - let mut buffer: ZBuf = ZBuf::empty(); - let mut writer = buffer.writer(); - let apld: ZBytes = a.into(); - let bpld: ZBytes = b.into(); - let cpld: ZBytes = c.into(); - - // SAFETY: we are serializing slices on a ZBuf, so serialization will never - // fail unless we run out of memory. In that case, Rust memory allocator - // will panic before the serializer has any chance to fail. - unsafe { - codec.write(&mut writer, &apld.0).unwrap_unchecked(); - codec.write(&mut writer, &bpld.0).unwrap_unchecked(); - codec.write(&mut writer, &cpld.0).unwrap_unchecked(); - } - - ZBytes::new(buffer) - }}; -} - -impl Serialize<(A, B, C)> for ZSerde -where - A: Into, - B: Into, - C: Into, -{ - type Output = ZBytes; - - fn serialize(self, t: (A, B, C)) -> Self::Output { - impl_tuple3!(t) - } -} - -impl Serialize<&(A, B, C)> for ZSerde -where - for<'a> &'a A: Into, - for<'b> &'b B: Into, - for<'b> &'b C: Into, -{ - type Output = ZBytes; - - fn serialize(self, t: &(A, B, C)) -> Self::Output { - impl_tuple3!(t) - } -} - -impl From<(A, B, C)> for ZBytes -where - A: Into, - B: Into, - C: Into, -{ - fn from(value: (A, B, C)) -> Self { - ZSerde.serialize(value) +impl From<&Cow<'_, str>> for ZBytes { + fn from(value: &Cow<'_, str>) -> Self { + value.clone().into() } } +// Define a transparent wrapper type to get around Rust's orphan rule. +// This allows to use bytes::Bytes directly as supporting buffer of a +// ZSlice resulting in zero-copy and zero-alloc bytes::Bytes serialization. +#[repr(transparent)] #[derive(Debug)] -pub enum ZReadOrDeserializeErrorTuple3 -where - A: TryFrom, - >::Error: Debug, - B: TryFrom, - >::Error: Debug, - C: TryFrom, - >::Error: Debug, -{ - One(ZReadOrDeserializeError), - Two(ZReadOrDeserializeError), - Three(ZReadOrDeserializeError), -} - -impl std::fmt::Display for ZReadOrDeserializeErrorTuple3 -where - A: Debug, - A: TryFrom, - >::Error: Debug, - B: Debug, - B: TryFrom, - >::Error: Debug, - C: Debug, - C: TryFrom, - >::Error: Debug, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - ZReadOrDeserializeErrorTuple3::One(e) => { - f.write_fmt(format_args!("1st tuple element: {}", e)) - } - ZReadOrDeserializeErrorTuple3::Two(e) => { - f.write_fmt(format_args!("2nd tuple element: {}", e)) - } - ZReadOrDeserializeErrorTuple3::Three(e) => { - f.write_fmt(format_args!("3rd tuple element: {}", e)) - } - } - } -} - -impl std::error::Error for ZReadOrDeserializeErrorTuple3 -where - A: Debug, - A: TryFrom, - >::Error: Debug, - B: Debug, - B: TryFrom, - >::Error: Debug, - C: Debug, - C: TryFrom, - >::Error: Debug, -{ -} - -impl Deserialize<(A, B, C)> for ZSerde -where - A: TryFrom, - >::Error: Debug, - B: TryFrom, - >::Error: Debug, - C: TryFrom, - >::Error: Debug, -{ - type Input<'a> = &'a ZBytes; - type Error = ZReadOrDeserializeErrorTuple3; - - fn deserialize(self, bytes: Self::Input<'_>) -> Result<(A, B, C), Self::Error> { - let codec = Zenoh080::new(); - let mut reader = bytes.0.reader(); - - let abuf: ZBuf = codec.read(&mut reader).map_err(|_| { - ZReadOrDeserializeErrorTuple3::One(ZReadOrDeserializeError::Read(ReadError)) - })?; - let apld = ZBytes::new(abuf); - let a = A::try_from(apld).map_err(|e| { - ZReadOrDeserializeErrorTuple3::One(ZReadOrDeserializeError::Deserialize(e)) - })?; - - let bbuf: ZBuf = codec.read(&mut reader).map_err(|_| { - ZReadOrDeserializeErrorTuple3::Two(ZReadOrDeserializeError::Read(ReadError)) - })?; - let bpld = ZBytes::new(bbuf); - let b = B::try_from(bpld).map_err(|e| { - ZReadOrDeserializeErrorTuple3::Two(ZReadOrDeserializeError::Deserialize(e)) - })?; - - let cbuf: ZBuf = codec.read(&mut reader).map_err(|_| { - ZReadOrDeserializeErrorTuple3::Three(ZReadOrDeserializeError::Read(ReadError)) - })?; - let cpld = ZBytes::new(cbuf); - let c = C::try_from(cpld).map_err(|e| { - ZReadOrDeserializeErrorTuple3::Three(ZReadOrDeserializeError::Deserialize(e)) - })?; - - Ok((a, b, c)) - } -} - -impl TryFrom for (A, B, C) -where - A: TryFrom, - >::Error: Debug, - B: TryFrom, - >::Error: Debug, - C: TryFrom, - >::Error: Debug, -{ - type Error = ZReadOrDeserializeErrorTuple3; - - fn try_from(value: ZBytes) -> Result { - ZSerde.deserialize(&value) - } -} - -impl TryFrom<&ZBytes> for (A, B, C) -where - A: TryFrom, - >::Error: Debug, - B: TryFrom, - >::Error: Debug, - C: TryFrom, - >::Error: Debug, -{ - type Error = ZReadOrDeserializeErrorTuple3; - - fn try_from(value: &ZBytes) -> Result { - ZSerde.deserialize(value) - } -} - -impl TryFrom<&mut ZBytes> for (A, B, C) -where - A: TryFrom, - >::Error: Debug, - B: TryFrom, - >::Error: Debug, - C: TryFrom, - >::Error: Debug, -{ - type Error = ZReadOrDeserializeErrorTuple3; - - fn try_from(value: &mut ZBytes) -> Result { - ZSerde.deserialize(&*value) +struct BytesWrap(bytes::Bytes); +impl ZSliceBuffer for BytesWrap { + fn as_slice(&self) -> &[u8] { + &self.0 } -} -// Tuple (a, b, c, d) -macro_rules! impl_tuple4 { - ($t:expr) => {{ - let (a, b, c, d) = $t; - - let codec = Zenoh080::new(); - let mut buffer: ZBuf = ZBuf::empty(); - let mut writer = buffer.writer(); - let apld: ZBytes = a.into(); - let bpld: ZBytes = b.into(); - let cpld: ZBytes = c.into(); - let dpld: ZBytes = d.into(); - - // SAFETY: we are serializing slices on a ZBuf, so serialization will never - // fail unless we run out of memory. In that case, Rust memory allocator - // will panic before the serializer has any chance to fail. - unsafe { - codec.write(&mut writer, &apld.0).unwrap_unchecked(); - codec.write(&mut writer, &bpld.0).unwrap_unchecked(); - codec.write(&mut writer, &cpld.0).unwrap_unchecked(); - codec.write(&mut writer, &dpld.0).unwrap_unchecked(); - } - - ZBytes::new(buffer) - }}; -} - -impl Serialize<(A, B, C, D)> for ZSerde -where - A: Into, - B: Into, - C: Into, - D: Into, -{ - type Output = ZBytes; - - fn serialize(self, t: (A, B, C, D)) -> Self::Output { - impl_tuple4!(t) + fn as_any(&self) -> &dyn std::any::Any { + self } -} -impl Serialize<&(A, B, C, D)> for ZSerde -where - for<'a> &'a A: Into, - for<'b> &'b B: Into, - for<'b> &'b C: Into, - for<'b> &'b D: Into, -{ - type Output = ZBytes; - - fn serialize(self, t: &(A, B, C, D)) -> Self::Output { - impl_tuple4!(t) + fn as_any_mut(&mut self) -> &mut dyn std::any::Any { + self } } - -impl From<(A, B, C, D)> for ZBytes -where - A: Into, - B: Into, - C: Into, - D: Into, -{ - fn from(value: (A, B, C, D)) -> Self { - ZSerde.serialize(value) +impl From for ZBytes { + fn from(value: bytes::Bytes) -> Self { + Self(BytesWrap(value).into()) } } -#[derive(Debug)] -pub enum ZReadOrDeserializeErrorTuple4 -where - A: TryFrom, - >::Error: Debug, - B: TryFrom, - >::Error: Debug, - C: TryFrom, - >::Error: Debug, - D: TryFrom, - >::Error: Debug, -{ - One(ZReadOrDeserializeError), - Two(ZReadOrDeserializeError), - Three(ZReadOrDeserializeError), - Four(ZReadOrDeserializeError), -} - -impl std::fmt::Display for ZReadOrDeserializeErrorTuple4 -where - A: Debug, - A: TryFrom, - >::Error: Debug, - B: Debug, - B: TryFrom, - >::Error: Debug, - C: Debug, - C: TryFrom, - >::Error: Debug, - D: Debug, - D: TryFrom, - >::Error: Debug, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - ZReadOrDeserializeErrorTuple4::One(e) => { - f.write_fmt(format_args!("1st tuple element: {}", e)) - } - ZReadOrDeserializeErrorTuple4::Two(e) => { - f.write_fmt(format_args!("2nd tuple element: {}", e)) - } - ZReadOrDeserializeErrorTuple4::Three(e) => { - f.write_fmt(format_args!("3rd tuple element: {}", e)) - } - ZReadOrDeserializeErrorTuple4::Four(e) => { - f.write_fmt(format_args!("4th tuple element: {}", e)) - } +#[cfg(all(feature = "unstable", feature = "shared-memory"))] +const _: () = { + use zenoh_shm::api::buffer::{zshm::ZShm, zshmmut::ZShmMut}; + impl From for ZBytes { + fn from(value: ZShm) -> Self { + Self(ZSlice::from(value).into()) } } -} - -impl std::error::Error for ZReadOrDeserializeErrorTuple4 -where - A: Debug, - A: TryFrom, - >::Error: Debug, - B: Debug, - B: TryFrom, - >::Error: Debug, - C: Debug, - C: TryFrom, - >::Error: Debug, - D: Debug, - D: TryFrom, - >::Error: Debug, -{ -} - -impl Deserialize<(A, B, C, D)> for ZSerde -where - A: TryFrom, - >::Error: Debug, - B: TryFrom, - >::Error: Debug, - C: TryFrom, - >::Error: Debug, - D: TryFrom, - >::Error: Debug, -{ - type Input<'a> = &'a ZBytes; - type Error = ZReadOrDeserializeErrorTuple4; - - fn deserialize(self, bytes: Self::Input<'_>) -> Result<(A, B, C, D), Self::Error> { - let codec = Zenoh080::new(); - let mut reader = bytes.0.reader(); - - let abuf: ZBuf = codec.read(&mut reader).map_err(|_| { - ZReadOrDeserializeErrorTuple4::One(ZReadOrDeserializeError::Read(ReadError)) - })?; - let apld = ZBytes::new(abuf); - let a = A::try_from(apld).map_err(|e| { - ZReadOrDeserializeErrorTuple4::One(ZReadOrDeserializeError::Deserialize(e)) - })?; - - let bbuf: ZBuf = codec.read(&mut reader).map_err(|_| { - ZReadOrDeserializeErrorTuple4::Two(ZReadOrDeserializeError::Read(ReadError)) - })?; - let bpld = ZBytes::new(bbuf); - let b = B::try_from(bpld).map_err(|e| { - ZReadOrDeserializeErrorTuple4::Two(ZReadOrDeserializeError::Deserialize(e)) - })?; - - let cbuf: ZBuf = codec.read(&mut reader).map_err(|_| { - ZReadOrDeserializeErrorTuple4::Three(ZReadOrDeserializeError::Read(ReadError)) - })?; - let cpld = ZBytes::new(cbuf); - let c = C::try_from(cpld).map_err(|e| { - ZReadOrDeserializeErrorTuple4::Three(ZReadOrDeserializeError::Deserialize(e)) - })?; - - let dbuf: ZBuf = codec.read(&mut reader).map_err(|_| { - ZReadOrDeserializeErrorTuple4::Four(ZReadOrDeserializeError::Read(ReadError)) - })?; - let dpld = ZBytes::new(dbuf); - let d = D::try_from(dpld).map_err(|e| { - ZReadOrDeserializeErrorTuple4::Four(ZReadOrDeserializeError::Deserialize(e)) - })?; - - Ok((a, b, c, d)) - } -} - -impl TryFrom for (A, B, C, D) -where - A: TryFrom, - >::Error: Debug, - B: TryFrom, - >::Error: Debug, - C: TryFrom, - >::Error: Debug, - D: TryFrom, - >::Error: Debug, -{ - type Error = ZReadOrDeserializeErrorTuple4; - - fn try_from(value: ZBytes) -> Result { - ZSerde.deserialize(&value) - } -} - -impl TryFrom<&ZBytes> for (A, B, C, D) -where - A: TryFrom, - >::Error: Debug, - B: TryFrom, - >::Error: Debug, - C: TryFrom, - >::Error: Debug, - D: TryFrom, - >::Error: Debug, -{ - type Error = ZReadOrDeserializeErrorTuple4; - - fn try_from(value: &ZBytes) -> Result { - ZSerde.deserialize(value) - } -} - -impl TryFrom<&mut ZBytes> for (A, B, C, D) -where - A: TryFrom, - >::Error: Debug, - B: TryFrom, - >::Error: Debug, - C: TryFrom, - >::Error: Debug, - D: TryFrom, - >::Error: Debug, -{ - type Error = ZReadOrDeserializeErrorTuple4; - - fn try_from(value: &mut ZBytes) -> Result { - ZSerde.deserialize(&*value) - } -} - -// HashMap -impl Serialize> for ZSerde -where - A: Into, - B: Into, -{ - type Output = ZBytes; - - fn serialize(self, mut t: HashMap) -> Self::Output { - ZBytes::from_iter(t.drain()) - } -} - -impl Serialize<&HashMap> for ZSerde -where - for<'a> &'a A: Into, - for<'b> &'b B: Into, -{ - type Output = ZBytes; - - fn serialize(self, t: &HashMap) -> Self::Output { - ZBytes::from_iter(t.iter()) - } -} - -impl From> for ZBytes -where - A: Into, - B: Into, -{ - fn from(value: HashMap) -> Self { - ZSerde.serialize(value) - } -} - -impl Deserialize> for ZSerde -where - A: TryFrom + Debug + std::cmp::Eq + std::hash::Hash, - >::Error: Debug, - B: TryFrom + Debug, - >::Error: Debug, -{ - type Input<'a> = &'a ZBytes; - type Error = ZReadOrDeserializeErrorTuple2; - - fn deserialize(self, bytes: Self::Input<'_>) -> Result, Self::Error> { - let mut hm = HashMap::new(); - for res in bytes.iter::<(A, B)>() { - let (k, v) = res?; - hm.insert(k, v); + impl From for ZBytes { + fn from(value: ZShmMut) -> Self { + Self(ZSlice::from(value).into()) } - Ok(hm) - } -} - -impl TryFrom for HashMap -where - A: TryFrom + Debug + std::cmp::Eq + std::hash::Hash, - >::Error: Debug, - B: TryFrom + Debug, - >::Error: Debug, -{ - type Error = ZReadOrDeserializeErrorTuple2; - - fn try_from(value: ZBytes) -> Result { - ZSerde.deserialize(&value) - } -} - -impl TryFrom<&ZBytes> for HashMap -where - A: TryFrom + Debug + std::cmp::Eq + std::hash::Hash, - >::Error: Debug, - B: TryFrom + Debug, - >::Error: Debug, -{ - type Error = ZReadOrDeserializeErrorTuple2; - - fn try_from(value: &ZBytes) -> Result { - ZSerde.deserialize(value) - } -} - -impl TryFrom<&mut ZBytes> for HashMap -where - A: TryFrom + Debug + std::cmp::Eq + std::hash::Hash, - >::Error: Debug, - B: TryFrom + Debug, - >::Error: Debug, -{ - type Error = ZReadOrDeserializeErrorTuple2; - - fn try_from(value: &mut ZBytes) -> Result { - ZSerde.deserialize(&*value) } -} +}; // Protocol attachment extension impl From for AttachmentType { @@ -3365,312 +477,3 @@ impl From> for ZBytes { this.buffer.into() } } - -mod tests { - - #[test] - fn serializer() { - use std::borrow::Cow; - - use rand::Rng; - use zenoh_buffers::{ZBuf, ZSlice}; - use zenoh_protocol::core::Parameters; - #[cfg(feature = "shared-memory")] - use zenoh_shm::api::{ - buffer::zshm::{zshm, ZShm}, - protocol_implementations::posix::{ - posix_shm_provider_backend::PosixShmProviderBackend, protocol_id::POSIX_PROTOCOL_ID, - }, - provider::shm_provider::ShmProviderBuilder, - }; - - use super::ZBytes; - use crate::bytes::{Deserialize, Serialize, ZSerde}; - #[cfg(feature = "shared-memory")] - use crate::zenoh_core::Wait; - - const NUM: usize = 1_000; - - macro_rules! serialize_deserialize { - ($t:ty, $in:expr) => { - let i = $in; - let t = i.clone(); - println!("Serialize:\t{:?}", t); - let v = ZBytes::serialize(t); - println!("Deserialize:\t{:?}", v); - let o: $t = v.deserialize().unwrap(); - assert_eq!(i, o); - println!(""); - }; - } - - // WARN: test function body produces stack overflow, so I split it into subroutines - #[inline(never)] - fn numeric() { - let mut rng = rand::thread_rng(); - - // unsigned integer - serialize_deserialize!(u8, u8::MIN); - serialize_deserialize!(u16, u16::MIN); - serialize_deserialize!(u32, u32::MIN); - serialize_deserialize!(u64, u64::MIN); - serialize_deserialize!(usize, usize::MIN); - - serialize_deserialize!(u8, u8::MAX); - serialize_deserialize!(u16, u16::MAX); - serialize_deserialize!(u32, u32::MAX); - serialize_deserialize!(u64, u64::MAX); - serialize_deserialize!(usize, usize::MAX); - - for _ in 0..NUM { - serialize_deserialize!(u8, rng.gen::()); - serialize_deserialize!(u16, rng.gen::()); - serialize_deserialize!(u32, rng.gen::()); - serialize_deserialize!(u64, rng.gen::()); - serialize_deserialize!(usize, rng.gen::()); - } - - // signed integer - serialize_deserialize!(i8, i8::MIN); - serialize_deserialize!(i16, i16::MIN); - serialize_deserialize!(i32, i32::MIN); - serialize_deserialize!(i64, i64::MIN); - serialize_deserialize!(isize, isize::MIN); - - serialize_deserialize!(i8, i8::MAX); - serialize_deserialize!(i16, i16::MAX); - serialize_deserialize!(i32, i32::MAX); - serialize_deserialize!(i64, i64::MAX); - serialize_deserialize!(isize, isize::MAX); - - for _ in 0..NUM { - serialize_deserialize!(i8, rng.gen::()); - serialize_deserialize!(i16, rng.gen::()); - serialize_deserialize!(i32, rng.gen::()); - serialize_deserialize!(i64, rng.gen::()); - serialize_deserialize!(isize, rng.gen::()); - } - - // float - serialize_deserialize!(f32, f32::MIN); - serialize_deserialize!(f64, f64::MIN); - - serialize_deserialize!(f32, f32::MAX); - serialize_deserialize!(f64, f64::MAX); - - for _ in 0..NUM { - serialize_deserialize!(f32, rng.gen::()); - serialize_deserialize!(f64, rng.gen::()); - } - } - numeric(); - - // WARN: test function body produces stack overflow, so I split it into subroutines - #[inline(never)] - fn basic() { - let mut rng = rand::thread_rng(); - - // bool - serialize_deserialize!(bool, true); - serialize_deserialize!(bool, false); - - // char - serialize_deserialize!(char, char::MAX); - serialize_deserialize!(char, rng.gen::()); - - let a = 'a'; - let bytes = ZSerde.serialize(a); - let s: String = ZSerde.deserialize(&bytes).unwrap(); - assert_eq!(a.to_string(), s); - - let a = String::from("a"); - let bytes = ZSerde.serialize(&a); - let s: char = ZSerde.deserialize(&bytes).unwrap(); - assert_eq!(a, s.to_string()); - - // String - serialize_deserialize!(String, ""); - serialize_deserialize!(String, String::from("abcdef")); - - // Cow - serialize_deserialize!(Cow, Cow::from("")); - serialize_deserialize!(Cow, Cow::from(String::from("abcdef"))); - - // Vec - serialize_deserialize!(Vec, vec![0u8; 0]); - serialize_deserialize!(Vec, vec![0u8; 64]); - - // Cow<[u8]> - serialize_deserialize!(Cow<[u8]>, Cow::from(vec![0u8; 0])); - serialize_deserialize!(Cow<[u8]>, Cow::from(vec![0u8; 64])); - - // ZBuf - serialize_deserialize!(ZBuf, ZBuf::from(vec![0u8; 0])); - serialize_deserialize!(ZBuf, ZBuf::from(vec![0u8; 64])); - } - basic(); - - // WARN: test function body produces stack overflow, so I split it into subroutines - #[inline(never)] - fn reader_writer() { - let mut bytes = ZBytes::empty(); - let mut writer = bytes.writer(); - - let i1 = 1_u8; - let i2 = String::from("abcdef"); - let i3 = vec![2u8; 64]; - - println!("Write: {:?}", i1); - writer.serialize(i1); - println!("Write: {:?}", i2); - writer.serialize(&i2); - println!("Write: {:?}", i3); - writer.serialize(&i3); - - let mut reader = bytes.reader(); - let o1: u8 = reader.deserialize().unwrap(); - println!("Read: {:?}", o1); - let o2: String = reader.deserialize().unwrap(); - println!("Read: {:?}", o2); - let o3: Vec = reader.deserialize().unwrap(); - println!("Read: {:?}", o3); - - println!(); - - assert_eq!(i1, o1); - assert_eq!(i2, o2); - assert_eq!(i3, o3); - } - reader_writer(); - - // SHM - #[cfg(feature = "shared-memory")] - fn shm() { - // create an SHM backend... - let backend = PosixShmProviderBackend::builder() - .with_size(4096) - .unwrap() - .wait() - .unwrap(); - // ...and an SHM provider - let provider = ShmProviderBuilder::builder() - .protocol_id::() - .backend(backend) - .wait(); - - // Prepare a layout for allocations - let layout = provider.alloc(1024).into_layout().unwrap(); - - // allocate an SHM buffer - let mutable_shm_buf = layout.alloc().wait().unwrap(); - - // convert to immutable SHM buffer - let immutable_shm_buf: ZShm = mutable_shm_buf.into(); - - serialize_deserialize!(&zshm, immutable_shm_buf); - } - #[cfg(feature = "shared-memory")] - shm(); - - // Parameters - serialize_deserialize!(Parameters, Parameters::from("")); - serialize_deserialize!(Parameters, Parameters::from("a=1;b=2;c3")); - - // Bytes - serialize_deserialize!(bytes::Bytes, bytes::Bytes::from(vec![1, 2, 3, 4])); - serialize_deserialize!(bytes::Bytes, bytes::Bytes::from("Hello World")); - - // Tuple - serialize_deserialize!((usize, usize), (0, 1)); - serialize_deserialize!((usize, String), (0, String::from("a"))); - serialize_deserialize!((String, String), (String::from("a"), String::from("b"))); - serialize_deserialize!( - (Cow<'static, [u8]>, Cow<'static, [u8]>), - (Cow::from(vec![0u8; 8]), Cow::from(vec![0u8; 8])) - ); - serialize_deserialize!( - (Cow<'static, str>, Cow<'static, str>), - (Cow::from("a"), Cow::from("b")) - ); - - fn iterator() { - let v: [usize; 5] = [0, 1, 2, 3, 4]; - println!("Serialize:\t{:?}", v); - let p = ZBytes::from_iter(v.iter()); - println!("Deserialize:\t{:?}\n", p); - for (i, t) in p.iter::().enumerate() { - assert_eq!(i, t.unwrap()); - } - - let mut v = vec![[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]]; - println!("Serialize:\t{:?}", v); - let p = ZBytes::from_iter(v.drain(..)); - println!("Deserialize:\t{:?}\n", p); - let mut iter = p.iter::<[u8; 4]>(); - assert_eq!(iter.next().unwrap().unwrap(), [0, 1, 2, 3]); - assert_eq!(iter.next().unwrap().unwrap(), [4, 5, 6, 7]); - assert_eq!(iter.next().unwrap().unwrap(), [8, 9, 10, 11]); - assert_eq!(iter.next().unwrap().unwrap(), [12, 13, 14, 15]); - assert!(iter.next().is_none()); - } - iterator(); - - fn hashmap() { - use std::collections::HashMap; - let mut hm: HashMap = HashMap::new(); - hm.insert(0, 0); - hm.insert(1, 1); - println!("Serialize:\t{:?}", hm); - let p = ZBytes::from(hm.clone()); - println!("Deserialize:\t{:?}\n", p); - let o = p.deserialize::>().unwrap(); - assert_eq!(hm, o); - - let mut hm: HashMap> = HashMap::new(); - hm.insert(0, vec![0u8; 8]); - hm.insert(1, vec![1u8; 16]); - println!("Serialize:\t{:?}", hm); - let p = ZBytes::from(hm.clone()); - println!("Deserialize:\t{:?}\n", p); - let o = p.deserialize::>>().unwrap(); - assert_eq!(hm, o); - - let mut hm: HashMap = HashMap::new(); - hm.insert(0, ZSlice::from(vec![0u8; 8])); - hm.insert(1, ZSlice::from(vec![1u8; 16])); - println!("Serialize:\t{:?}", hm); - let p = ZBytes::from(hm.clone()); - println!("Deserialize:\t{:?}\n", p); - let o = p.deserialize::>().unwrap(); - assert_eq!(hm, o); - - let mut hm: HashMap = HashMap::new(); - hm.insert(0, ZBuf::from(vec![0u8; 8])); - hm.insert(1, ZBuf::from(vec![1u8; 16])); - println!("Serialize:\t{:?}", hm); - let p = ZBytes::from(hm.clone()); - println!("Deserialize:\t{:?}\n", p); - let o = p.deserialize::>().unwrap(); - 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 = ZBytes::from(hm.clone()); - println!("Deserialize:\t{:?}\n", p); - let o = p.deserialize::>().unwrap(); - assert_eq!(hm, o); - - let mut hm: HashMap, Cow<'static, str>> = HashMap::new(); - hm.insert(Cow::from("0"), Cow::from("a")); - hm.insert(Cow::from("1"), Cow::from("b")); - println!("Serialize:\t{:?}", hm); - let p = ZBytes::from(hm.clone()); - println!("Deserialize:\t{:?}\n", p); - let o = p.deserialize::, Cow>>().unwrap(); - assert_eq!(hm, o); - } - hashmap(); - } -} diff --git a/zenoh/src/api/publisher.rs b/zenoh/src/api/publisher.rs index efe74a9c1a..4e38a183f7 100644 --- a/zenoh/src/api/publisher.rs +++ b/zenoh/src/api/publisher.rs @@ -909,7 +909,7 @@ mod tests { assert_eq!(sample.kind, kind); if let SampleKind::Put = kind { - assert_eq!(sample.payload.deserialize::().unwrap(), VALUE); + assert_eq!(sample.payload.try_to_string().unwrap(), VALUE); } } @@ -936,7 +936,7 @@ mod tests { assert_eq!(sample.kind, kind); if let SampleKind::Put = kind { - assert_eq!(sample.payload.deserialize::().unwrap(), VALUE); + assert_eq!(sample.payload.try_to_string().unwrap(), VALUE); } } diff --git a/zenoh/src/api/session.rs b/zenoh/src/api/session.rs index 083d1d474a..1147b3aa07 100644 --- a/zenoh/src/api/session.rs +++ b/zenoh/src/api/session.rs @@ -1613,7 +1613,7 @@ impl SessionInner { for token in known_tokens { callback.call(Sample { key_expr: token, - payload: ZBytes::empty(), + payload: ZBytes::new(), kind: SampleKind::Put, encoding: Encoding::default(), timestamp: None, @@ -2378,7 +2378,7 @@ impl Primitives for WeakSession { let reply = Reply { result: Ok(Sample { key_expr, - payload: ZBytes::empty(), + payload: ZBytes::new(), kind: SampleKind::Put, encoding: Encoding::default(), timestamp: None, diff --git a/zenoh/src/api/value.rs b/zenoh/src/api/value.rs index 88470b3360..3bb2c7d467 100644 --- a/zenoh/src/api/value.rs +++ b/zenoh/src/api/value.rs @@ -38,7 +38,7 @@ impl Value { /// Creates an empty [`Value`]. pub const fn empty() -> Self { Value { - payload: ZBytes::empty(), + payload: ZBytes::new(), encoding: Encoding::default(), } } diff --git a/zenoh/src/lib.rs b/zenoh/src/lib.rs index d004338b76..e0abc0c186 100644 --- a/zenoh/src/lib.rs +++ b/zenoh/src/lib.rs @@ -214,10 +214,7 @@ pub mod sample { /// Payload primitives pub mod bytes { pub use crate::api::{ - bytes::{ - Deserialize, OptionZBytes, Serialize, ZBytes, ZBytesIterator, ZBytesReader, - ZBytesSliceIterator, ZBytesWriter, ZDeserializeError, ZSerde, - }, + bytes::{OptionZBytes, ZBytes, ZBytesReader, ZBytesSliceIterator, ZBytesWriter}, encoding::Encoding, }; } diff --git a/zenoh/src/net/runtime/adminspace.rs b/zenoh/src/net/runtime/adminspace.rs index 657bf8bf05..f8cc3a4425 100644 --- a/zenoh/src/net/runtime/adminspace.rs +++ b/zenoh/src/net/runtime/adminspace.rs @@ -616,8 +616,8 @@ fn local_data(context: &AdminContext, query: Query) { } tracing::trace!("AdminSpace router_data: {:?}", json); - let payload = match ZBytes::try_from(json) { - Ok(p) => p, + let payload = match serde_json::to_vec(&json) { + Ok(bytes) => ZBytes::from(bytes), Err(e) => { tracing::error!("Error serializing AdminSpace reply: {:?}", e); return; @@ -767,11 +767,10 @@ fn plugins_data(context: &AdminContext, query: Query) { for status in statuses { tracing::debug!("plugin status: {:?}", status); let key = root_key.join(status.id()).unwrap(); - let status = serde_json::to_value(status).unwrap(); - match ZBytes::try_from(status) { - Ok(zbuf) => { + match serde_json::to_vec(&status) { + Ok(bytes) => { if let Err(e) = query - .reply(key, zbuf) + .reply(key, bytes) .encoding(Encoding::APPLICATION_JSON) .wait() { @@ -825,13 +824,14 @@ fn plugins_status(context: &AdminContext, query: Query) { Ok(Ok(responses)) => { for response in responses { if let Ok(key_expr) = KeyExpr::try_from(response.key) { - match ZBytes::try_from(response.value) { - Ok(zbuf) => { - if let Err(e) = query.reply(key_expr, zbuf).encoding(Encoding::APPLICATION_JSON).wait() { + match serde_json::to_vec(&response.value) { + Ok(bytes) => { + if let Err(e) = query.reply(key_expr, bytes).encoding(Encoding::APPLICATION_JSON).wait() { tracing::error!("Error sending AdminSpace reply: {:?}", e); } - }, + } Err(e) => tracing::debug!("Admin query error: {}", e), + } } else { tracing::error!("Error: plugin {} replied with an invalid key", plugin_key); diff --git a/zenoh/tests/acl.rs b/zenoh/tests/acl.rs index 389abfa47a..da55c191b0 100644 --- a/zenoh/tests/acl.rs +++ b/zenoh/tests/acl.rs @@ -141,7 +141,7 @@ mod test { .callback(move |sample| { if sample.kind() == SampleKind::Put { let mut temp_value = zlock!(temp_recv_value); - *temp_value = sample.payload().deserialize::().unwrap(); + *temp_value = sample.payload().try_to_string().unwrap().into_owned(); } else if sample.kind() == SampleKind::Delete { let mut deleted = zlock!(deleted_clone); *deleted = true; @@ -195,7 +195,7 @@ mod test { .callback(move |sample| { if sample.kind() == SampleKind::Put { let mut temp_value = zlock!(temp_recv_value); - *temp_value = sample.payload().deserialize::().unwrap(); + *temp_value = sample.payload().try_to_string().unwrap().into_owned(); } else if sample.kind() == SampleKind::Delete { let mut deleted = zlock!(deleted_clone); *deleted = true; @@ -277,7 +277,7 @@ mod test { .callback(move |sample| { if sample.kind() == SampleKind::Put { let mut temp_value = zlock!(temp_recv_value); - *temp_value = sample.payload().deserialize::().unwrap(); + *temp_value = sample.payload().try_to_string().unwrap().into_owned(); } else if sample.kind() == SampleKind::Delete { let mut deleted = zlock!(deleted_clone); *deleted = true; @@ -358,7 +358,7 @@ mod test { .callback(move |sample| { if sample.kind() == SampleKind::Put { let mut temp_value = zlock!(temp_recv_value); - *temp_value = sample.payload().deserialize::().unwrap(); + *temp_value = sample.payload().try_to_string().unwrap().into_owned(); } else if sample.kind() == SampleKind::Delete { let mut deleted = zlock!(deleted_clone); *deleted = true; @@ -436,7 +436,7 @@ mod test { while let Ok(reply) = ztimeout!(recv_reply.recv_async()) { match reply.result() { Ok(sample) => { - received_value = sample.payload().deserialize::().unwrap(); + received_value = sample.payload().try_to_string().unwrap().into_owned(); break; } Err(e) => println!("Error : {:?}", e), @@ -490,7 +490,7 @@ mod test { while let Ok(reply) = ztimeout!(recv_reply.recv_async()) { match reply.result() { Ok(sample) => { - received_value = sample.payload().deserialize::().unwrap(); + received_value = sample.payload().try_to_string().unwrap().into_owned(); break; } Err(e) => println!("Error : {:?}", e), @@ -571,7 +571,7 @@ mod test { while let Ok(reply) = ztimeout!(recv_reply.recv_async()) { match reply.result() { Ok(sample) => { - received_value = sample.payload().deserialize::().unwrap(); + received_value = sample.payload().try_to_string().unwrap().into_owned(); break; } Err(e) => println!("Error : {:?}", e), @@ -650,7 +650,7 @@ mod test { while let Ok(reply) = ztimeout!(recv_reply.recv_async()) { match reply.result() { Ok(sample) => { - received_value = sample.payload().deserialize::().unwrap(); + received_value = sample.payload().try_to_string().unwrap().into_owned(); break; } Err(e) => println!("Error : {:?}", e), @@ -718,7 +718,7 @@ mod test { while let Ok(reply) = ztimeout!(recv_reply.recv_async()) { match reply.result() { Ok(sample) => { - received_value = sample.payload().deserialize::().unwrap(); + received_value = sample.payload().try_to_string().unwrap().into_owned(); break; } Err(e) => println!("Error : {:?}", e), @@ -792,7 +792,7 @@ mod test { while let Ok(reply) = ztimeout!(recv_reply.recv_async()) { match reply.result() { Ok(sample) => { - received_value = sample.payload().deserialize::().unwrap(); + received_value = sample.payload().try_to_string().unwrap().into_owned(); break; } Err(e) => println!("Error : {:?}", e), diff --git a/zenoh/tests/attachments.rs b/zenoh/tests/attachments.rs index dd9e287428..d85344d3d8 100644 --- a/zenoh/tests/attachments.rs +++ b/zenoh/tests/attachments.rs @@ -11,49 +11,30 @@ // Contributors: // ZettaScale Zenoh Team, // -#![cfg(feature = "unstable")] -use zenoh::{bytes::ZBytes, config::Config, Wait}; +use zenoh::{config::Config, Wait}; #[test] fn attachment_pubsub() { let zenoh = zenoh::open(Config::default()).wait().unwrap(); - let _sub = zenoh + const ATTACHMENT: &[u8] = b"pubsub attachment"; + zenoh .declare_subscriber("test/attachment") .callback(|sample| { - println!("{}", sample.payload().deserialize::().unwrap()); - for (k, v) in sample - .attachment() - .unwrap() - .iter::<( - [u8; std::mem::size_of::()], - [u8; std::mem::size_of::()], - )>() - .map(Result::unwrap) - { - assert!(k.iter().rev().zip(v.as_slice()).all(|(k, v)| k == v)) - } + println!("{}", sample.payload().try_to_string().unwrap()); + assert_eq!(sample.attachment().unwrap().to_bytes(), ATTACHMENT); }) .wait() .unwrap(); - let publisher = zenoh.declare_publisher("test/attachment").wait().unwrap(); - for i in 0..10 { - let mut backer = [( - [0; std::mem::size_of::()], - [0; std::mem::size_of::()], - ); 10]; - for (j, backer) in backer.iter_mut().enumerate() { - *backer = ((i * 10 + j).to_le_bytes(), (i * 10 + j).to_be_bytes()) - } - + for _ in 0..10 { zenoh .put("test/attachment", "put") - .attachment(ZBytes::from_iter(backer.iter())) + .attachment(ATTACHMENT) .wait() .unwrap(); publisher .put("publisher") - .attachment(ZBytes::from_iter(backer.iter())) + .attachment(ATTACHMENT) .wait() .unwrap(); } @@ -62,71 +43,31 @@ fn attachment_pubsub() { #[test] fn attachment_queries() { let zenoh = zenoh::open(Config::default()).wait().unwrap(); - let _sub = zenoh + const QUERY_ATTACHMENT: &[u8] = b"query attachment"; + const REPLY_ATTACHMENT: &[u8] = b"reply attachment"; + zenoh .declare_queryable("test/attachment") .callback(|query| { - let s = query - .payload() - .map(|p| p.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::()], - )>() - .map(Result::unwrap) - { - assert!(k.iter().rev().zip(v.as_slice()).all(|(k, v)| k == v)); - } - + println!("{}", query.payload().unwrap().try_to_string().unwrap()); + assert_eq!(query.attachment().unwrap().to_bytes(), QUERY_ATTACHMENT); query .reply(query.key_expr().clone(), query.payload().unwrap().clone()) - .attachment(ZBytes::from_iter( - attachment - .iter::<( - [u8; std::mem::size_of::()], - [u8; std::mem::size_of::()], - )>() - .map(Result::unwrap) - .map(|(k, _)| (k, k)), - )) + .attachment(REPLY_ATTACHMENT) .wait() .unwrap(); }) .wait() .unwrap(); - for i in 0..10 { - let mut backer = [( - [0; std::mem::size_of::()], - [0; std::mem::size_of::()], - ); 10]; - for (j, backer) in backer.iter_mut().enumerate() { - *backer = ((i * 10 + j).to_le_bytes(), (i * 10 + j).to_be_bytes()) - } - + for _ in 0..10 { let get = zenoh .get("test/attachment") .payload("query") - .attachment(ZBytes::from_iter(backer.iter())) + .attachment(QUERY_ATTACHMENT) .wait() .unwrap(); while let Ok(reply) = get.recv() { let response = reply.result().unwrap(); - for (k, v) in response - .attachment() - .unwrap() - .iter::<( - [u8; std::mem::size_of::()], - [u8; std::mem::size_of::()], - )>() - .map(Result::unwrap) - { - assert_eq!(k, v) - } + assert_eq!(response.attachment().unwrap().to_bytes(), REPLY_ATTACHMENT); } } } diff --git a/zenoh/tests/authentication.rs b/zenoh/tests/authentication.rs index 3d6579d6a4..cd9b3848d2 100644 --- a/zenoh/tests/authentication.rs +++ b/zenoh/tests/authentication.rs @@ -901,7 +901,7 @@ client2name:client2passwd"; .declare_subscriber(KEY_EXPR) .callback(move |sample| { let mut temp_value = zlock!(temp_recv_value); - *temp_value = sample.payload().deserialize::().unwrap(); + *temp_value = sample.payload().try_to_string().unwrap().into_owned(); }) .await .unwrap(); @@ -969,7 +969,7 @@ client2name:client2passwd"; .declare_subscriber(KEY_EXPR) .callback(move |sample| { let mut temp_value = zlock!(temp_recv_value); - *temp_value = sample.payload().deserialize::().unwrap(); + *temp_value = sample.payload().try_to_string().unwrap().into_owned(); })) .unwrap(); @@ -1052,14 +1052,14 @@ client2name:client2passwd"; while let Ok(reply) = ztimeout!(recv_reply.recv_async()) { match reply.result() { Ok(sample) => { - received_value = sample.payload().deserialize::().unwrap(); + received_value = sample.payload().try_to_string().unwrap().into_owned(); break; } Err(e) => println!( "Error : {}", e.payload() - .deserialize::() - .unwrap_or_else(|e| format!("{}", e)) + .try_to_string() + .unwrap_or_else(|e| e.to_string().into()) ), } } @@ -1137,14 +1137,14 @@ client2name:client2passwd"; while let Ok(reply) = ztimeout!(recv_reply.recv_async()) { match reply.result() { Ok(sample) => { - received_value = sample.payload().deserialize::().unwrap(); + received_value = sample.payload().try_to_string().unwrap().into_owned(); break; } Err(e) => println!( "Error : {}", e.payload() - .deserialize::() - .unwrap_or_else(|e| format!("{}", e)) + .try_to_string() + .unwrap_or_else(|e| e.to_string().into()) ), } } @@ -1211,7 +1211,7 @@ client2name:client2passwd"; .declare_subscriber(KEY_EXPR) .callback(move |sample| { let mut temp_value = zlock!(temp_recv_value); - *temp_value = sample.payload().deserialize::().unwrap(); + *temp_value = sample.payload().try_to_string().unwrap().into_owned(); }) .await .unwrap(); @@ -1281,7 +1281,7 @@ client2name:client2passwd"; .declare_subscriber(KEY_EXPR) .callback(move |sample| { let mut temp_value = zlock!(temp_recv_value); - *temp_value = sample.payload().deserialize::().unwrap(); + *temp_value = sample.payload().try_to_string().unwrap().into_owned(); })) .unwrap(); @@ -1365,14 +1365,14 @@ client2name:client2passwd"; while let Ok(reply) = ztimeout!(recv_reply.recv_async()) { match reply.result() { Ok(sample) => { - received_value = sample.payload().deserialize::().unwrap(); + received_value = sample.payload().try_to_string().unwrap().into_owned(); break; } Err(e) => println!( "Error : {}", e.payload() - .deserialize::() - .unwrap_or_else(|e| format!("{}", e)) + .try_to_string() + .unwrap_or_else(|e| e.to_string().into()) ), } } @@ -1451,14 +1451,14 @@ client2name:client2passwd"; while let Ok(reply) = ztimeout!(recv_reply.recv_async()) { match reply.result() { Ok(sample) => { - received_value = sample.payload().deserialize::().unwrap(); + received_value = sample.payload().try_to_string().unwrap().into_owned(); break; } Err(e) => println!( "Error : {}", e.payload() - .deserialize::() - .unwrap_or_else(|e| format!("{}", e)) + .try_to_string() + .unwrap_or_else(|e| e.to_string().into()) ), } } @@ -1526,7 +1526,7 @@ client2name:client2passwd"; .declare_subscriber(KEY_EXPR) .callback(move |sample| { let mut temp_value = zlock!(temp_recv_value); - *temp_value = sample.payload().deserialize::().unwrap(); + *temp_value = sample.payload().try_to_string().unwrap().into_owned(); }) .await .unwrap(); @@ -1596,7 +1596,7 @@ client2name:client2passwd"; .declare_subscriber(KEY_EXPR) .callback(move |sample| { let mut temp_value = zlock!(temp_recv_value); - *temp_value = sample.payload().deserialize::().unwrap(); + *temp_value = sample.payload().try_to_string().unwrap().into_owned(); })) .unwrap(); @@ -1680,14 +1680,14 @@ client2name:client2passwd"; while let Ok(reply) = ztimeout!(recv_reply.recv_async()) { match reply.result() { Ok(sample) => { - received_value = sample.payload().deserialize::().unwrap(); + received_value = sample.payload().try_to_string().unwrap().into_owned(); break; } Err(e) => println!( "Error : {}", e.payload() - .deserialize::() - .unwrap_or_else(|e| format!("{}", e)) + .try_to_string() + .unwrap_or_else(|e| e.to_string().into()) ), } } @@ -1766,14 +1766,14 @@ client2name:client2passwd"; while let Ok(reply) = ztimeout!(recv_reply.recv_async()) { match reply.result() { Ok(sample) => { - received_value = sample.payload().deserialize::().unwrap(); + received_value = sample.payload().try_to_string().unwrap().into_owned(); break; } Err(e) => println!( "Error : {}", e.payload() - .deserialize::() - .unwrap_or_else(|e| format!("{}", e)) + .try_to_string() + .unwrap_or_else(|e| e.to_string().into()) ), } } @@ -1843,7 +1843,7 @@ client2name:client2passwd"; .declare_subscriber(KEY_EXPR) .callback(move |sample| { let mut temp_value = zlock!(temp_recv_value); - *temp_value = sample.payload().deserialize::().unwrap(); + *temp_value = sample.payload().try_to_string().unwrap().into_owned(); })) .unwrap(); @@ -1866,7 +1866,7 @@ client2name:client2passwd"; .declare_subscriber(KEY_EXPR) .callback(move |sample| { let mut temp_value = zlock!(temp_recv_value); - *temp_value = sample.payload().deserialize::().unwrap(); + *temp_value = sample.payload().try_to_string().unwrap().into_owned(); })) .unwrap(); @@ -1939,7 +1939,7 @@ client2name:client2passwd"; .declare_subscriber(KEY_EXPR) .callback(move |sample| { let mut temp_value = zlock!(temp_recv_value); - *temp_value = sample.payload().deserialize::().unwrap(); + *temp_value = sample.payload().try_to_string().unwrap().into_owned(); })) .unwrap(); @@ -1962,7 +1962,7 @@ client2name:client2passwd"; .declare_subscriber(KEY_EXPR) .callback(move |sample| { let mut temp_value = zlock!(temp_recv_value); - *temp_value = sample.payload().deserialize::().unwrap(); + *temp_value = sample.payload().try_to_string().unwrap().into_owned(); })) .unwrap(); diff --git a/zenoh/tests/bytes.rs b/zenoh/tests/bytes.rs index c9a2e016f4..9b0fbf0a8a 100644 --- a/zenoh/tests/bytes.rs +++ b/zenoh/tests/bytes.rs @@ -14,10 +14,7 @@ #![cfg(all(feature = "shared-memory", feature = "unstable"))] use zenoh::{ bytes::ZBytes, - shm::{ - zshm, zshmmut, PosixShmProviderBackend, ShmProviderBuilder, ZShm, ZShmMut, - POSIX_PROTOCOL_ID, - }, + shm::{zshmmut, PosixShmProviderBackend, ShmProviderBuilder, ZShm, ZShmMut, POSIX_PROTOCOL_ID}, Wait, }; @@ -53,7 +50,7 @@ fn shm_bytes_single_buf() { // branch to illustrate immutable access to SHM data { // deserialize ZBytes as an immutably borrowed zshm (ZBytes -> &zshm) - let borrowed_shm_buf: &zshm = payload.deserialize().unwrap(); + let borrowed_shm_buf = payload.as_shm().unwrap(); // construct owned buffer from borrowed type (&zshm -> ZShm) let owned = borrowed_shm_buf.to_owned(); @@ -67,7 +64,7 @@ fn shm_bytes_single_buf() { // branch to illustrate mutable access to SHM data { // deserialize ZBytes as mutably borrowed zshm (ZBytes -> &mut zshm) - let borrowed_shm_buf: &mut zshm = payload.deserialize_mut().unwrap(); + let borrowed_shm_buf = payload.as_shm_mut().unwrap(); // convert zshm to zshmmut (&mut zshm -> &mut zshmmut) let _borrowed_shm_buf_mut: &mut zshmmut = borrowed_shm_buf.try_into().unwrap(); diff --git a/zenoh/tests/handler.rs b/zenoh/tests/handler.rs index d87917a0dd..b661be4087 100644 --- a/zenoh/tests/handler.rs +++ b/zenoh/tests/handler.rs @@ -32,11 +32,7 @@ fn pubsub_with_ringbuffer() { // Should only receive the last three samples ("put7", "put8", "put9") for i in 7..10 { assert_eq!( - sub.recv() - .unwrap() - .payload() - .deserialize::() - .unwrap(), + sub.recv().unwrap().payload().try_to_string().unwrap(), format!("put{i}") ); } @@ -66,8 +62,5 @@ fn query_with_ringbuffer() { let query = queryable.recv().unwrap(); // Only receive the latest query - assert_eq!( - query.payload().unwrap().deserialize::().unwrap(), - "query2" - ); + assert_eq!(query.payload().unwrap().try_to_string().unwrap(), "query2"); } diff --git a/zenoh/tests/shm.rs b/zenoh/tests/shm.rs index 908fc5f2da..327ad76c0e 100644 --- a/zenoh/tests/shm.rs +++ b/zenoh/tests/shm.rs @@ -23,8 +23,7 @@ use std::{ use zenoh::{ qos::{CongestionControl, Reliability}, shm::{ - zshm, BlockOn, GarbageCollect, PosixShmProviderBackend, ShmProviderBuilder, - POSIX_PROTOCOL_ID, + BlockOn, GarbageCollect, PosixShmProviderBackend, ShmProviderBuilder, POSIX_PROTOCOL_ID, }, Session, Wait, }; @@ -122,7 +121,7 @@ async fn test_session_pubsub(peer01: &Session, peer02: &Session, reliability: Re .declare_subscriber(&key_expr) .callback(move |sample| { assert_eq!(sample.payload().len(), size); - let _ = sample.payload().deserialize::<&zshm>().unwrap(); + let _ = sample.payload().as_shm().unwrap(); c_msgs.fetch_add(1, Ordering::Relaxed); })) .unwrap();