Skip to content

Commit

Permalink
docs: add documentation for serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
wyfo committed Oct 17, 2024
1 parent 363e817 commit 86cbfaa
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 4 deletions.
111 changes: 107 additions & 4 deletions zenoh-ext/src/serialization.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
//
// Copyright (c) 2024 ZettaScale Technology
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
//
// Contributors:
// ZettaScale Zenoh Team, <[email protected]>
//
use std::{
borrow::Cow,
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
Expand All @@ -10,6 +23,7 @@ use std::{

use zenoh::bytes::{ZBytes, ZBytesReader, ZBytesWriter};

/// Error occurring in deserialization.
#[derive(Debug)]
pub struct ZDeserializeError;
impl fmt::Display for ZDeserializeError {
Expand All @@ -25,7 +39,15 @@ fn default_serialize_n<T: Serialize>(slice: &[T], serializer: &mut ZSerializer)
}
}

/// Serialization implementation.
///
/// See [Zenoh serialization format RFC][1].
///
/// [1]: https://github.com/eclipse-zenoh/roadmap/blob/main/rfcs/ALL/Serialization.md
pub trait Serialize {
/// Serialize the given object into a [`ZSerializer`].
///
/// User may prefer to use [`ZSerializer::serialize`] instead of this function.
fn serialize(&self, serializer: &mut ZSerializer);
#[doc(hidden)]
fn serialize_n(slice: &[Self], serializer: &mut ZSerializer)
Expand Down Expand Up @@ -62,7 +84,15 @@ fn default_deserialize_n_uninit<'a, T: Deserialize>(
Ok(unsafe { &mut *(in_place as *mut [MaybeUninit<T>] as *mut [T]) })
}

/// Deserialization implementation.
///
/// See [Zenoh serialization format RFC][1].
///
/// [1]: https://github.com/eclipse-zenoh/roadmap/blob/main/rfcs/ALL/Serialization.md
pub trait Deserialize: Sized {
/// Deserialize the given type from a [`ZDeserializer`].
///
/// User may prefer to use [`ZDeserializer::deserialize`] instead of this function.
fn deserialize(deserializer: &mut ZDeserializer) -> Result<Self, ZDeserializeError>;
#[doc(hidden)]
fn deserialize_n(
Expand All @@ -80,12 +110,36 @@ pub trait Deserialize: Sized {
}
}

/// Serialize an object according to the [Zenoh serialization format][1].
///
/// Serialization doesn't take the ownership of the data.
///
/// # Examples
///
/// ```rust
/// use zenoh_ext::*;
/// let zbytes = z_serialize(&(42i32, vec![1u8, 2, 3]));
/// assert_eq!(z_deserialize::<(i32, Vec<u8>)>(&zbytes).unwrap(), (42i32, vec![1u8, 2, 3]));
/// ```
///
/// [1]: https://github.com/eclipse-zenoh/roadmap/blob/main/rfcs/ALL/Serialization.md
pub fn z_serialize<T: Serialize + ?Sized>(t: &T) -> ZBytes {
let mut serializer = ZSerializer::new();
serializer.serialize(t);
serializer.finish()
}

/// Deserialize an object according to the [Zenoh serialization format][1].
///
/// # Examples
///
/// ```rust
/// use zenoh_ext::*;
/// let zbytes = z_serialize(&(42i32, vec![1u8, 2, 3]));
/// assert_eq!(z_deserialize::<(i32, Vec<u8>)>(&zbytes).unwrap(), (42i32, vec![1u8, 2, 3]));
/// ```
///
/// [1]: https://github.com/eclipse-zenoh/roadmap/blob/main/rfcs/ALL/Serialization.md
pub fn z_deserialize<T: Deserialize>(zbytes: &ZBytes) -> Result<T, ZDeserializeError> {
let mut deserializer = ZDeserializer::new(zbytes);
let t = T::deserialize(&mut deserializer)?;
Expand All @@ -95,18 +149,44 @@ pub fn z_deserialize<T: Deserialize>(zbytes: &ZBytes) -> Result<T, ZDeserializeE
Ok(t)
}

/// Serializer implementing the [Zenoh serialization format][1].
///
/// Serializing objects one after the other is equivalent to serialize a tuple of these objects.
///
/// # Examples
///
/// ```rust
/// use zenoh_ext::*;
/// let mut serializer = ZSerializer::new();
/// serializer.serialize(42i32);
/// serializer.serialize(vec![1u8, 2, 3]);
/// let zbytes = serializer.finish();
/// assert_eq!(z_deserialize::<(i32, Vec<u8>)>(&zbytes).unwrap(), (42i32, vec![1u8, 2, 3]));
/// ```
///
/// [1]: https://github.com/eclipse-zenoh/roadmap/blob/main/rfcs/ALL/Serialization.md
#[derive(Debug)]
pub struct ZSerializer(ZBytesWriter);

impl ZSerializer {
/// Instantiate a [`ZSerializer`].
pub fn new() -> Self {
Self(ZBytes::writer())
}

/// Serialize the given object into a [`ZSerializer`].
///
/// Serialization doesn't take the ownership of the data.
pub fn serialize<T: Serialize>(&mut self, t: T) {
t.serialize(self)
}

/// Serialize the given iterator into a [`ZSerializer`].
///
/// Sequence serialized with this method may be deserialized with [`ZDeserializer::deserialize_iter`].
/// See [Zenoh serialization format RFC][1].
///
/// [1]: https://github.com/eclipse-zenoh/roadmap/blob/main/rfcs/ALL/Serialization.md#sequences
pub fn serialize_iter<T: Serialize, I: IntoIterator<Item = T>>(&mut self, iter: I)
where
I::IntoIter: ExactSizeIterator,
Expand All @@ -118,10 +198,7 @@ impl ZSerializer {
}
}

pub fn serialize_n<T: Serialize>(&mut self, ts: &[T]) {
T::serialize_n(ts, self);
}

/// Finish serialization by returning a [`ZBytes`].
pub fn finish(self) -> ZBytes {
self.0.finish()
}
Expand All @@ -139,22 +216,47 @@ impl From<ZSerializer> for ZBytes {
}
}

/// Deserializer implementing the [Zenoh serialization format][1].
///
/// Deserializing objects one after the other is equivalent to serialize a tuple of these objects.
///
/// # Examples
///
/// ```rust
/// use zenoh_ext::*;
/// let zbytes = z_serialize(&(42i32, vec![1u8, 2, 3]));
/// let mut deserializer = ZDeserializer::new(&zbytes);
/// assert_eq!(deserializer.deserialize::<i32>().unwrap(), 42i32);
/// assert_eq!(deserializer.deserialize::<Vec<u8>>().unwrap(), vec![1u8, 2, 3]);
/// assert!(deserializer.done())
/// ```
///
/// [1]: https://github.com/eclipse-zenoh/roadmap/blob/main/rfcs/ALL/Serialization.md
#[derive(Debug)]
pub struct ZDeserializer<'a>(ZBytesReader<'a>);

impl<'a> ZDeserializer<'a> {
/// Instantiate a [`ZDeserializer`] from a [`ZBytes`].
pub fn new(zbytes: &'a ZBytes) -> Self {
Self(zbytes.reader())
}

/// Return true if there is no data left to deserialize.
pub fn done(&self) -> bool {
self.0.is_empty()
}

/// Deserialize the given type from a [`ZDeserializer`].
pub fn deserialize<T: Deserialize>(&mut self) -> Result<T, ZDeserializeError> {
T::deserialize(self)
}

/// Deserialize an iterator into a [`ZDeserializer`].
///
/// Sequence deserialized with this method may have been serialized with [`ZSerializer::serialize_iter`].
/// See [Zenoh serialization format RFC][1].
///
/// [1]: https://github.com/eclipse-zenoh/roadmap/blob/main/rfcs/ALL/Serialization.md#sequences
pub fn deserialize_iter<'b, T: Deserialize>(
&'b mut self,
) -> Result<ZReadIter<'a, 'b, T>, ZDeserializeError> {
Expand All @@ -167,6 +269,7 @@ impl<'a> ZDeserializer<'a> {
}
}

/// Iterator returned by [`ZDeserializer::deserialize_iter`].
pub struct ZReadIter<'a, 'b, T: Deserialize> {
deserializer: &'b mut ZDeserializer<'a>,
len: usize,
Expand Down
11 changes: 11 additions & 0 deletions zenoh/src/api/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,21 @@ impl ZBytes {
self.0.len()
}

/// Access raw bytes contained in the [`ZBytes`].
///
/// In the case `ZBytes` contains non-contiguous regions of memory, an allocation and a copy
/// will be done, that's why the method returns a [`Cow`].
/// It's also possible to use [`ZBytes::slices`] instead to avoid this copy.
pub fn to_bytes(&self) -> Cow<[u8]> {
self.0.contiguous()
}

/// Try to access a string contained in the [`ZBytes`], fail if it contains non-UTF8 bytes.
///
/// In the case `ZBytes` contains non-contiguous regions of memory, an allocation and a copy
/// will be done, that's why the method returns a [`Cow`].
/// It's also possible to use [`ZBytes::slices`] instead to avoid this copy, but then the UTF8
/// check has to be done manually.
pub fn try_to_string(&self) -> Result<Cow<str>, Utf8Error> {
Ok(match self.to_bytes() {
Cow::Borrowed(s) => std::str::from_utf8(s)?.into(),
Expand Down

0 comments on commit 86cbfaa

Please sign in to comment.