From 393849562df102d418f6e37562ccf0b71907a244 Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Wed, 25 Sep 2024 13:20:49 +0200 Subject: [PATCH 01/21] feat!: move serialization into zenoh-ext --- Cargo.lock | 69 +- Cargo.toml | 1 - .../src/pub_sub/bin/z_pub_sub.rs | 4 +- .../src/queryable_get/bin/z_queryable_get.rs | 8 +- commons/zenoh-buffers/src/zbuf.rs | 2 +- examples/Cargo.toml | 2 +- examples/build.rs | 4 + examples/examples/z_bytes.rs | 212 +- examples/examples/z_get.rs | 8 +- examples/examples/z_get_liveliness.rs | 4 +- examples/examples/z_get_shm.rs | 10 +- examples/examples/z_pub.rs | 2 +- examples/examples/z_pull.rs | 8 +- examples/examples/z_put_float.rs | 9 +- examples/examples/z_queryable.rs | 4 +- examples/examples/z_queryable_shm.rs | 10 +- examples/examples/z_storage.rs | 2 +- examples/examples/z_sub.rs | 8 +- examples/examples/z_sub_shm.rs | 10 +- plugins/zenoh-plugin-example/src/lib.rs | 3 +- plugins/zenoh-plugin-rest/build.rs | 2 +- plugins/zenoh-plugin-rest/src/lib.rs | 66 +- plugins/zenoh-plugin-storage-manager/build.rs | 2 +- .../src/replication/aligner.rs | 43 +- .../src/replication/core.rs | 22 +- .../src/storages_mgt/service.rs | 39 +- .../tests/operations.rs | 8 +- .../tests/wildcard.rs | 24 +- zenoh-ext/examples/examples/z_query_sub.rs | 4 +- zenoh-ext/src/lib.rs | 6 + zenoh-ext/src/session_ext.rs | 10 +- zenoh-ext/src/zbytes_ext.rs | 319 ++ zenoh/Cargo.toml | 29 +- zenoh/src/api/admin.rs | 21 +- zenoh/src/api/builders/publisher.rs | 4 +- zenoh/src/api/builders/sample.rs | 2 +- zenoh/src/api/bytes.rs | 3663 ++--------------- zenoh/src/api/publisher.rs | 4 +- zenoh/src/api/session.rs | 4 +- zenoh/src/api/value.rs | 2 +- zenoh/src/lib.rs | 5 +- zenoh/src/net/runtime/adminspace.rs | 20 +- zenoh/tests/acl.rs | 20 +- zenoh/tests/attachments.rs | 93 +- zenoh/tests/authentication.rs | 56 +- zenoh/tests/bytes.rs | 9 +- zenoh/tests/handler.rs | 11 +- zenoh/tests/shm.rs | 5 +- 48 files changed, 1062 insertions(+), 3811 deletions(-) create mode 100644 examples/build.rs create mode 100644 zenoh-ext/src/zbytes_ext.rs diff --git a/Cargo.lock b/Cargo.lock index 015a06ee67..12f81cd486 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2171,7 +2171,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 +2292,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 +2982,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 +3028,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 +3072,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 +3092,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 +4849,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" @@ -5433,7 +5473,6 @@ dependencies = [ "tokio-util", "tracing", "uhlc", - "unwrap-infallible", "vec_map", "zenoh-buffers", "zenoh-codec", @@ -5541,13 +5580,13 @@ 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", "zenoh", "zenoh-ext", ] diff --git a/Cargo.toml b/Cargo.toml index 2fcaaa9cd5..7a9f117385 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -176,7 +176,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..28543a40c3 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 @@ -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..457121dd3b 100644 --- a/commons/zenoh-buffers/src/zbuf.rs +++ b/commons/zenoh-buffers/src/zbuf.rs @@ -404,7 +404,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..2ecaa1ae4a 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -38,7 +38,6 @@ 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 } @@ -47,6 +46,7 @@ rand = { workspace = true, features = ["default"] } [build-dependencies] rustc_version = { workspace = true } +prost-build = "0.13.3" [[example]] name = "z_scout" diff --git a/examples/build.rs b/examples/build.rs new file mode 100644 index 0000000000..3c6e0ce215 --- /dev/null +++ b/examples/build.rs @@ -0,0 +1,4 @@ +fn main() -> std::io::Result<()> { + 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..75777831aa 100644 --- a/examples/examples/z_bytes.rs +++ b/examples/examples/z_bytes.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + // // Copyright (c) 2024 ZettaScale Technology // @@ -11,163 +13,111 @@ // Contributors: // ZettaScale Zenoh Team, // - -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 + { + // Requires to import zenoh-ext trait + use zenoh_ext::ZBytesExt; + + // Numeric types: u8, u16, u32, u128, i8, i16, i32, i128, f32, f64 + let input = 1234_u32; + let payload = ZBytes::serialize(&input); + let output: u32 = payload.deserialize().unwrap(); + assert_eq!(input, output); + + // Vec + let input = vec![0.0f32, 1.5, 42.0]; + let payload = ZBytes::serialize(&input); + let output: Vec = payload.deserialize().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 = ZBytes::serialize(&input); + let output: HashMap = payload.deserialize().unwrap(); + assert_eq!(input, output); + + // Tuple + let input = (0.42f64, "string".to_string()); + let payload = ZBytes::serialize(&input); + let output: (f64, String) = payload.deserialize().unwrap(); + assert_eq!(input, 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 zbytes = ZBytes::new(); + let mut writer = zbytes.writer(); + writer.write(&[0u8, 1]).unwrap(); + writer.append(input2.clone()); + assert_eq!(*zbytes.to_bytes(), [0u8, 1, 2, 3]); + let mut reader = zbytes.reader(); + let mut buf = [0; 2]; + reader.read(&mut buf).unwrap(); + assert_eq!(buf, *input1); + reader.read(&mut buf).unwrap(); + assert_eq!(buf, *input2.to_bytes()); } 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..76421f2814 100644 --- a/examples/examples/z_get_shm.rs +++ b/examples/examples/z_get_shm.rs @@ -78,16 +78,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..8a5584018e 100644 --- a/examples/examples/z_put_float.rs +++ b/examples/examples/z_put_float.rs @@ -12,8 +12,9 @@ // ZettaScale Zenoh Team, // use clap::Parser; -use zenoh::{key_expr::KeyExpr, Config}; +use zenoh::{bytes::ZBytes, key_expr::KeyExpr, Config}; use zenoh_examples::CommonArgs; +use zenoh_ext::ZBytesExt; #[tokio::main] async fn main() { @@ -26,7 +27,11 @@ 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, ZBytes::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..1064bbebfa 100644 --- a/examples/examples/z_queryable_shm.rs +++ b/examples/examples/z_queryable_shm.rs @@ -144,9 +144,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 +157,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..9259e5d569 100644 --- a/examples/examples/z_sub_shm.rs +++ b/examples/examples/z_sub_shm.rs @@ -104,9 +104,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 +117,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 c06fc09951..3b6dd5d7aa 100644 --- a/plugins/zenoh-plugin-rest/src/lib.rs +++ b/plugins/zenoh-plugin-rest/src/lib.rs @@ -101,33 +101,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())), } } @@ -170,10 +167,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() ) } @@ -183,7 +177,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() ) } } @@ -209,18 +203,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 e805bda26c..c30f7b89c4 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 zenoh::{ @@ -88,17 +85,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::Diff(digest_diff) => { @@ -367,17 +363,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 @@ -655,7 +652,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 42e82eae94..d55f574d7f 100644 --- a/plugins/zenoh-plugin-storage-manager/src/storages_mgt/service.rs +++ b/plugins/zenoh-plugin-storage-manager/src/storages_mgt/service.rs @@ -264,23 +264,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 @@ -330,7 +331,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, @@ -634,7 +635,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/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..45969e6c41 100644 --- a/zenoh-ext/src/lib.rs +++ b/zenoh-ext/src/lib.rs @@ -16,12 +16,18 @@ mod publication_cache; mod querying_subscriber; mod session_ext; mod subscriber_ext; +mod zbytes_ext; + pub use publication_cache::{PublicationCache, PublicationCacheBuilder}; pub use querying_subscriber::{ FetchingSubscriber, FetchingSubscriberBuilder, QueryingSubscriberBuilder, }; pub use session_ext::SessionExt; pub use subscriber_ext::{SubscriberBuilderExt, SubscriberForward}; +pub use zbytes_ext::{ + Deserialize, Serialize, ZBytesExt, ZBytesReaderExt, ZBytesWriterExt, ZDeserializeError, + ZReadIter, +}; use zenoh::{internal::zerror, query::Reply, sample::Sample, Result as ZResult}; /// The space of keys to use in a [`FetchingSubscriber`]. 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-ext/src/zbytes_ext.rs b/zenoh-ext/src/zbytes_ext.rs new file mode 100644 index 0000000000..edd88515fb --- /dev/null +++ b/zenoh-ext/src/zbytes_ext.rs @@ -0,0 +1,319 @@ +use std::{ + borrow::Cow, + collections::{BTreeMap, BTreeSet, HashMap, HashSet}, + fmt, + hash::Hash, + io::{Read, Write}, + marker::PhantomData, + ptr, +}; + +use zenoh::bytes::{ZBytes, ZBytesReader, ZBytesWriter}; + +#[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 {} + +pub trait Serialize { + fn write_into(&self, writer: &mut ZBytesWriter); + #[doc(hidden)] + fn write_slice_into(slice: &[Self], writer: &mut ZBytesWriter) + where + Self: Sized, + { + writer.write_iter(slice) + } +} +impl Serialize for &T { + fn write_into(&self, writer: &mut ZBytesWriter) { + T::write_into(*self, writer) + } +} + +pub trait Deserialize: Sized { + fn read_from(reader: &mut ZBytesReader) -> Result; + #[doc(hidden)] + fn read_slice_from(reader: &mut ZBytesReader) -> Result, ZDeserializeError> { + reader.read_iter::()?.collect() + } +} + +pub trait ZBytesExt { + fn serialize(t: &T) -> Self; + fn deserialize(&self) -> Result; +} + +impl ZBytesExt for ZBytes { + fn serialize(t: &T) -> Self { + let mut zbytes = ZBytes::new(); + t.write_into(&mut zbytes.writer()); + zbytes + } + + fn deserialize(&self) -> Result { + let mut reader = self.reader(); + let t = T::read_from(&mut reader)?; + if !reader.is_empty() { + return Err(ZDeserializeError); + } + Ok(t) + } +} + +pub trait ZBytesWriterExt<'a> { + fn write_iter>(&mut self, iter: I) + where + I::IntoIter: ExactSizeIterator; +} + +impl<'a> ZBytesWriterExt<'a> for ZBytesWriter<'a> { + fn write_iter>(&mut self, iter: I) + where + I::IntoIter: ExactSizeIterator, + { + let iter = iter.into_iter(); + self.write_vle(iter.len() as u64); + for t in iter { + t.write_into(self) + } + } +} + +pub trait ZBytesReaderExt<'a> { + fn read_iter(&mut self) -> Result, ZDeserializeError>; +} +impl<'a> ZBytesReaderExt<'a> for ZBytesReader<'a> { + fn read_iter(&mut self) -> Result, ZDeserializeError> { + let len = self.read_vle().ok_or(ZDeserializeError)? as usize; + Ok(ZReadIter { + reader: self, + len, + _phantom: PhantomData, + }) + } +} + +pub struct ZReadIter<'a, 'b, T: Deserialize> { + reader: &'b mut ZBytesReader<'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::read_from(self.reader)) + } + + 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); + } +} + +macro_rules! impl_num { + ($($ty:ty),* $(,)?) => {$( + impl Serialize for $ty { + fn write_into(&self, writer: &mut ZBytesWriter) { + writer.write(&(*self).to_le_bytes()).unwrap(); + } + fn write_slice_into(slice: &[Self], writer: &mut ZBytesWriter) where Self: Sized { + if cfg!(target_endian = "little") || std::mem::size_of::() == 1 { + writer.write_vle(slice.len() as u64); + // SAFETY: transmuting numeric types to their little endian bytes is safe + writer.write(unsafe { slice.align_to().1 }).unwrap(); + } else { + writer.write_iter(slice); + } + } + } + impl Deserialize for $ty { + fn read_from(reader: &mut ZBytesReader) -> Result { + let mut buf = [0; { std::mem::size_of::() }]; + reader.read(&mut buf).or(Err(ZDeserializeError))?; + Ok(<$ty>::from_le_bytes(buf)) + } + fn read_slice_from(reader: &mut ZBytesReader) -> Result, ZDeserializeError> { + let size = std::mem::size_of::(); + if cfg!(target_endian = "little") || size == 1 { + let len = reader.read_vle().ok_or(ZDeserializeError)? as usize; + let total_size = len * size; + let mut buf = std::mem::ManuallyDrop::new(vec![0; total_size].into_boxed_slice()); + reader.read(&mut buf).or(Err(ZDeserializeError))?; + // SAFETY: transmuting numeric types from their little endian bytes is safe + Ok(unsafe { Box::from_raw(ptr::slice_from_raw_parts_mut(buf.as_mut_ptr().cast(), len)) }) + } else { + reader.read_iter::()?.collect() + } + } + } + )*}; +} +impl_num!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, f32, f64); + +impl Serialize for bool { + fn write_into(&self, writer: &mut ZBytesWriter) { + (*self as u8).write_into(writer); + } +} +impl Deserialize for bool { + fn read_from(reader: &mut ZBytesReader) -> Result { + match u8::read_from(reader)? { + 0 => Ok(false), + 1 => Ok(true), + _ => Err(ZDeserializeError), + } + } +} + +impl Serialize for [T] { + fn write_into(&self, writer: &mut ZBytesWriter) { + T::write_slice_into(self, writer) + } +} +impl<'a, T: Serialize + 'a> Serialize for Cow<'a, [T]> +where + [T]: ToOwned, +{ + fn write_into(&self, writer: &mut ZBytesWriter) { + T::write_slice_into(self, writer) + } +} +impl Serialize for Box<[T]> { + fn write_into(&self, writer: &mut ZBytesWriter) { + T::write_slice_into(self, writer) + } +} +impl Deserialize for Box<[T]> { + fn read_from(reader: &mut ZBytesReader) -> Result { + T::read_slice_from(reader) + } +} +impl Serialize for Vec { + fn write_into(&self, writer: &mut ZBytesWriter) { + T::write_slice_into(self, writer) + } +} +impl Deserialize for Vec { + fn read_from(reader: &mut ZBytesReader) -> Result { + T::read_slice_from(reader).map(Into::into) + } +} +impl Serialize for HashSet { + fn write_into(&self, writer: &mut ZBytesWriter) { + writer.write_iter(self); + } +} +impl Deserialize for HashSet { + fn read_from(reader: &mut ZBytesReader) -> Result { + reader.read_iter::()?.collect() + } +} +impl Serialize for BTreeSet { + fn write_into(&self, writer: &mut ZBytesWriter) { + writer.write_iter(self); + } +} +impl Deserialize for BTreeSet { + fn read_from(reader: &mut ZBytesReader) -> Result { + reader.read_iter::()?.collect() + } +} +impl Serialize for HashMap { + fn write_into(&self, writer: &mut ZBytesWriter) { + writer.write_iter(self); + } +} +impl Deserialize for HashMap { + fn read_from(reader: &mut ZBytesReader) -> Result { + reader.read_iter::<(K, V)>()?.collect() + } +} +impl Serialize for BTreeMap { + fn write_into(&self, writer: &mut ZBytesWriter) { + writer.write_iter(self); + } +} +impl Deserialize for BTreeMap { + fn read_from(reader: &mut ZBytesReader) -> Result { + reader.read_iter::<(K, V)>()?.collect() + } +} +impl Serialize for str { + fn write_into(&self, writer: &mut ZBytesWriter) { + self.as_bytes().write_into(writer); + } +} +impl Serialize for Cow<'_, str> { + fn write_into(&self, writer: &mut ZBytesWriter) { + self.as_bytes().write_into(writer); + } +} +impl Serialize for String { + fn write_into(&self, writer: &mut ZBytesWriter) { + self.as_bytes().write_into(writer); + } +} +impl Deserialize for String { + fn read_from(reader: &mut ZBytesReader) -> Result { + String::from_utf8(Deserialize::read_from(reader)?).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 write_into(&self, writer: &mut ZBytesWriter) { + $(self.$i.write_into(writer);)* + } + } + #[allow(unused)] + impl<$($ty: Deserialize),*> Deserialize for ($($ty,)*) { + fn read_from(reader: &mut ZBytesReader) -> Result { + Ok(($($ty::read_from(reader)?,)*)) + } + } + }; +} +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, +); 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 b96fc75dd2..6a686e2637 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..15e8f9e59b 100644 --- a/zenoh/src/api/bytes.rs +++ b/zenoh/src/api/bytes.rs @@ -13,13 +13,8 @@ // //! 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, str::Utf8Error}; -use uhlc::Timestamp; -use unwrap_infallible::UnwrapInfallible; use zenoh_buffers::{ buffer::{Buffer, SplitBuffer}, reader::{HasReader, Reader}, @@ -27,20 +22,7 @@ use zenoh_buffers::{ ZBuf, ZBufReader, ZBufWriter, ZSlice, ZSliceBuffer, }; use zenoh_codec::{RCodec, WCodec, Zenoh080}; -use zenoh_protocol::{ - core::{Encoding as EncodingProto, Parameters}, - zenoh::ext::AttachmentType, -}; -#[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,147 +68,28 @@ 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)] @@ -234,19 +97,10 @@ 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 +111,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,7 +136,7 @@ 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. @@ -281,30 +146,6 @@ impl ZBytes { 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::, - } - } - /// Return an iterator on raw bytes slices contained in the [`ZBytes`]. /// /// [`ZBytes`] may store data in non-contiguous regions of memory, this iterator @@ -320,7 +161,7 @@ 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 zbs = ZBytes::new(); /// let mut writer = zbs.writer(); /// writer.write(&buf1); /// writer.write(&buf2); @@ -348,7 +189,7 @@ 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 zbs = ZBytes::new(); /// let mut writer = zbs.writer(); /// writer.append(ZBytes::from(buf1.clone())); /// writer.append(ZBytes::from(buf2.clone())); @@ -360,166 +201,37 @@ impl ZBytes { 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(); + if zslices.by_ref().count() != 1 { + return None; + } + let zslice = zslices.next().unwrap(); + zslice.downcast_ref::().map(Into::into) + } - /// 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(); + if zslices.by_ref().count() != 1 { + return None; + } + let zslice = zslices.next().unwrap(); + // SAFETY: ShmBufInner cannot change the size of the slice + unsafe { zslice.downcast_mut::() }.map(Into::into) + } } -} +}; -/// 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 { @@ -531,19 +243,10 @@ impl ZBytesReader<'_> { 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, - { + #[zenoh_macros::internal] + pub fn read_vle(&mut self) -> Option { 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) + codec.read(&mut self.0).ok() } } @@ -560,103 +263,14 @@ 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(()) - } - /// 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,7 +280,7 @@ 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 bytes = ZBytes::new(); /// let mut writer = bytes.writer(); /// // Append data without copying by passing ownership /// writer.append(one); @@ -685,6 +299,12 @@ impl ZBytesWriter<'_> { unsafe { self.0.write_zslice(s).unwrap_unchecked() } } } + + #[zenoh_macros::internal] + pub fn write_vle(&mut self, vle: u64) { + let codec = Zenoh080::new(); + codec.write(&mut self.0, vle).unwrap(); + } } impl std::io::Write for ZBytesWriter<'_> { @@ -697,7 +317,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,7 +326,7 @@ 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 zbs = ZBytes::new(); /// let mut writer = zbs.writer(); /// writer.write(&buf1); /// writer.write(&buf2); @@ -740,2616 +360,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) - } -} - -/// 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 ZBytes { + fn from(value: ZBuf) -> Self { + Self(value) } } - -impl std::error::Error for ZDeserializeError {} - -// ZBytes -impl Serialize for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: ZBytes) -> Self::Output { - t +impl From for ZBuf { + fn from(value: ZBytes) -> Self { + value.0 } } - -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 { + Self(value.into()) } } - -impl From<&mut ZBytes> for ZBytes { - fn from(t: &mut ZBytes) -> Self { - ZSerde.serialize(t) +impl From<&[u8; N]> for ZBytes { + fn from(value: &[u8; N]) -> Self { + value.to_vec().into() } } - -impl Serialize<&ZBytes> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: &ZBytes) -> Self::Output { - t.clone() +impl From> for ZBytes { + fn from(value: Vec) -> Self { + Self(value.into()) } } - -impl Serialize<&mut ZBytes> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: &mut ZBytes) -> Self::Output { - t.clone() +impl From<&Vec> for ZBytes { + fn from(value: &Vec) -> Self { + value.clone().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<&[u8]> for ZBytes { + fn from(value: &[u8]) -> Self { + value.to_vec().into() } } - -// ZBuf -#[doc(hidden)] -impl Serialize for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: ZBuf) -> Self::Output { - ZBytes::new(t) +impl From> for ZBytes { + fn from(value: Cow<'_, [u8]>) -> Self { + value.into_owned().into() } } - -#[doc(hidden)] -impl From for ZBytes { - fn from(t: ZBuf) -> Self { - ZSerde.serialize(t) +impl From<&Cow<'_, [u8]>> for ZBytes { + fn from(value: &Cow<'_, [u8]>) -> Self { + value.clone().into() } } - -#[doc(hidden)] -impl Serialize<&ZBuf> for ZSerde { - type Output = ZBytes; - - fn serialize(self, t: &ZBuf) -> Self::Output { - ZBytes::new(t.clone()) +impl From for ZBytes { + fn from(value: String) -> Self { + value.into_bytes().into() } } - -#[doc(hidden)] -impl From<&ZBuf> for ZBytes { - fn from(t: &ZBuf) -> Self { - ZSerde.serialize(t) +impl From<&String> for ZBytes { + fn from(value: &String) -> Self { + value.clone().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<&str> for ZBytes { + fn from(value: &str) -> Self { + value.as_bytes().into() } } - -#[doc(hidden)] -impl From<&mut ZBuf> for ZBytes { - fn from(t: &mut ZBuf) -> Self { - ZSerde.serialize(t) +impl From> for ZBytes { + fn from(value: Cow<'_, str>) -> Self { + value.into_owned().into() } } - -#[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()) +impl From<&Cow<'_, str>> for ZBytes { + fn from(value: &Cow<'_, str>) -> Self { + value.clone().into() } } -#[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) - } -} - -#[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 { @@ -3366,311 +486,230 @@ impl From> for ZBytes { } } -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(); - } -} +// 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; +// #[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::new(); +// 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")) +// ); +// } +// } 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 be8be3b024..85ee915a03 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 a49261c9d1..e73963a98d 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(); From b589b78fa59368985fa1ece76b5cc5ceec19d7b8 Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Wed, 25 Sep 2024 18:35:24 +0200 Subject: [PATCH 02/21] refactor: rename write_xxx/read_xxx to (de)serialize_xxx --- zenoh-ext/src/zbytes_ext.rs | 146 ++++++++++++++++++++---------------- 1 file changed, 80 insertions(+), 66 deletions(-) diff --git a/zenoh-ext/src/zbytes_ext.rs b/zenoh-ext/src/zbytes_ext.rs index edd88515fb..d650913b45 100644 --- a/zenoh-ext/src/zbytes_ext.rs +++ b/zenoh-ext/src/zbytes_ext.rs @@ -20,26 +20,26 @@ impl fmt::Display for ZDeserializeError { impl std::error::Error for ZDeserializeError {} pub trait Serialize { - fn write_into(&self, writer: &mut ZBytesWriter); + fn serialize(&self, writer: &mut ZBytesWriter); #[doc(hidden)] - fn write_slice_into(slice: &[Self], writer: &mut ZBytesWriter) + fn serialize_slice(slice: &[Self], writer: &mut ZBytesWriter) where Self: Sized, { - writer.write_iter(slice) + writer.serialize_iter(slice) } } impl Serialize for &T { - fn write_into(&self, writer: &mut ZBytesWriter) { - T::write_into(*self, writer) + fn serialize(&self, writer: &mut ZBytesWriter) { + T::serialize(*self, writer) } } pub trait Deserialize: Sized { - fn read_from(reader: &mut ZBytesReader) -> Result; + fn deserialize(reader: &mut ZBytesReader) -> Result; #[doc(hidden)] - fn read_slice_from(reader: &mut ZBytesReader) -> Result, ZDeserializeError> { - reader.read_iter::()?.collect() + fn deserialize_slice(reader: &mut ZBytesReader) -> Result, ZDeserializeError> { + reader.deserialize_iter::()?.collect() } } @@ -51,13 +51,13 @@ pub trait ZBytesExt { impl ZBytesExt for ZBytes { fn serialize(t: &T) -> Self { let mut zbytes = ZBytes::new(); - t.write_into(&mut zbytes.writer()); + t.serialize(&mut zbytes.writer()); zbytes } fn deserialize(&self) -> Result { let mut reader = self.reader(); - let t = T::read_from(&mut reader)?; + let t = T::deserialize(&mut reader)?; if !reader.is_empty() { return Err(ZDeserializeError); } @@ -66,29 +66,43 @@ impl ZBytesExt for ZBytes { } pub trait ZBytesWriterExt<'a> { - fn write_iter>(&mut self, iter: I) + fn serialize(&mut self, t: T); + fn serialize_iter>(&mut self, iter: I) where I::IntoIter: ExactSizeIterator; } impl<'a> ZBytesWriterExt<'a> for ZBytesWriter<'a> { - fn write_iter>(&mut self, iter: I) + fn serialize(&mut self, t: T) { + t.serialize(self); + } + + fn serialize_iter>(&mut self, iter: I) where I::IntoIter: ExactSizeIterator, { let iter = iter.into_iter(); self.write_vle(iter.len() as u64); for t in iter { - t.write_into(self) + t.serialize(self); } } } pub trait ZBytesReaderExt<'a> { - fn read_iter(&mut self) -> Result, ZDeserializeError>; + fn deserialize(&mut self) -> Result; + fn deserialize_iter( + &mut self, + ) -> Result, ZDeserializeError>; } impl<'a> ZBytesReaderExt<'a> for ZBytesReader<'a> { - fn read_iter(&mut self) -> Result, ZDeserializeError> { + fn deserialize(&mut self) -> Result { + T::deserialize(self) + } + + fn deserialize_iter( + &mut self, + ) -> Result, ZDeserializeError> { let len = self.read_vle().ok_or(ZDeserializeError)? as usize; Ok(ZReadIter { reader: self, @@ -110,7 +124,7 @@ impl Iterator for ZReadIter<'_, '_, T> { return None; } self.len -= 1; - Some(T::read_from(self.reader)) + Some(T::deserialize(self.reader)) } fn size_hint(&self) -> (usize, Option) { @@ -127,26 +141,26 @@ impl Drop for ZReadIter<'_, '_, T> { macro_rules! impl_num { ($($ty:ty),* $(,)?) => {$( impl Serialize for $ty { - fn write_into(&self, writer: &mut ZBytesWriter) { + fn serialize(&self, writer: &mut ZBytesWriter) { writer.write(&(*self).to_le_bytes()).unwrap(); } - fn write_slice_into(slice: &[Self], writer: &mut ZBytesWriter) where Self: Sized { + fn serialize_slice(slice: &[Self], writer: &mut ZBytesWriter) where Self: Sized { if cfg!(target_endian = "little") || std::mem::size_of::() == 1 { writer.write_vle(slice.len() as u64); // SAFETY: transmuting numeric types to their little endian bytes is safe writer.write(unsafe { slice.align_to().1 }).unwrap(); } else { - writer.write_iter(slice); + writer.serialize_iter(slice); } } } impl Deserialize for $ty { - fn read_from(reader: &mut ZBytesReader) -> Result { + fn deserialize(reader: &mut ZBytesReader) -> Result { let mut buf = [0; { std::mem::size_of::() }]; reader.read(&mut buf).or(Err(ZDeserializeError))?; Ok(<$ty>::from_le_bytes(buf)) } - fn read_slice_from(reader: &mut ZBytesReader) -> Result, ZDeserializeError> { + fn deserialize_slice(reader: &mut ZBytesReader) -> Result, ZDeserializeError> { let size = std::mem::size_of::(); if cfg!(target_endian = "little") || size == 1 { let len = reader.read_vle().ok_or(ZDeserializeError)? as usize; @@ -156,7 +170,7 @@ macro_rules! impl_num { // SAFETY: transmuting numeric types from their little endian bytes is safe Ok(unsafe { Box::from_raw(ptr::slice_from_raw_parts_mut(buf.as_mut_ptr().cast(), len)) }) } else { - reader.read_iter::()?.collect() + reader.deserialize_iter::()?.collect() } } } @@ -165,13 +179,13 @@ macro_rules! impl_num { impl_num!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, f32, f64); impl Serialize for bool { - fn write_into(&self, writer: &mut ZBytesWriter) { - (*self as u8).write_into(writer); + fn serialize(&self, writer: &mut ZBytesWriter) { + (*self as u8).serialize(writer); } } impl Deserialize for bool { - fn read_from(reader: &mut ZBytesReader) -> Result { - match u8::read_from(reader)? { + fn deserialize(reader: &mut ZBytesReader) -> Result { + match u8::deserialize(reader)? { 0 => Ok(false), 1 => Ok(true), _ => Err(ZDeserializeError), @@ -180,96 +194,96 @@ impl Deserialize for bool { } impl Serialize for [T] { - fn write_into(&self, writer: &mut ZBytesWriter) { - T::write_slice_into(self, writer) + fn serialize(&self, writer: &mut ZBytesWriter) { + T::serialize_slice(self, writer) } } impl<'a, T: Serialize + 'a> Serialize for Cow<'a, [T]> where [T]: ToOwned, { - fn write_into(&self, writer: &mut ZBytesWriter) { - T::write_slice_into(self, writer) + fn serialize(&self, writer: &mut ZBytesWriter) { + T::serialize_slice(self, writer) } } impl Serialize for Box<[T]> { - fn write_into(&self, writer: &mut ZBytesWriter) { - T::write_slice_into(self, writer) + fn serialize(&self, writer: &mut ZBytesWriter) { + T::serialize_slice(self, writer) } } impl Deserialize for Box<[T]> { - fn read_from(reader: &mut ZBytesReader) -> Result { - T::read_slice_from(reader) + fn deserialize(reader: &mut ZBytesReader) -> Result { + T::deserialize_slice(reader) } } impl Serialize for Vec { - fn write_into(&self, writer: &mut ZBytesWriter) { - T::write_slice_into(self, writer) + fn serialize(&self, writer: &mut ZBytesWriter) { + T::serialize_slice(self, writer) } } impl Deserialize for Vec { - fn read_from(reader: &mut ZBytesReader) -> Result { - T::read_slice_from(reader).map(Into::into) + fn deserialize(reader: &mut ZBytesReader) -> Result { + T::deserialize_slice(reader).map(Into::into) } } impl Serialize for HashSet { - fn write_into(&self, writer: &mut ZBytesWriter) { - writer.write_iter(self); + fn serialize(&self, writer: &mut ZBytesWriter) { + writer.serialize_iter(self); } } impl Deserialize for HashSet { - fn read_from(reader: &mut ZBytesReader) -> Result { - reader.read_iter::()?.collect() + fn deserialize(reader: &mut ZBytesReader) -> Result { + reader.deserialize_iter::()?.collect() } } impl Serialize for BTreeSet { - fn write_into(&self, writer: &mut ZBytesWriter) { - writer.write_iter(self); + fn serialize(&self, writer: &mut ZBytesWriter) { + writer.serialize_iter(self); } } impl Deserialize for BTreeSet { - fn read_from(reader: &mut ZBytesReader) -> Result { - reader.read_iter::()?.collect() + fn deserialize(reader: &mut ZBytesReader) -> Result { + reader.deserialize_iter::()?.collect() } } impl Serialize for HashMap { - fn write_into(&self, writer: &mut ZBytesWriter) { - writer.write_iter(self); + fn serialize(&self, writer: &mut ZBytesWriter) { + writer.serialize_iter(self); } } impl Deserialize for HashMap { - fn read_from(reader: &mut ZBytesReader) -> Result { - reader.read_iter::<(K, V)>()?.collect() + fn deserialize(reader: &mut ZBytesReader) -> Result { + reader.deserialize_iter::<(K, V)>()?.collect() } } impl Serialize for BTreeMap { - fn write_into(&self, writer: &mut ZBytesWriter) { - writer.write_iter(self); + fn serialize(&self, writer: &mut ZBytesWriter) { + writer.serialize_iter(self); } } impl Deserialize for BTreeMap { - fn read_from(reader: &mut ZBytesReader) -> Result { - reader.read_iter::<(K, V)>()?.collect() + fn deserialize(reader: &mut ZBytesReader) -> Result { + reader.deserialize_iter::<(K, V)>()?.collect() } } impl Serialize for str { - fn write_into(&self, writer: &mut ZBytesWriter) { - self.as_bytes().write_into(writer); + fn serialize(&self, writer: &mut ZBytesWriter) { + self.as_bytes().serialize(writer); } } impl Serialize for Cow<'_, str> { - fn write_into(&self, writer: &mut ZBytesWriter) { - self.as_bytes().write_into(writer); + fn serialize(&self, writer: &mut ZBytesWriter) { + self.as_bytes().serialize(writer); } } impl Serialize for String { - fn write_into(&self, writer: &mut ZBytesWriter) { - self.as_bytes().write_into(writer); + fn serialize(&self, writer: &mut ZBytesWriter) { + self.as_bytes().serialize(writer); } } impl Deserialize for String { - fn read_from(reader: &mut ZBytesReader) -> Result { - String::from_utf8(Deserialize::read_from(reader)?).or(Err(ZDeserializeError)) + fn deserialize(reader: &mut ZBytesReader) -> Result { + String::from_utf8(Deserialize::deserialize(reader)?).or(Err(ZDeserializeError)) } } @@ -287,14 +301,14 @@ macro_rules! impl_tuple { (@@$($ty:ident/$i:tt),* $(,)?) => { #[allow(unused)] impl<$($ty: Serialize),*> Serialize for ($($ty,)*) { - fn write_into(&self, writer: &mut ZBytesWriter) { - $(self.$i.write_into(writer);)* + fn serialize(&self, writer: &mut ZBytesWriter) { + $(self.$i.serialize(writer);)* } } #[allow(unused)] impl<$($ty: Deserialize),*> Deserialize for ($($ty,)*) { - fn read_from(reader: &mut ZBytesReader) -> Result { - Ok(($($ty::read_from(reader)?,)*)) + fn deserialize(reader: &mut ZBytesReader) -> Result { + Ok(($($ty::deserialize(reader)?,)*)) } } }; From aecbb83938ca3abbf174a18d07b544e43a8faace Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Wed, 25 Sep 2024 18:39:56 +0200 Subject: [PATCH 03/21] fix: lints --- zenoh/src/api/bytes.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zenoh/src/api/bytes.rs b/zenoh/src/api/bytes.rs index 15e8f9e59b..25d72646f0 100644 --- a/zenoh/src/api/bytes.rs +++ b/zenoh/src/api/bytes.rs @@ -21,7 +21,6 @@ use zenoh_buffers::{ writer::HasWriter, ZBuf, ZBufReader, ZBufWriter, ZSlice, ZSliceBuffer, }; -use zenoh_codec::{RCodec, WCodec, Zenoh080}; 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`. @@ -245,6 +244,7 @@ impl ZBytesReader<'_> { #[zenoh_macros::internal] pub fn read_vle(&mut self) -> Option { + use zenoh_codec::{RCodec, Zenoh080}; let codec = Zenoh080::new(); codec.read(&mut self.0).ok() } @@ -302,6 +302,7 @@ impl ZBytesWriter<'_> { #[zenoh_macros::internal] pub fn write_vle(&mut self, vle: u64) { + use zenoh_codec::{WCodec, Zenoh080}; let codec = Zenoh080::new(); codec.write(&mut self.0, vle).unwrap(); } From 3f91c7ac87ac6c2cad93176f272221c822675aa3 Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Wed, 25 Sep 2024 19:56:06 +0200 Subject: [PATCH 04/21] fix: fix `ZBytes::as_shm` --- zenoh/src/api/bytes.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/zenoh/src/api/bytes.rs b/zenoh/src/api/bytes.rs index 25d72646f0..548a01d64b 100644 --- a/zenoh/src/api/bytes.rs +++ b/zenoh/src/api/bytes.rs @@ -207,21 +207,15 @@ const _: () = { impl ZBytes { pub fn as_shm(&self) -> Option<&zshm> { let mut zslices = self.0.zslices(); - if zslices.by_ref().count() != 1 { - return None; - } - let zslice = zslices.next().unwrap(); - zslice.downcast_ref::().map(Into::into) + let buf = zslices.next()?.downcast_ref::(); + buf.map(Into::into).filter(|_| zslices.next().is_none()) } pub fn as_shm_mut(&mut self) -> Option<&mut zshm> { let mut zslices = self.0.zslices_mut(); - if zslices.by_ref().count() != 1 { - return None; - } - let zslice = zslices.next().unwrap(); // SAFETY: ShmBufInner cannot change the size of the slice - unsafe { zslice.downcast_mut::() }.map(Into::into) + let buf = unsafe { zslices.next()?.downcast_mut::() }; + buf.map(Into::into).filter(|_| zslices.next().is_none()) } } }; From df18470cc46be02c86d757b08a7e921303e61102 Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Wed, 25 Sep 2024 21:24:17 +0200 Subject: [PATCH 05/21] fix: make protoc non-mandatory to execute z_bytes example --- Cargo.lock | 20 +++++++++++++++++++- examples/Cargo.toml | 4 ++-- examples/build.rs | 12 ++++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 12f81cd486..bd334f9db5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5129,6 +5129,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" @@ -5408,6 +5420,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" @@ -5583,10 +5601,10 @@ dependencies = [ "prost 0.13.3", "prost-build", "rand 0.8.5", - "rustc_version 0.4.1", "serde_json", "serde_yaml", "tokio", + "which", "zenoh", "zenoh-ext", ] diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 2ecaa1ae4a..2120daa873 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -45,8 +45,8 @@ zenoh-ext = { workspace = true } rand = { workspace = true, features = ["default"] } [build-dependencies] -rustc_version = { workspace = true } -prost-build = "0.13.3" +prost-build = "0.13" +which = "6" [[example]] name = "z_scout" diff --git a/examples/build.rs b/examples/build.rs index 3c6e0ce215..c1e0a6f145 100644 --- a/examples/build.rs +++ b/examples/build.rs @@ -1,4 +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: &'static 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(PROTO.as_bytes())?; + return Ok(()); + } prost_build::compile_protos(&["examples/example.proto"], &["examples/"])?; Ok(()) } From 9c70e621ff8b30eb79b6fef67a25958e3bdc60f7 Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Wed, 25 Sep 2024 21:41:58 +0200 Subject: [PATCH 06/21] fix: lint --- examples/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/build.rs b/examples/build.rs index c1e0a6f145..166163eba0 100644 --- a/examples/build.rs +++ b/examples/build.rs @@ -6,7 +6,7 @@ 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: &'static 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,}"#; + 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(PROTO.as_bytes())?; return Ok(()); From 6f233e022646c77d3161524d9fe6536a8c208891 Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Wed, 25 Sep 2024 22:05:09 +0200 Subject: [PATCH 07/21] fix: lint --- examples/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/build.rs b/examples/build.rs index 166163eba0..ad3169be24 100644 --- a/examples/build.rs +++ b/examples/build.rs @@ -8,7 +8,7 @@ fn main() -> std::io::Result<()> { 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(PROTO.as_bytes())?; + File::create(out_path)?.write_all(PROTO.as_bytes())?; return Ok(()); } prost_build::compile_protos(&["examples/example.proto"], &["examples/"])?; From a0169e20165a8ffe7673b1eb3853499c68e4fde8 Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Wed, 25 Sep 2024 22:21:40 +0200 Subject: [PATCH 08/21] fix: lint --- zenoh-ext/src/zbytes_ext.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/zenoh-ext/src/zbytes_ext.rs b/zenoh-ext/src/zbytes_ext.rs index d650913b45..7a35318eb5 100644 --- a/zenoh-ext/src/zbytes_ext.rs +++ b/zenoh-ext/src/zbytes_ext.rs @@ -142,13 +142,13 @@ macro_rules! impl_num { ($($ty:ty),* $(,)?) => {$( impl Serialize for $ty { fn serialize(&self, writer: &mut ZBytesWriter) { - writer.write(&(*self).to_le_bytes()).unwrap(); + writer.write_all(&(*self).to_le_bytes()).unwrap(); } fn serialize_slice(slice: &[Self], writer: &mut ZBytesWriter) where Self: Sized { if cfg!(target_endian = "little") || std::mem::size_of::() == 1 { writer.write_vle(slice.len() as u64); // SAFETY: transmuting numeric types to their little endian bytes is safe - writer.write(unsafe { slice.align_to().1 }).unwrap(); + writer.write_all(unsafe { slice.align_to().1 }).unwrap(); } else { writer.serialize_iter(slice); } @@ -157,7 +157,7 @@ macro_rules! impl_num { impl Deserialize for $ty { fn deserialize(reader: &mut ZBytesReader) -> Result { let mut buf = [0; { std::mem::size_of::() }]; - reader.read(&mut buf).or(Err(ZDeserializeError))?; + reader.read_exact(&mut buf).or(Err(ZDeserializeError))?; Ok(<$ty>::from_le_bytes(buf)) } fn deserialize_slice(reader: &mut ZBytesReader) -> Result, ZDeserializeError> { @@ -166,7 +166,7 @@ macro_rules! impl_num { let len = reader.read_vle().ok_or(ZDeserializeError)? as usize; let total_size = len * size; let mut buf = std::mem::ManuallyDrop::new(vec![0; total_size].into_boxed_slice()); - reader.read(&mut buf).or(Err(ZDeserializeError))?; + reader.read_exact(&mut buf).or(Err(ZDeserializeError))?; // SAFETY: transmuting numeric types from their little endian bytes is safe Ok(unsafe { Box::from_raw(ptr::slice_from_raw_parts_mut(buf.as_mut_ptr().cast(), len)) }) } else { From 757e26263375ef9b2e987652da38d42d6a5ccc00 Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Wed, 25 Sep 2024 22:29:30 +0200 Subject: [PATCH 09/21] fix: add Serialize implementation for ZBytes --- zenoh-ext/src/zbytes_ext.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/zenoh-ext/src/zbytes_ext.rs b/zenoh-ext/src/zbytes_ext.rs index 7a35318eb5..cfc817198c 100644 --- a/zenoh-ext/src/zbytes_ext.rs +++ b/zenoh-ext/src/zbytes_ext.rs @@ -138,6 +138,13 @@ impl Drop for ZReadIter<'_, '_, T> { } } +impl Serialize for ZBytes { + fn serialize(&self, writer: &mut ZBytesWriter) { + writer.write_vle(self.len() as u64); + writer.append(self.clone()) + } +} + macro_rules! impl_num { ($($ty:ty),* $(,)?) => {$( impl Serialize for $ty { From 4d238f9eb671d1ef4f17245127b8307bf1bc39d0 Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Wed, 25 Sep 2024 22:55:16 +0200 Subject: [PATCH 10/21] fix: lints --- examples/examples/z_bytes.rs | 6 +++--- plugins/zenoh-plugin-rest/src/lib.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/examples/z_bytes.rs b/examples/examples/z_bytes.rs index 75777831aa..874f08a002 100644 --- a/examples/examples/z_bytes.rs +++ b/examples/examples/z_bytes.rs @@ -111,13 +111,13 @@ fn main() { let input2 = ZBytes::from([2, 3]); let mut zbytes = ZBytes::new(); let mut writer = zbytes.writer(); - writer.write(&[0u8, 1]).unwrap(); + writer.write_all(&[0u8, 1]).unwrap(); writer.append(input2.clone()); assert_eq!(*zbytes.to_bytes(), [0u8, 1, 2, 3]); let mut reader = zbytes.reader(); let mut buf = [0; 2]; - reader.read(&mut buf).unwrap(); + reader.read_exact(&mut buf).unwrap(); assert_eq!(buf, *input1); - reader.read(&mut buf).unwrap(); + reader.read_exact(&mut buf).unwrap(); assert_eq!(buf, *input2.to_bytes()); } diff --git a/plugins/zenoh-plugin-rest/src/lib.rs b/plugins/zenoh-plugin-rest/src/lib.rs index 3b6dd5d7aa..d708dc73fb 100644 --- a/plugins/zenoh-plugin-rest/src/lib.rs +++ b/plugins/zenoh-plugin-rest/src/lib.rs @@ -120,7 +120,7 @@ fn payload_to_json(payload: &ZBytes, encoding: &Encoding) -> serde_json::Value { tracing::warn!( "Encoding is String but data is not String, converting to base64, Error: {e:?}" ); - base64_encode(&e.as_bytes()) + base64_encode(e.as_bytes()) }), ), // otherwise convert to JSON string From 254698d0807d6fa69fba820e8993bba489177ac5 Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Thu, 26 Sep 2024 01:00:02 +0200 Subject: [PATCH 11/21] refactor: replace extension traits by dedicated types --- examples/examples/z_bytes.rs | 19 +- zenoh-ext/Cargo.toml | 10 +- zenoh-ext/src/lib.rs | 10 +- zenoh-ext/src/serialization.rs | 359 +++++++++++++++++++++++++++++++++ zenoh-ext/src/zbytes_ext.rs | 340 ------------------------------- 5 files changed, 378 insertions(+), 360 deletions(-) create mode 100644 zenoh-ext/src/serialization.rs delete mode 100644 zenoh-ext/src/zbytes_ext.rs diff --git a/examples/examples/z_bytes.rs b/examples/examples/z_bytes.rs index 874f08a002..9fcf788962 100644 --- a/examples/examples/z_bytes.rs +++ b/examples/examples/z_bytes.rs @@ -72,33 +72,32 @@ fn main() { // zenoh-ext serialization { - // Requires to import zenoh-ext trait - use zenoh_ext::ZBytesExt; + use zenoh_ext::{z_deserialize, z_serialize}; // Numeric types: u8, u16, u32, u128, i8, i16, i32, i128, f32, f64 let input = 1234_u32; - let payload = ZBytes::serialize(&input); - let output: u32 = payload.deserialize().unwrap(); + let payload = z_serialize(&input); + let output: u32 = z_deserialize(&payload).unwrap(); assert_eq!(input, output); // Vec let input = vec![0.0f32, 1.5, 42.0]; - let payload = ZBytes::serialize(&input); - let output: Vec = payload.deserialize().unwrap(); + 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 = ZBytes::serialize(&input); - let output: HashMap = payload.deserialize().unwrap(); + 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 = ZBytes::serialize(&input); - let output: (f64, String) = payload.deserialize().unwrap(); + let payload = z_serialize(&input); + let output: (f64, String) = z_deserialize(&payload).unwrap(); assert_eq!(input, output); // Look at Serialize/Deserialize documentation for the exhaustive diff --git a/zenoh-ext/Cargo.toml b/zenoh-ext/Cargo.toml index 4b06a97264..40c4ffbc2a 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 } diff --git a/zenoh-ext/src/lib.rs b/zenoh-ext/src/lib.rs index 45969e6c41..475284518f 100644 --- a/zenoh-ext/src/lib.rs +++ b/zenoh-ext/src/lib.rs @@ -14,20 +14,20 @@ pub mod group; mod publication_cache; mod querying_subscriber; +mod serialization; mod session_ext; mod subscriber_ext; -mod zbytes_ext; pub use publication_cache::{PublicationCache, PublicationCacheBuilder}; pub use querying_subscriber::{ FetchingSubscriber, FetchingSubscriberBuilder, QueryingSubscriberBuilder, }; +pub use serialization::{ + z_deserialize, z_serialize, Deserialize, Serialize, ZDeserializeError, ZDeserializer, + ZReadIter, ZSerializer, +}; pub use session_ext::SessionExt; pub use subscriber_ext::{SubscriberBuilderExt, SubscriberForward}; -pub use zbytes_ext::{ - Deserialize, Serialize, ZBytesExt, ZBytesReaderExt, ZBytesWriterExt, ZDeserializeError, - ZReadIter, -}; use zenoh::{internal::zerror, query::Reply, sample::Sample, Result as ZResult}; /// The space of keys to use in a [`FetchingSubscriber`]. diff --git a/zenoh-ext/src/serialization.rs b/zenoh-ext/src/serialization.rs new file mode 100644 index 0000000000..61a3186955 --- /dev/null +++ b/zenoh-ext/src/serialization.rs @@ -0,0 +1,359 @@ +use std::{ + borrow::Cow, + collections::{BTreeMap, BTreeSet, HashMap, HashSet}, + fmt, + hash::Hash, + io::{Read, Write}, + marker::PhantomData, + ptr, +}; + +use zenoh::bytes::{ZBytes, ZBytesReader, ZBytesWriter}; + +#[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 {} + +pub trait Serialize { + fn serialize(&self, serializer: &mut ZSerializer); + #[doc(hidden)] + fn serialize_slice(slice: &[Self], serializer: &mut ZSerializer) + where + Self: Sized, + { + serializer.serialize_iter(slice); + } +} +impl Serialize for &T { + fn serialize(&self, serializer: &mut ZSerializer) { + T::serialize(*self, serializer) + } +} + +pub trait Deserialize: Sized { + fn deserialize(deserializer: &mut ZDeserializer) -> Result; + #[doc(hidden)] + fn deserialize_slice( + deserializer: &mut ZDeserializer, + ) -> Result, ZDeserializeError> { + deserializer.deserialize_iter()?.collect() + } +} + +pub fn z_serialize(t: &T) -> ZBytes { + let mut zbytes = ZBytes::new(); + ZSerializer::new(&mut zbytes).serialize(t); + zbytes +} + +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<'a>(ZBytesWriter<'a>); + +impl<'a> ZSerializer<'a> { + pub fn new(zbytes: &'a mut ZBytes) -> 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.0.write_vle(iter.len() as u64); + for t in iter { + t.serialize(self); + } + } +} + +impl<'a> From> for ZSerializer<'a> { + fn from(value: ZBytesWriter<'a>) -> Self { + Self(value) + } +} + +#[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) + } + + fn read_vle(&mut self) -> Result { + Ok(self.0.read_vle().ok_or(ZDeserializeError)? as usize) + } + + pub fn deserialize_iter<'b, T: Deserialize>( + &'b mut self, + ) -> Result, ZDeserializeError> { + let len = self.read_vle()?; + Ok(ZReadIter { + deserializer: self, + len, + _phantom: PhantomData, + }) + } +} + +impl<'a> From> for ZDeserializer<'a> { + fn from(value: ZBytesReader<'a>) -> Self { + Self(value) + } +} + +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.0.write_vle(self.len() as u64); + 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_slice(slice: &[Self], serializer: &mut ZSerializer) where Self: Sized { + if cfg!(target_endian = "little") || std::mem::size_of::() == 1 { + serializer.0.write_vle(slice.len() as u64); + // SAFETY: transmuting numeric types to their little endian bytes is safe + serializer.0.write_all(unsafe { slice.align_to().1 }).unwrap(); + } else { + serializer.serialize_iter(slice); + } + } + } + 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_slice(deserializer: &mut ZDeserializer) -> Result, ZDeserializeError> { + let size = std::mem::size_of::(); + if cfg!(target_endian = "little") || size == 1 { + let len = deserializer.read_vle()? as usize; + let total_size = len * size; + let mut buf = std::mem::ManuallyDrop::new(vec![0; total_size].into_boxed_slice()); + deserializer.0.read_exact(&mut buf).or(Err(ZDeserializeError))?; + // SAFETY: transmuting numeric types from their little endian bytes is safe + Ok(unsafe { Box::from_raw(ptr::slice_from_raw_parts_mut(buf.as_mut_ptr().cast(), len)) }) + } else { + deserializer.deserialize_iter()?.collect() + } + } + } + )*}; +} +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), + } + } +} + +impl Serialize for [T] { + fn serialize(&self, serializer: &mut ZSerializer) { + T::serialize_slice(self, serializer) + } +} +impl<'a, T: Serialize + 'a> Serialize for Cow<'a, [T]> +where + [T]: ToOwned, +{ + fn serialize(&self, serializer: &mut ZSerializer) { + T::serialize_slice(self, serializer) + } +} +impl Serialize for Box<[T]> { + fn serialize(&self, serializer: &mut ZSerializer) { + T::serialize_slice(self, serializer) + } +} +impl Deserialize for Box<[T]> { + fn deserialize(deserializer: &mut ZDeserializer) -> Result { + T::deserialize_slice(deserializer) + } +} +impl Serialize for Vec { + fn serialize(&self, serializer: &mut ZSerializer) { + T::serialize_slice(self, serializer) + } +} +impl Deserialize for Vec { + fn deserialize(deserializer: &mut ZDeserializer) -> Result { + T::deserialize_slice(deserializer).map(Into::into) + } +} +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, +); diff --git a/zenoh-ext/src/zbytes_ext.rs b/zenoh-ext/src/zbytes_ext.rs deleted file mode 100644 index cfc817198c..0000000000 --- a/zenoh-ext/src/zbytes_ext.rs +++ /dev/null @@ -1,340 +0,0 @@ -use std::{ - borrow::Cow, - collections::{BTreeMap, BTreeSet, HashMap, HashSet}, - fmt, - hash::Hash, - io::{Read, Write}, - marker::PhantomData, - ptr, -}; - -use zenoh::bytes::{ZBytes, ZBytesReader, ZBytesWriter}; - -#[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 {} - -pub trait Serialize { - fn serialize(&self, writer: &mut ZBytesWriter); - #[doc(hidden)] - fn serialize_slice(slice: &[Self], writer: &mut ZBytesWriter) - where - Self: Sized, - { - writer.serialize_iter(slice) - } -} -impl Serialize for &T { - fn serialize(&self, writer: &mut ZBytesWriter) { - T::serialize(*self, writer) - } -} - -pub trait Deserialize: Sized { - fn deserialize(reader: &mut ZBytesReader) -> Result; - #[doc(hidden)] - fn deserialize_slice(reader: &mut ZBytesReader) -> Result, ZDeserializeError> { - reader.deserialize_iter::()?.collect() - } -} - -pub trait ZBytesExt { - fn serialize(t: &T) -> Self; - fn deserialize(&self) -> Result; -} - -impl ZBytesExt for ZBytes { - fn serialize(t: &T) -> Self { - let mut zbytes = ZBytes::new(); - t.serialize(&mut zbytes.writer()); - zbytes - } - - fn deserialize(&self) -> Result { - let mut reader = self.reader(); - let t = T::deserialize(&mut reader)?; - if !reader.is_empty() { - return Err(ZDeserializeError); - } - Ok(t) - } -} - -pub trait ZBytesWriterExt<'a> { - fn serialize(&mut self, t: T); - fn serialize_iter>(&mut self, iter: I) - where - I::IntoIter: ExactSizeIterator; -} - -impl<'a> ZBytesWriterExt<'a> for ZBytesWriter<'a> { - fn serialize(&mut self, t: T) { - t.serialize(self); - } - - fn serialize_iter>(&mut self, iter: I) - where - I::IntoIter: ExactSizeIterator, - { - let iter = iter.into_iter(); - self.write_vle(iter.len() as u64); - for t in iter { - t.serialize(self); - } - } -} - -pub trait ZBytesReaderExt<'a> { - fn deserialize(&mut self) -> Result; - fn deserialize_iter( - &mut self, - ) -> Result, ZDeserializeError>; -} -impl<'a> ZBytesReaderExt<'a> for ZBytesReader<'a> { - fn deserialize(&mut self) -> Result { - T::deserialize(self) - } - - fn deserialize_iter( - &mut self, - ) -> Result, ZDeserializeError> { - let len = self.read_vle().ok_or(ZDeserializeError)? as usize; - Ok(ZReadIter { - reader: self, - len, - _phantom: PhantomData, - }) - } -} - -pub struct ZReadIter<'a, 'b, T: Deserialize> { - reader: &'b mut ZBytesReader<'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.reader)) - } - - 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, writer: &mut ZBytesWriter) { - writer.write_vle(self.len() as u64); - writer.append(self.clone()) - } -} - -macro_rules! impl_num { - ($($ty:ty),* $(,)?) => {$( - impl Serialize for $ty { - fn serialize(&self, writer: &mut ZBytesWriter) { - writer.write_all(&(*self).to_le_bytes()).unwrap(); - } - fn serialize_slice(slice: &[Self], writer: &mut ZBytesWriter) where Self: Sized { - if cfg!(target_endian = "little") || std::mem::size_of::() == 1 { - writer.write_vle(slice.len() as u64); - // SAFETY: transmuting numeric types to their little endian bytes is safe - writer.write_all(unsafe { slice.align_to().1 }).unwrap(); - } else { - writer.serialize_iter(slice); - } - } - } - impl Deserialize for $ty { - fn deserialize(reader: &mut ZBytesReader) -> Result { - let mut buf = [0; { std::mem::size_of::() }]; - reader.read_exact(&mut buf).or(Err(ZDeserializeError))?; - Ok(<$ty>::from_le_bytes(buf)) - } - fn deserialize_slice(reader: &mut ZBytesReader) -> Result, ZDeserializeError> { - let size = std::mem::size_of::(); - if cfg!(target_endian = "little") || size == 1 { - let len = reader.read_vle().ok_or(ZDeserializeError)? as usize; - let total_size = len * size; - let mut buf = std::mem::ManuallyDrop::new(vec![0; total_size].into_boxed_slice()); - reader.read_exact(&mut buf).or(Err(ZDeserializeError))?; - // SAFETY: transmuting numeric types from their little endian bytes is safe - Ok(unsafe { Box::from_raw(ptr::slice_from_raw_parts_mut(buf.as_mut_ptr().cast(), len)) }) - } else { - reader.deserialize_iter::()?.collect() - } - } - } - )*}; -} -impl_num!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, f32, f64); - -impl Serialize for bool { - fn serialize(&self, writer: &mut ZBytesWriter) { - (*self as u8).serialize(writer); - } -} -impl Deserialize for bool { - fn deserialize(reader: &mut ZBytesReader) -> Result { - match u8::deserialize(reader)? { - 0 => Ok(false), - 1 => Ok(true), - _ => Err(ZDeserializeError), - } - } -} - -impl Serialize for [T] { - fn serialize(&self, writer: &mut ZBytesWriter) { - T::serialize_slice(self, writer) - } -} -impl<'a, T: Serialize + 'a> Serialize for Cow<'a, [T]> -where - [T]: ToOwned, -{ - fn serialize(&self, writer: &mut ZBytesWriter) { - T::serialize_slice(self, writer) - } -} -impl Serialize for Box<[T]> { - fn serialize(&self, writer: &mut ZBytesWriter) { - T::serialize_slice(self, writer) - } -} -impl Deserialize for Box<[T]> { - fn deserialize(reader: &mut ZBytesReader) -> Result { - T::deserialize_slice(reader) - } -} -impl Serialize for Vec { - fn serialize(&self, writer: &mut ZBytesWriter) { - T::serialize_slice(self, writer) - } -} -impl Deserialize for Vec { - fn deserialize(reader: &mut ZBytesReader) -> Result { - T::deserialize_slice(reader).map(Into::into) - } -} -impl Serialize for HashSet { - fn serialize(&self, writer: &mut ZBytesWriter) { - writer.serialize_iter(self); - } -} -impl Deserialize for HashSet { - fn deserialize(reader: &mut ZBytesReader) -> Result { - reader.deserialize_iter::()?.collect() - } -} -impl Serialize for BTreeSet { - fn serialize(&self, writer: &mut ZBytesWriter) { - writer.serialize_iter(self); - } -} -impl Deserialize for BTreeSet { - fn deserialize(reader: &mut ZBytesReader) -> Result { - reader.deserialize_iter::()?.collect() - } -} -impl Serialize for HashMap { - fn serialize(&self, writer: &mut ZBytesWriter) { - writer.serialize_iter(self); - } -} -impl Deserialize for HashMap { - fn deserialize(reader: &mut ZBytesReader) -> Result { - reader.deserialize_iter::<(K, V)>()?.collect() - } -} -impl Serialize for BTreeMap { - fn serialize(&self, writer: &mut ZBytesWriter) { - writer.serialize_iter(self); - } -} -impl Deserialize for BTreeMap { - fn deserialize(reader: &mut ZBytesReader) -> Result { - reader.deserialize_iter::<(K, V)>()?.collect() - } -} -impl Serialize for str { - fn serialize(&self, writer: &mut ZBytesWriter) { - self.as_bytes().serialize(writer); - } -} -impl Serialize for Cow<'_, str> { - fn serialize(&self, writer: &mut ZBytesWriter) { - self.as_bytes().serialize(writer); - } -} -impl Serialize for String { - fn serialize(&self, writer: &mut ZBytesWriter) { - self.as_bytes().serialize(writer); - } -} -impl Deserialize for String { - fn deserialize(reader: &mut ZBytesReader) -> Result { - String::from_utf8(Deserialize::deserialize(reader)?).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, writer: &mut ZBytesWriter) { - $(self.$i.serialize(writer);)* - } - } - #[allow(unused)] - impl<$($ty: Deserialize),*> Deserialize for ($($ty,)*) { - fn deserialize(reader: &mut ZBytesReader) -> Result { - Ok(($($ty::deserialize(reader)?,)*)) - } - } - }; -} -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, -); From aec6cf3b86af423d5afb200afd74522851a1202d Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Thu, 26 Sep 2024 10:34:13 +0200 Subject: [PATCH 12/21] fix: lints --- examples/examples/z_bytes_shm.rs | 9 +++------ examples/examples/z_get_shm.rs | 3 +-- examples/examples/z_put_float.rs | 9 +++------ examples/examples/z_queryable_shm.rs | 7 ++++--- examples/examples/z_sub_shm.rs | 10 ++++------ 5 files changed, 15 insertions(+), 23 deletions(-) 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_shm.rs b/examples/examples/z_get_shm.rs index 76421f2814..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, }; diff --git a/examples/examples/z_put_float.rs b/examples/examples/z_put_float.rs index 8a5584018e..176e626586 100644 --- a/examples/examples/z_put_float.rs +++ b/examples/examples/z_put_float.rs @@ -12,9 +12,9 @@ // ZettaScale Zenoh Team, // use clap::Parser; -use zenoh::{bytes::ZBytes, key_expr::KeyExpr, Config}; +use zenoh::{key_expr::KeyExpr, Config}; use zenoh_examples::CommonArgs; -use zenoh_ext::ZBytesExt; +use zenoh_ext::z_serialize; #[tokio::main] async fn main() { @@ -28,10 +28,7 @@ async fn main() { println!("Putting Float ('{key_expr}': '{payload}')..."); // you must have imported `zenoh_ext::ZBytesExt` to use `ZBytes::serialize` - session - .put(&key_expr, ZBytes::serialize(&payload)) - .await - .unwrap(); + session.put(&key_expr, z_serialize(&payload)).await.unwrap(); session.close().await.unwrap(); } diff --git a/examples/examples/z_queryable_shm.rs b/examples/examples/z_queryable_shm.rs index 1064bbebfa..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 diff --git a/examples/examples/z_sub_shm.rs b/examples/examples/z_sub_shm.rs index 9259e5d569..656f006e3d 100644 --- a/examples/examples/z_sub_shm.rs +++ b/examples/examples/z_sub_shm.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + // // Copyright (c) 2023 ZettaScale Technology // @@ -12,8 +14,6 @@ // ZettaScale Zenoh Team, // 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 From a3d5177eb2ad8b953afced26a22079ea8968f390 Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Thu, 26 Sep 2024 16:28:41 +0200 Subject: [PATCH 13/21] fix: add `?Sized` bound to `z_serialize` --- zenoh-ext/src/serialization.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zenoh-ext/src/serialization.rs b/zenoh-ext/src/serialization.rs index 61a3186955..3f0b13f78f 100644 --- a/zenoh-ext/src/serialization.rs +++ b/zenoh-ext/src/serialization.rs @@ -29,7 +29,7 @@ pub trait Serialize { serializer.serialize_iter(slice); } } -impl Serialize for &T { +impl Serialize for &T { fn serialize(&self, serializer: &mut ZSerializer) { T::serialize(*self, serializer) } @@ -45,7 +45,7 @@ pub trait Deserialize: Sized { } } -pub fn z_serialize(t: &T) -> ZBytes { +pub fn z_serialize(t: &T) -> ZBytes { let mut zbytes = ZBytes::new(); ZSerializer::new(&mut zbytes).serialize(t); zbytes From 1f11f57cc52fb211f83b4134b22233baf14a108a Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Thu, 26 Sep 2024 16:57:52 +0200 Subject: [PATCH 14/21] fix: add VarInt implementation --- zenoh-ext/src/lib.rs | 2 +- zenoh-ext/src/serialization.rs | 52 ++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/zenoh-ext/src/lib.rs b/zenoh-ext/src/lib.rs index 475284518f..8741571663 100644 --- a/zenoh-ext/src/lib.rs +++ b/zenoh-ext/src/lib.rs @@ -23,7 +23,7 @@ pub use querying_subscriber::{ FetchingSubscriber, FetchingSubscriberBuilder, QueryingSubscriberBuilder, }; pub use serialization::{ - z_deserialize, z_serialize, Deserialize, Serialize, ZDeserializeError, ZDeserializer, + z_deserialize, z_serialize, Deserialize, Serialize, VarInt, ZDeserializeError, ZDeserializer, ZReadIter, ZSerializer, }; pub use session_ext::SessionExt; diff --git a/zenoh-ext/src/serialization.rs b/zenoh-ext/src/serialization.rs index 3f0b13f78f..6776b31e67 100644 --- a/zenoh-ext/src/serialization.rs +++ b/zenoh-ext/src/serialization.rs @@ -357,3 +357,55 @@ impl_tuple!( T14 / 14, T15 / 15, ); + +#[repr(transparent)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct VarInt(T); + +impl VarInt { + pub fn new(int: T) -> Self { + Self(int) + } + + pub fn from_ref(int: &T) -> &Self { + // SAFETY: VInt is repr(transparent) + unsafe { &*(int as *const T as *const Self) } + } + + pub fn into_inner(self) -> T { + self.0 + } + + pub fn as_inner(&self) -> &T { + &self.0 + } +} + +macro_rules! impl_varint { + ($($u:ty: $i:ty),* $(,)?) => {$( + impl Serialize for VarInt<$u> { + fn serialize(&self, serializer: &mut ZSerializer) { + serializer.0.write_vle(self.0 as u64); + } + } + 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 = deserializer.0.read_vle().ok_or(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); From ddf3ee5924638e899da3beb83270251529410d42 Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Fri, 27 Sep 2024 15:45:45 +0200 Subject: [PATCH 15/21] feat!: ZBytesWriter/ZSerializer have no more lifetime --- Cargo.lock | 7 +++ Cargo.toml | 1 + commons/zenoh-buffers/src/zbuf.rs | 4 ++ examples/examples/z_bytes.rs | 4 +- zenoh-ext/Cargo.toml | 1 + zenoh-ext/src/serialization.rs | 76 +++++++++++++++++++++++-------- zenoh/src/api/bytes.rs | 66 +++++++++++++++------------ 7 files changed, 108 insertions(+), 51 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bd334f9db5..22dd5841fa 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" @@ -5616,6 +5622,7 @@ dependencies = [ "bincode", "flume", "futures", + "leb128", "serde", "tokio", "tracing", diff --git a/Cargo.toml b/Cargo.toml index 7a9f117385..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" diff --git a/commons/zenoh-buffers/src/zbuf.rs b/commons/zenoh-buffers/src/zbuf.rs index 457121dd3b..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); diff --git a/examples/examples/z_bytes.rs b/examples/examples/z_bytes.rs index 9fcf788962..c75932ef36 100644 --- a/examples/examples/z_bytes.rs +++ b/examples/examples/z_bytes.rs @@ -108,10 +108,10 @@ fn main() { use std::io::{Read, Write}; let input1 = &[0u8, 1]; let input2 = ZBytes::from([2, 3]); - let mut zbytes = ZBytes::new(); - let mut writer = zbytes.writer(); + 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]; diff --git a/zenoh-ext/Cargo.toml b/zenoh-ext/Cargo.toml index 40c4ffbc2a..a66b6559ee 100644 --- a/zenoh-ext/Cargo.toml +++ b/zenoh-ext/Cargo.toml @@ -45,6 +45,7 @@ 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 } diff --git a/zenoh-ext/src/serialization.rs b/zenoh-ext/src/serialization.rs index 6776b31e67..c69841734e 100644 --- a/zenoh-ext/src/serialization.rs +++ b/zenoh-ext/src/serialization.rs @@ -46,9 +46,9 @@ pub trait Deserialize: Sized { } pub fn z_serialize(t: &T) -> ZBytes { - let mut zbytes = ZBytes::new(); - ZSerializer::new(&mut zbytes).serialize(t); - zbytes + let mut serializer = ZSerializer::new(); + serializer.serialize(t); + serializer.finish() } pub fn z_deserialize(zbytes: &ZBytes) -> Result { @@ -61,11 +61,11 @@ pub fn z_deserialize(zbytes: &ZBytes) -> Result(ZBytesWriter<'a>); +pub struct ZSerializer(ZBytesWriter); -impl<'a> ZSerializer<'a> { - pub fn new(zbytes: &'a mut ZBytes) -> Self { - Self(zbytes.writer()) +impl ZSerializer { + pub fn new() -> Self { + Self(ZBytes::writer()) } pub fn serialize(&mut self, t: T) { @@ -77,15 +77,25 @@ impl<'a> ZSerializer<'a> { I::IntoIter: ExactSizeIterator, { let iter = iter.into_iter(); - self.0.write_vle(iter.len() as u64); + self.serialize(VarInt(iter.len())); for t in iter { t.serialize(self); } } + + pub fn finish(self) -> ZBytes { + self.0.finish() + } +} + +impl From for ZBytes { + fn from(value: ZSerializer) -> Self { + value.finish() + } } -impl<'a> From> for ZSerializer<'a> { - fn from(value: ZBytesWriter<'a>) -> Self { +impl From for ZSerializer { + fn from(value: ZBytesWriter) -> Self { Self(value) } } @@ -106,14 +116,10 @@ impl<'a> ZDeserializer<'a> { T::deserialize(self) } - fn read_vle(&mut self) -> Result { - Ok(self.0.read_vle().ok_or(ZDeserializeError)? as usize) - } - pub fn deserialize_iter<'b, T: Deserialize>( &'b mut self, ) -> Result, ZDeserializeError> { - let len = self.read_vle()?; + let len = >::deserialize(self)?.0; Ok(ZReadIter { deserializer: self, len, @@ -159,7 +165,7 @@ impl Drop for ZReadIter<'_, '_, T> { impl Serialize for ZBytes { fn serialize(&self, serializer: &mut ZSerializer) { - serializer.0.write_vle(self.len() as u64); + serializer.serialize(VarInt(self.len())); serializer.0.append(self.clone()); } } @@ -172,7 +178,7 @@ macro_rules! impl_num { } fn serialize_slice(slice: &[Self], serializer: &mut ZSerializer) where Self: Sized { if cfg!(target_endian = "little") || std::mem::size_of::() == 1 { - serializer.0.write_vle(slice.len() as u64); + serializer.serialize(VarInt(slice.len())); // SAFETY: transmuting numeric types to their little endian bytes is safe serializer.0.write_all(unsafe { slice.align_to().1 }).unwrap(); } else { @@ -189,7 +195,7 @@ macro_rules! impl_num { fn deserialize_slice(deserializer: &mut ZDeserializer) -> Result, ZDeserializeError> { let size = std::mem::size_of::(); if cfg!(target_endian = "little") || size == 1 { - let len = deserializer.read_vle()? as usize; + let len = >::deserialize(deserializer)?.0; let total_size = len * size; let mut buf = std::mem::ManuallyDrop::new(vec![0; total_size].into_boxed_slice()); deserializer.0.read_exact(&mut buf).or(Err(ZDeserializeError))?; @@ -383,9 +389,39 @@ impl VarInt { macro_rules! impl_varint { ($($u:ty: $i:ty),* $(,)?) => {$( + impl From<$u> for VarInt<$u> { + fn from(value: $u) -> Self { + Self(value) + } + } + impl From<$i> for VarInt<$i> { + fn from(value: $i) -> Self { + Self(value) + } + } + 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 AsRef<$u> for VarInt<$u> { + fn as_ref(&self) -> &$u { + &self.0 + } + } + impl AsRef<$i> for VarInt<$i> { + fn as_ref(&self) -> &$i { + &self.0 + } + } impl Serialize for VarInt<$u> { fn serialize(&self, serializer: &mut ZSerializer) { - serializer.0.write_vle(self.0 as u64); + leb128::write::unsigned(&mut serializer.0, self.0 as u64).unwrap(); } } impl Serialize for VarInt<$i> { @@ -396,7 +432,7 @@ macro_rules! impl_varint { } impl Deserialize for VarInt<$u> { fn deserialize(deserializer: &mut ZDeserializer) -> Result { - let n = deserializer.0.read_vle().ok_or(ZDeserializeError)?; + let n = leb128::read::unsigned(&mut deserializer.0).or(Err(ZDeserializeError))?; Ok(VarInt(<$u>::try_from(n).or(Err(ZDeserializeError))?)) } } diff --git a/zenoh/src/api/bytes.rs b/zenoh/src/api/bytes.rs index 548a01d64b..4dfe11aeb5 100644 --- a/zenoh/src/api/bytes.rs +++ b/zenoh/src/api/bytes.rs @@ -13,13 +13,12 @@ // //! ZBytes primitives. -use std::{borrow::Cow, fmt::Debug, str::Utf8Error}; +use std::{borrow::Cow, fmt::Debug, mem, str::Utf8Error}; use zenoh_buffers::{ buffer::{Buffer, SplitBuffer}, reader::{HasReader, Reader}, - writer::HasWriter, - ZBuf, ZBufReader, ZBufWriter, ZSlice, ZSliceBuffer, + ZBuf, ZBufReader, ZSlice, ZSliceBuffer, }; use zenoh_protocol::zenoh::ext::AttachmentType; @@ -141,8 +140,8 @@ impl ZBytes { /// 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()) + pub fn writer() -> ZBytesWriter { + Self::new().into() } /// Return an iterator on raw bytes slices contained in the [`ZBytes`]. @@ -235,13 +234,6 @@ impl ZBytesReader<'_> { pub fn is_empty(&self) -> bool { self.remaining() == 0 } - - #[zenoh_macros::internal] - pub fn read_vle(&mut self) -> Option { - use zenoh_codec::{RCodec, Zenoh080}; - let codec = Zenoh080::new(); - codec.read(&mut self.0).ok() - } } impl std::io::Read for ZBytesReader<'_> { @@ -257,11 +249,13 @@ impl std::io::Seek for ZBytesReader<'_> { } /// A writer that implements [`std::io::Write`] trait to serialize into a [`ZBytes`]. -#[repr(transparent)] #[derive(Debug)] -pub struct ZBytesWriter<'a>(ZBufWriter<'a>); +pub struct ZBytesWriter { + zbuf: ZBuf, + vec: Vec, +} -impl ZBytesWriter<'_> { +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. @@ -285,26 +279,41 @@ impl ZBytesWriter<'_> { /// let mut out: Vec = bytes.into(); /// assert_eq!(out, 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); } } - #[zenoh_macros::internal] - pub fn write_vle(&mut self, vle: u64) { - use zenoh_codec::{WCodec, Zenoh080}; - let codec = Zenoh080::new(); - codec.write(&mut self.0, vle).unwrap(); + 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 From for ZBytesWriter { + fn from(value: ZBytes) -> Self { + Self { + zbuf: value.0, + vec: vec![], + } + } +} + +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<()> { @@ -339,7 +348,6 @@ impl std::io::Write for ZBytesWriter<'_> { /// // let out: Vec = zbs.into(); /// assert_eq!(buf, out); /// ``` -#[repr(transparent)] #[derive(Debug)] pub struct ZBytesSliceIterator<'a>(ZBytesSliceIteratorInner<'a>); From 1b80456a43aff25ddbdfba35b5754e9bec558fa9 Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Fri, 27 Sep 2024 18:11:59 +0200 Subject: [PATCH 16/21] feat: use bytemuck for `VarInt` slice conversion --- Cargo.lock | 7 ++++ Cargo.toml | 1 + zenoh-ext/Cargo.toml | 1 + zenoh-ext/src/serialization.rs | 59 ++++++++++++++-------------------- 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 22dd5841fa..a336a7df9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -685,6 +685,12 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" +[[package]] +name = "bytemuck" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" + [[package]] name = "byteorder" version = "1.5.0" @@ -5620,6 +5626,7 @@ name = "zenoh-ext" version = "1.0.0-dev" dependencies = [ "bincode", + "bytemuck", "flume", "futures", "leb128", diff --git a/Cargo.toml b/Cargo.toml index 3f58ffae46..78454b740a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -86,6 +86,7 @@ async-trait = "0.1.82" base64 = "0.22.1" bincode = "1.3.3" bytes = "1.7.1" +bytemuck = "1" clap = { version = "4.5.17", features = ["derive"] } console-subscriber = "0.4.0" const_format = "0.2.33" diff --git a/zenoh-ext/Cargo.toml b/zenoh-ext/Cargo.toml index a66b6559ee..7d5db44101 100644 --- a/zenoh-ext/Cargo.toml +++ b/zenoh-ext/Cargo.toml @@ -40,6 +40,7 @@ tokio = { workspace = true, features = [ "io-std", ] } bincode = { workspace = true } +bytemuck = { workspace = true } zenoh-util = { workspace = true } flume = { workspace = true } futures = { workspace = true } diff --git a/zenoh-ext/src/serialization.rs b/zenoh-ext/src/serialization.rs index c69841734e..78dca6d3be 100644 --- a/zenoh-ext/src/serialization.rs +++ b/zenoh-ext/src/serialization.rs @@ -5,6 +5,7 @@ use std::{ hash::Hash, io::{Read, Write}, marker::PhantomData, + ops::{Deref, DerefMut}, ptr, }; @@ -366,39 +367,39 @@ impl_tuple!( #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct VarInt(T); +pub struct VarInt(pub T); -impl VarInt { - pub fn new(int: T) -> Self { - Self(int) - } +unsafe impl bytemuck::TransparentWrapper for VarInt {} +impl Deref for VarInt { + type Target = T; - pub fn from_ref(int: &T) -> &Self { - // SAFETY: VInt is repr(transparent) - unsafe { &*(int as *const T as *const Self) } + fn deref(&self) -> &Self::Target { + &self.0 } - - pub fn into_inner(self) -> T { - self.0 +} +impl DerefMut for VarInt { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 } - - pub fn as_inner(&self) -> &T { - &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<$u> for VarInt<$u> { - fn from(value: $u) -> Self { - Self(value) - } - } - impl From<$i> for VarInt<$i> { - fn from(value: $i) -> Self { - Self(value) - } - } impl From> for $u { fn from(value: VarInt<$u>) -> Self { value.0 @@ -409,16 +410,6 @@ macro_rules! impl_varint { value.0 } } - impl AsRef<$u> for VarInt<$u> { - fn as_ref(&self) -> &$u { - &self.0 - } - } - impl AsRef<$i> for VarInt<$i> { - fn as_ref(&self) -> &$i { - &self.0 - } - } impl Serialize for VarInt<$u> { fn serialize(&self, serializer: &mut ZSerializer) { leb128::write::unsigned(&mut serializer.0, self.0 as u64).unwrap(); From 8362a22017f71c810afa815fb777701b795fadd0 Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Fri, 27 Sep 2024 23:32:03 +0200 Subject: [PATCH 17/21] feat: remove bytemuck depedency --- Cargo.lock | 7 ------- Cargo.toml | 1 - zenoh-ext/Cargo.toml | 1 - zenoh-ext/src/serialization.rs | 28 ++++++++++++++++++++++++++-- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a336a7df9b..22dd5841fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -685,12 +685,6 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" -[[package]] -name = "bytemuck" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" - [[package]] name = "byteorder" version = "1.5.0" @@ -5626,7 +5620,6 @@ name = "zenoh-ext" version = "1.0.0-dev" dependencies = [ "bincode", - "bytemuck", "flume", "futures", "leb128", diff --git a/Cargo.toml b/Cargo.toml index 78454b740a..3f58ffae46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -86,7 +86,6 @@ async-trait = "0.1.82" base64 = "0.22.1" bincode = "1.3.3" bytes = "1.7.1" -bytemuck = "1" clap = { version = "4.5.17", features = ["derive"] } console-subscriber = "0.4.0" const_format = "0.2.33" diff --git a/zenoh-ext/Cargo.toml b/zenoh-ext/Cargo.toml index 7d5db44101..a66b6559ee 100644 --- a/zenoh-ext/Cargo.toml +++ b/zenoh-ext/Cargo.toml @@ -40,7 +40,6 @@ tokio = { workspace = true, features = [ "io-std", ] } bincode = { workspace = true } -bytemuck = { workspace = true } zenoh-util = { workspace = true } flume = { workspace = true } futures = { workspace = true } diff --git a/zenoh-ext/src/serialization.rs b/zenoh-ext/src/serialization.rs index 78dca6d3be..a368bc1684 100644 --- a/zenoh-ext/src/serialization.rs +++ b/zenoh-ext/src/serialization.rs @@ -368,8 +368,32 @@ impl_tuple!( #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct VarInt(pub T); - -unsafe impl bytemuck::TransparentWrapper for VarInt {} +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; From 3bf271b64891016b1867961b2750594890ff6276 Mon Sep 17 00:00:00 2001 From: Michael Ilyin Date: Sun, 29 Sep 2024 16:43:41 +0200 Subject: [PATCH 18/21] serializarion for zenoh::time::Timestamp --- examples/examples/z_bytes.rs | 11 +++++++++-- zenoh-ext/src/serialization.rs | 31 ++++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/examples/examples/z_bytes.rs b/examples/examples/z_bytes.rs index c75932ef36..2cc6d21789 100644 --- a/examples/examples/z_bytes.rs +++ b/examples/examples/z_bytes.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::{collections::HashMap, time::{SystemTime, UNIX_EPOCH}}; // // Copyright (c) 2024 ZettaScale Technology @@ -13,7 +13,7 @@ use std::collections::HashMap; // Contributors: // ZettaScale Zenoh Team, // -use zenoh::bytes::ZBytes; +use zenoh::{bytes::ZBytes, time::{Timestamp, TimestampId}}; fn main() { // Raw bytes @@ -100,6 +100,13 @@ fn main() { let output: (f64, String) = z_deserialize(&payload).unwrap(); assert_eq!(input, output); + // Zenoh types + let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().into(); + let input = Timestamp::new(now, TimestampId::rand()); + let payload = z_serialize(&input); + let output: Timestamp = z_deserialize(&payload).unwrap(); + assert_eq!(input, output); + // Look at Serialize/Deserialize documentation for the exhaustive // list of provided implementations } diff --git a/zenoh-ext/src/serialization.rs b/zenoh-ext/src/serialization.rs index a368bc1684..874b04cc34 100644 --- a/zenoh-ext/src/serialization.rs +++ b/zenoh-ext/src/serialization.rs @@ -9,7 +9,7 @@ use std::{ ptr, }; -use zenoh::bytes::{ZBytes, ZBytesReader, ZBytesWriter}; +use zenoh::{bytes::{ZBytes, ZBytesReader, ZBytesWriter}, time::{Timestamp, TimestampId, NTP64}}; #[derive(Debug)] pub struct ZDeserializeError; @@ -89,6 +89,12 @@ impl ZSerializer { } } +impl Default for ZSerializer { + fn default() -> Self { + Self::new() + } +} + impl From for ZBytes { fn from(value: ZSerializer) -> Self { value.finish() @@ -460,3 +466,26 @@ macro_rules! impl_varint { )*}; } impl_varint!(u8: i8, u16: i16, u32: i32, u64: i64, usize: isize); + +// +// Serialization/deseialization for zenoh types +// + +impl Serialize for zenoh::time::Timestamp { + fn serialize(&self, serializer: &mut ZSerializer) { + let time = self.get_time().as_u64(); + let id = self.get_id().to_le_bytes(); + time.serialize(serializer); + id.serialize(serializer); + } +} + +impl Deserialize for zenoh::time::Timestamp { + fn deserialize(deserializer: &mut ZDeserializer) -> Result { + let time = u64::deserialize(deserializer)?; + let time = NTP64(time); + let id = Vec::::deserialize(deserializer)?; + let id = id.as_slice().try_into().map_err(|_| ZDeserializeError)?; + Ok(Timestamp::new(time, id)) + } +} \ No newline at end of file From 795843ffb1f20a7fe22f8d4ebac3214915ff61dd Mon Sep 17 00:00:00 2001 From: Michael Ilyin Date: Sun, 29 Sep 2024 21:15:52 +0200 Subject: [PATCH 19/21] intermediate types serialization added --- zenoh-ext/src/serialization.rs | 38 +++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/zenoh-ext/src/serialization.rs b/zenoh-ext/src/serialization.rs index 874b04cc34..ee3066b0f9 100644 --- a/zenoh-ext/src/serialization.rs +++ b/zenoh-ext/src/serialization.rs @@ -471,21 +471,45 @@ impl_varint!(u8: i8, u16: i16, u32: i32, u64: i64, usize: isize); // Serialization/deseialization for zenoh types // -impl Serialize for zenoh::time::Timestamp { +impl Serialize for zenoh::time::NTP64 { fn serialize(&self, serializer: &mut ZSerializer) { - let time = self.get_time().as_u64(); - let id = self.get_id().to_le_bytes(); + let time = self.as_u64(); time.serialize(serializer); - id.serialize(serializer); } } -impl Deserialize for zenoh::time::Timestamp { +impl Deserialize for zenoh::time::NTP64 { fn deserialize(deserializer: &mut ZDeserializer) -> Result { let time = u64::deserialize(deserializer)?; - let time = NTP64(time); + Ok(NTP64(time)) + } +} + +impl Serialize for zenoh::time::TimestampId { + fn serialize(&self, serializer: &mut ZSerializer) { + self.to_le_bytes().serialize(serializer); + } +} + +impl Deserialize for zenoh::time::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 zenoh::time::Timestamp { + fn serialize(&self, serializer: &mut ZSerializer) { + self.get_time().serialize(serializer); + self.get_id().serialize(serializer); + } +} + +impl Deserialize for zenoh::time::Timestamp { + fn deserialize(deserializer: &mut ZDeserializer) -> Result { + let time = NTP64::deserialize(deserializer)?; + let id = TimestampId::deserialize(deserializer)?; Ok(Timestamp::new(time, id)) } -} \ No newline at end of file +} From ba934f80cf040ea06583689cbe8cdf094b015774 Mon Sep 17 00:00:00 2001 From: Michael Ilyin Date: Sun, 29 Sep 2024 22:00:08 +0200 Subject: [PATCH 20/21] encoding serialization added --- examples/examples/z_bytes.rs | 14 ++++++++++++-- zenoh-ext/src/serialization.rs | 29 +++++++++++++++++++++-------- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/examples/examples/z_bytes.rs b/examples/examples/z_bytes.rs index 2cc6d21789..27b40bc6e9 100644 --- a/examples/examples/z_bytes.rs +++ b/examples/examples/z_bytes.rs @@ -1,4 +1,3 @@ -use std::{collections::HashMap, time::{SystemTime, UNIX_EPOCH}}; // // Copyright (c) 2024 ZettaScale Technology @@ -13,7 +12,8 @@ use std::{collections::HashMap, time::{SystemTime, UNIX_EPOCH}}; // Contributors: // ZettaScale Zenoh Team, // -use zenoh::{bytes::ZBytes, time::{Timestamp, TimestampId}}; +use zenoh::{bytes::{Encoding, ZBytes}, time::{Timestamp, TimestampId}}; +use std::{collections::HashMap, str::FromStr, time::{SystemTime, UNIX_EPOCH}}; fn main() { // Raw bytes @@ -107,6 +107,16 @@ fn main() { let output: Timestamp = z_deserialize(&payload).unwrap(); assert_eq!(input, output); + let input = Encoding::TEXT_JSON; + let payload = z_serialize(&input); + let output: Encoding = z_deserialize(&payload).unwrap(); + assert_eq!(input, output); + + let input = Encoding::from_str("text/plain;foobar").unwrap(); + let payload = z_serialize(&input); + let output: Encoding = z_deserialize(&payload).unwrap(); + assert_eq!(input, output); + // Look at Serialize/Deserialize documentation for the exhaustive // list of provided implementations } diff --git a/zenoh-ext/src/serialization.rs b/zenoh-ext/src/serialization.rs index ee3066b0f9..f0dc67283c 100644 --- a/zenoh-ext/src/serialization.rs +++ b/zenoh-ext/src/serialization.rs @@ -6,10 +6,10 @@ use std::{ io::{Read, Write}, marker::PhantomData, ops::{Deref, DerefMut}, - ptr, + ptr, str::FromStr, }; -use zenoh::{bytes::{ZBytes, ZBytesReader, ZBytesWriter}, time::{Timestamp, TimestampId, NTP64}}; +use zenoh::{bytes::{Encoding, ZBytes, ZBytesReader, ZBytesWriter}, time::{Timestamp, TimestampId, NTP64}}; #[derive(Debug)] pub struct ZDeserializeError; @@ -471,27 +471,27 @@ impl_varint!(u8: i8, u16: i16, u32: i32, u64: i64, usize: isize); // Serialization/deseialization for zenoh types // -impl Serialize for zenoh::time::NTP64 { +impl Serialize for NTP64 { fn serialize(&self, serializer: &mut ZSerializer) { let time = self.as_u64(); time.serialize(serializer); } } -impl Deserialize for zenoh::time::NTP64 { +impl Deserialize for NTP64 { fn deserialize(deserializer: &mut ZDeserializer) -> Result { let time = u64::deserialize(deserializer)?; Ok(NTP64(time)) } } -impl Serialize for zenoh::time::TimestampId { +impl Serialize for TimestampId { fn serialize(&self, serializer: &mut ZSerializer) { self.to_le_bytes().serialize(serializer); } } -impl Deserialize for zenoh::time::TimestampId { +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)?; @@ -499,17 +499,30 @@ impl Deserialize for zenoh::time::TimestampId { } } -impl Serialize for zenoh::time::Timestamp { +impl Serialize for Timestamp { fn serialize(&self, serializer: &mut ZSerializer) { self.get_time().serialize(serializer); self.get_id().serialize(serializer); } } -impl Deserialize for zenoh::time::Timestamp { +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) + } +} From cf37dd653c9b25ba485b107976604898653b3b6b Mon Sep 17 00:00:00 2001 From: Michael Ilyin Date: Sun, 29 Sep 2024 22:01:05 +0200 Subject: [PATCH 21/21] cargo fmt --- examples/examples/z_bytes.rs | 13 ++++++++++--- zenoh-ext/src/serialization.rs | 10 +++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/examples/examples/z_bytes.rs b/examples/examples/z_bytes.rs index 27b40bc6e9..808a8a2ec2 100644 --- a/examples/examples/z_bytes.rs +++ b/examples/examples/z_bytes.rs @@ -1,4 +1,3 @@ - // // Copyright (c) 2024 ZettaScale Technology // @@ -12,8 +11,16 @@ // Contributors: // ZettaScale Zenoh Team, // -use zenoh::{bytes::{Encoding, ZBytes}, time::{Timestamp, TimestampId}}; -use std::{collections::HashMap, str::FromStr, time::{SystemTime, UNIX_EPOCH}}; +use std::{ + collections::HashMap, + str::FromStr, + time::{SystemTime, UNIX_EPOCH}, +}; + +use zenoh::{ + bytes::{Encoding, ZBytes}, + time::{Timestamp, TimestampId}, +}; fn main() { // Raw bytes diff --git a/zenoh-ext/src/serialization.rs b/zenoh-ext/src/serialization.rs index f0dc67283c..04b30a5976 100644 --- a/zenoh-ext/src/serialization.rs +++ b/zenoh-ext/src/serialization.rs @@ -6,10 +6,14 @@ use std::{ io::{Read, Write}, marker::PhantomData, ops::{Deref, DerefMut}, - ptr, str::FromStr, + ptr, + str::FromStr, }; -use zenoh::{bytes::{Encoding, ZBytes, ZBytesReader, ZBytesWriter}, time::{Timestamp, TimestampId, NTP64}}; +use zenoh::{ + bytes::{Encoding, ZBytes, ZBytesReader, ZBytesWriter}, + time::{Timestamp, TimestampId, NTP64}, +}; #[derive(Debug)] pub struct ZDeserializeError; @@ -502,7 +506,7 @@ impl Deserialize for TimestampId { impl Serialize for Timestamp { fn serialize(&self, serializer: &mut ZSerializer) { self.get_time().serialize(serializer); - self.get_id().serialize(serializer); + self.get_id().serialize(serializer); } }