Skip to main content

zenoh_buffers/
lib.rs

1//
2// Copyright (c) 2023 ZettaScale Technology
3//
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7// which is available at https://www.apache.org/licenses/LICENSE-2.0.
8//
9// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10//
11// Contributors:
12//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>
13//
14
15//! ⚠️ WARNING ⚠️
16//!
17//! This crate is intended for Zenoh's internal use.
18//!
19//! [Click here for Zenoh's documentation](https://docs.rs/zenoh/latest/zenoh)
20//!
21//! Provide different buffer implementations used for serialization and deserialization.
22#![cfg_attr(not(feature = "std"), no_std)]
23extern crate alloc;
24
25mod bbuf;
26mod slice;
27pub mod vec;
28mod zbuf;
29mod zslice;
30
31pub use bbuf::*;
32pub use zbuf::*;
33pub use zslice::*;
34
35// SAFETY: this crate operates on eventually initialized slices for read and write. Because of that, internal buffers
36//         implementation keeps track of various slices indexes. Boundaries checks are performed by individual
37//         implementations every time they need to access a slices. This means, that accessing a slice with [<range>]
38//         syntax after having already verified the indexes will force the compiler to verify again the slice
39//         boundaries. In case of access violation the program will panic. However, it is desirable to avoid redundant
40//         checks for performance reasons. Nevertheless, it is desirable to keep those checks for testing and debugging
41//         purposes. Hence, the macros below will allow to switch boundaries check in case of test and to avoid them in
42//         all the other cases.
43#[cfg(any(test, feature = "test"))]
44#[macro_export]
45macro_rules! unsafe_slice {
46    ($s:expr,$r:expr) => {
47        &$s[$r]
48    };
49}
50
51#[cfg(any(test, feature = "test"))]
52#[macro_export]
53macro_rules! unsafe_slice_mut {
54    ($s:expr,$r:expr) => {
55        &mut $s[$r]
56    };
57}
58
59#[cfg(all(not(test), not(feature = "test")))]
60#[macro_export]
61macro_rules! unsafe_slice {
62    ($s:expr,$r:expr) => {{
63        let slice = &*$s;
64        let index = $r;
65        unsafe { slice.get_unchecked(index) }
66    }};
67}
68
69#[cfg(all(not(test), not(feature = "test")))]
70#[macro_export]
71macro_rules! unsafe_slice_mut {
72    ($s:expr,$r:expr) => {{
73        let slice = &mut *$s;
74        let index = $r;
75        unsafe { slice.get_unchecked_mut(index) }
76    }};
77}
78
79pub mod buffer {
80    use alloc::{borrow::Cow, vec::Vec};
81
82    pub trait Buffer {
83        /// Returns the number of bytes in the buffer.
84        fn len(&self) -> usize;
85
86        /// Returns `true` if the buffer has a length of 0.
87        fn is_empty(&self) -> bool {
88            self.len() == 0
89        }
90    }
91
92    /// A trait for buffers that can be composed of multiple non contiguous slices.
93    pub trait SplitBuffer: Buffer {
94        type Slices<'a>: Iterator<Item = &'a [u8]> + ExactSizeIterator
95        where
96            Self: 'a;
97
98        /// Gets all the slices of this buffer.
99        fn slices(&self) -> Self::Slices<'_>;
100
101        /// Returns all the bytes of this buffer in a contiguous slice.
102        /// This may require allocation and copy if the original buffer
103        /// is not contiguous.
104        fn contiguous(&self) -> Cow<'_, [u8]> {
105            let mut slices = self.slices();
106            match slices.len() {
107                0 => Cow::Borrowed(b""),
108                1 => {
109                    // SAFETY: unwrap here is safe because we have explicitly checked
110                    //         the iterator has 1 element.
111                    Cow::Borrowed(unsafe { slices.next().unwrap_unchecked() })
112                }
113                _ => Cow::Owned(slices.fold(Vec::with_capacity(self.len()), |mut acc, it| {
114                    acc.extend_from_slice(it);
115                    acc
116                })),
117            }
118        }
119    }
120}
121
122pub mod writer {
123    use core::num::NonZeroUsize;
124
125    use crate::ZSlice;
126
127    #[derive(Debug, Clone, Copy)]
128    pub struct DidntWrite;
129
130    pub trait Writer {
131        fn write(&mut self, bytes: &[u8]) -> Result<NonZeroUsize, DidntWrite>;
132        fn write_exact(&mut self, bytes: &[u8]) -> Result<(), DidntWrite>;
133        fn remaining(&self) -> usize;
134
135        fn write_u8(&mut self, byte: u8) -> Result<(), DidntWrite> {
136            self.write_exact(core::slice::from_ref(&byte))
137        }
138        #[inline(always)]
139        fn write_zslice(&mut self, slice: &ZSlice) -> Result<(), DidntWrite> {
140            self.write_exact(slice.as_slice())
141        }
142        fn can_write(&self) -> bool {
143            self.remaining() != 0
144        }
145        /// Provides a buffer of exactly `len` uninitialized bytes to `write` to allow in-place writing.
146        /// `write` must return the number of bytes it actually wrote.
147        ///
148        /// # Safety
149        ///
150        /// Caller must ensure that `write` return an integer lesser than or equal to the length of
151        /// the slice passed in argument
152        unsafe fn with_slot<F>(&mut self, len: usize, write: F) -> Result<NonZeroUsize, DidntWrite>
153        where
154            F: FnOnce(&mut [u8]) -> usize;
155    }
156
157    impl<W: Writer + ?Sized> Writer for &mut W {
158        fn write(&mut self, bytes: &[u8]) -> Result<NonZeroUsize, DidntWrite> {
159            (**self).write(bytes)
160        }
161        fn write_exact(&mut self, bytes: &[u8]) -> Result<(), DidntWrite> {
162            (**self).write_exact(bytes)
163        }
164        fn remaining(&self) -> usize {
165            (**self).remaining()
166        }
167        fn write_u8(&mut self, byte: u8) -> Result<(), DidntWrite> {
168            (**self).write_u8(byte)
169        }
170        fn write_zslice(&mut self, slice: &ZSlice) -> Result<(), DidntWrite> {
171            (**self).write_zslice(slice)
172        }
173        fn can_write(&self) -> bool {
174            (**self).can_write()
175        }
176        unsafe fn with_slot<F>(&mut self, len: usize, write: F) -> Result<NonZeroUsize, DidntWrite>
177        where
178            F: FnOnce(&mut [u8]) -> usize,
179        {
180            // SAFETY: same precondition
181            unsafe { (**self).with_slot(len, write) }
182        }
183    }
184
185    pub trait BacktrackableWriter: Writer {
186        type Mark;
187
188        fn mark(&mut self) -> Self::Mark;
189        fn rewind(&mut self, mark: Self::Mark) -> bool;
190    }
191
192    impl<W: BacktrackableWriter + ?Sized> BacktrackableWriter for &mut W {
193        type Mark = W::Mark;
194        fn mark(&mut self) -> Self::Mark {
195            (**self).mark()
196        }
197        fn rewind(&mut self, mark: Self::Mark) -> bool {
198            (**self).rewind(mark)
199        }
200    }
201
202    pub trait HasWriter {
203        type Writer: Writer;
204
205        /// Returns the most appropriate writer for `self`
206        fn writer(self) -> Self::Writer;
207    }
208}
209
210pub mod reader {
211    use core::num::NonZeroUsize;
212
213    use crate::{ZBuf, ZSlice};
214
215    #[derive(Debug, Clone, Copy)]
216    pub struct DidntRead;
217
218    pub trait Reader {
219        fn read(&mut self, into: &mut [u8]) -> Result<NonZeroUsize, DidntRead>;
220        fn read_exact(&mut self, into: &mut [u8]) -> Result<(), DidntRead>;
221        fn remaining(&self) -> usize;
222
223        fn read_zbuf(&mut self, len: usize) -> Result<ZBuf, DidntRead> {
224            let mut buf = ZBuf::empty();
225            self.read_zslices(len, |s| buf.push_zslice(s))?;
226            Ok(buf)
227        }
228
229        /// Returns an iterator of `ZSlices` such that the sum of their length is _exactly_ `len`.
230        fn read_zslices<F: FnMut(ZSlice)>(
231            &mut self,
232            len: usize,
233            for_each_slice: F,
234        ) -> Result<(), DidntRead>;
235
236        /// Reads exactly `len` bytes, returning them as a single `ZSlice`.
237        fn read_zslice(&mut self, len: usize) -> Result<ZSlice, DidntRead>;
238
239        fn read_u8(&mut self) -> Result<u8, DidntRead> {
240            let mut byte = 0;
241            let read = self.read(core::slice::from_mut(&mut byte))?;
242            if read.get() == 1 {
243                Ok(byte)
244            } else {
245                Err(DidntRead)
246            }
247        }
248
249        fn can_read(&self) -> bool {
250            self.remaining() != 0
251        }
252    }
253
254    impl<R: Reader + ?Sized> Reader for &mut R {
255        #[inline(always)]
256        fn read(&mut self, into: &mut [u8]) -> Result<NonZeroUsize, DidntRead> {
257            (**self).read(into)
258        }
259        #[inline(always)]
260        fn read_exact(&mut self, into: &mut [u8]) -> Result<(), DidntRead> {
261            (**self).read_exact(into)
262        }
263        #[inline(always)]
264        fn remaining(&self) -> usize {
265            (**self).remaining()
266        }
267        #[inline(always)]
268        fn read_zbuf(&mut self, len: usize) -> Result<ZBuf, DidntRead> {
269            (**self).read_zbuf(len)
270        }
271        #[inline(always)]
272        fn read_zslices<F: FnMut(ZSlice)>(
273            &mut self,
274            len: usize,
275            for_each_slice: F,
276        ) -> Result<(), DidntRead> {
277            (**self).read_zslices(len, for_each_slice)
278        }
279        #[inline(always)]
280        fn read_zslice(&mut self, len: usize) -> Result<ZSlice, DidntRead> {
281            (**self).read_zslice(len)
282        }
283        #[inline(always)]
284        fn read_u8(&mut self) -> Result<u8, DidntRead> {
285            (**self).read_u8()
286        }
287        #[inline(always)]
288        fn can_read(&self) -> bool {
289            (**self).can_read()
290        }
291    }
292
293    pub trait BacktrackableReader: Reader {
294        type Mark;
295
296        fn mark(&mut self) -> Self::Mark;
297        fn rewind(&mut self, mark: Self::Mark) -> bool;
298    }
299
300    impl<R: BacktrackableReader + ?Sized> BacktrackableReader for &mut R {
301        type Mark = R::Mark;
302        fn mark(&mut self) -> Self::Mark {
303            (**self).mark()
304        }
305        fn rewind(&mut self, mark: Self::Mark) -> bool {
306            (**self).rewind(mark)
307        }
308    }
309
310    pub trait AdvanceableReader: Reader {
311        fn skip(&mut self, offset: usize) -> Result<(), DidntRead>;
312        fn backtrack(&mut self, offset: usize) -> Result<(), DidntRead>;
313        fn advance(&mut self, offset: isize) -> Result<(), DidntRead> {
314            if offset > 0 {
315                self.skip(offset as usize)
316            } else {
317                self.backtrack((-offset) as usize)
318            }
319        }
320    }
321
322    #[derive(Debug, Clone, Copy)]
323    pub struct DidntSiphon;
324
325    pub trait SiphonableReader: Reader {
326        fn siphon<W>(&mut self, writer: &mut W) -> Result<NonZeroUsize, DidntSiphon>
327        where
328            W: crate::writer::Writer;
329    }
330
331    pub trait HasReader {
332        type Reader: Reader;
333
334        /// Returns the most appropriate reader for `self`
335        fn reader(self) -> Self::Reader;
336    }
337}