Skip to content

Commit

Permalink
Encoding encoder (#746)
Browse files Browse the repository at this point in the history
* Encoding contains a mapping

* Add forgotten file

* Provide default encoder

* Refine encoder

* Fix encoding codec

* Do not change the protocol representation

* Accept Cow<'static, str> in EncodingMapping trait

* Improve Value::Display

* Fix doctests

* Bump EncodingPrefix to u16. Add IANA encoding mapping.

* Improve doc

* Remove generic from Encoding::starts_with

* Remove Display impl for Encoding

* Improve doc

* Improve doc

* Improve encoding parsing

* Improve comments

* Improve doc

* Encoding suffix bitflag

* Encoder/Decoder traits take self

* Rename encoding() to with_encoding()

* Make Value, ZBuf, SingleOrVec empty() const

* Derive Encoder for &mut u* and i*

* Integers are encoded as le_bytes are not as string

* Integers are encoded as le_bytes are not as string

* Fix doctest
  • Loading branch information
Mallets authored Feb 26, 2024
1 parent cbda61a commit 2036826
Show file tree
Hide file tree
Showing 32 changed files with 11,077 additions and 931 deletions.
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions commons/zenoh-buffers/src/zbuf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@ pub struct ZBuf {

impl ZBuf {
#[must_use]
pub fn empty() -> Self {
Self::default()
pub const fn empty() -> Self {
Self {
slices: SingleOrVec::empty(),
}
}

pub fn clear(&mut self) {
Expand Down
31 changes: 24 additions & 7 deletions commons/zenoh-buffers/src/zslice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,24 +92,41 @@ pub struct ZSlice {
}

impl ZSlice {
#[deprecated(note = "use `new` instead")]
pub fn make(
buf: Arc<dyn ZSliceBuffer>,
start: usize,
end: usize,
) -> Result<ZSlice, Arc<dyn ZSliceBuffer>> {
Self::new(buf, start, end)
}

pub fn new(
buf: Arc<dyn ZSliceBuffer>,
start: usize,
end: usize,
) -> Result<ZSlice, Arc<dyn ZSliceBuffer>> {
if start <= end && end <= buf.as_slice().len() {
Ok(ZSlice {
buf,
start,
end,
#[cfg(feature = "shared-memory")]
kind: ZSliceKind::Raw,
})
// unsafe: this operation is safe because we just checked the slice boundaries
Ok(unsafe { ZSlice::new_unchecked(buf, start, end) })
} else {
Err(buf)
}
}

/// # Safety
/// This function does not verify wether the `start` and `end` indexes are within the buffer boundaries.
/// If a [`ZSlice`] is built via this constructor, a later access may panic if `start` and `end` indexes are out-of-bound.
pub unsafe fn new_unchecked(buf: Arc<dyn ZSliceBuffer>, start: usize, end: usize) -> Self {
ZSlice {
buf,
start,
end,
#[cfg(feature = "shared-memory")]
kind: ZSliceKind::Raw,
}
}

#[inline]
#[must_use]
pub fn downcast_ref<T>(&self) -> Option<&T>
Expand Down
2 changes: 1 addition & 1 deletion commons/zenoh-codec/benches/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ fn criterion_benchmark(c: &mut Criterion) {
let mut idx = 0;
while idx < zslice.len() {
let len = (zslice.len() - idx).min(chunk);
zbuf.push_zslice(ZSlice::make(buff.clone(), idx, idx + len).unwrap());
zbuf.push_zslice(ZSlice::new(buff.clone(), idx, idx + len).unwrap());
idx += len;
}

Expand Down
49 changes: 40 additions & 9 deletions commons/zenoh-codec/src/core/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,19 @@ use zenoh_buffers::{
reader::{DidntRead, Reader},
writer::{DidntWrite, Writer},
};
use zenoh_protocol::core::{Encoding, EncodingPrefix};
use zenoh_protocol::{
common::imsg,
core::encoding::{flag, Encoding, EncodingPrefix},
};

impl LCodec<&Encoding> for Zenoh080 {
fn w_len(self, x: &Encoding) -> usize {
1 + self.w_len(x.suffix())
let (prefix, suffix) = (x.prefix(), x.suffix());
let mut len = self.w_len((prefix as u32) << 1);
if !suffix.is_empty() {
len += self.w_len(x.suffix());
}
len
}
}

Expand All @@ -32,9 +40,18 @@ where
type Output = Result<(), DidntWrite>;

fn write(self, writer: &mut W, x: &Encoding) -> Self::Output {
let zodec = Zenoh080Bounded::<EncodingPrefix>::new();
zodec.write(&mut *writer, x.prefix())?;
zodec.write(&mut *writer, x.suffix())?;
let mut prefix = (x.prefix() as u32) << 1;
let suffix = x.suffix();

if !suffix.is_empty() {
prefix |= flag::S;
}
let zodec = Zenoh080Bounded::<u32>::new();
zodec.write(&mut *writer, prefix)?;
if !suffix.is_empty() {
let zodec = Zenoh080Bounded::<u8>::new();
zodec.write(&mut *writer, suffix)?;
}
Ok(())
}
}
Expand All @@ -46,10 +63,24 @@ where
type Error = DidntRead;

fn read(self, reader: &mut R) -> Result<Encoding, Self::Error> {
let zodec = Zenoh080Bounded::<EncodingPrefix>::new();
let prefix: EncodingPrefix = zodec.read(&mut *reader)?;
let suffix: String = zodec.read(&mut *reader)?;
let encoding = Encoding::new(prefix, suffix).map_err(|_| DidntRead)?;
let zodec = Zenoh080Bounded::<u32>::new();
let prefix: u32 = zodec.read(&mut *reader)?;
let (prefix, has_suffix) = (
(prefix >> 1) as EncodingPrefix,
imsg::has_flag(prefix as u8, flag::S as u8),
);

let mut suffix = String::new();
if has_suffix {
let zodec = Zenoh080Bounded::<u8>::new();
suffix = zodec.read(&mut *reader)?;
}

let mut encoding: Encoding = Encoding::new(prefix);
if !suffix.is_empty() {
encoding = encoding.with_suffix(suffix).map_err(|_| DidntRead)?;
}

Ok(encoding)
}
}
10 changes: 9 additions & 1 deletion commons/zenoh-collections/src/single_or_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ enum SingleOrVecInner<T> {
}

impl<T> SingleOrVecInner<T> {
const fn empty() -> Self {
SingleOrVecInner::Vec(Vec::new())
}

fn push(&mut self, value: T) {
match self {
SingleOrVecInner::Vec(vec) if vec.capacity() == 0 => *self = Self::Single(value),
Expand All @@ -50,7 +54,7 @@ where

impl<T> Default for SingleOrVecInner<T> {
fn default() -> Self {
SingleOrVecInner::Vec(Vec::new())
Self::empty()
}
}

Expand Down Expand Up @@ -85,6 +89,10 @@ where
pub struct SingleOrVec<T>(SingleOrVecInner<T>);

impl<T> SingleOrVec<T> {
pub const fn empty() -> Self {
Self(SingleOrVecInner::empty())
}

pub fn push(&mut self, value: T) {
self.0.push(value);
}
Expand Down
1 change: 0 additions & 1 deletion commons/zenoh-protocol/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ complete_n = []
const_format = { workspace = true }
hex = { workspace = true, features = ["alloc"] }
rand = { workspace = true, features = ["alloc", "getrandom"], optional = true }
phf = { workspace = true }
serde = { workspace = true, features = ["alloc"] }
uhlc = { workspace = true, default-features = false }
uuid = { workspace = true } # Needs a getrandom::getrandom() custom implementation on embedded (in root crate)
Expand Down
Loading

0 comments on commit 2036826

Please sign in to comment.