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 conitguous 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        fn write_zslice(&mut self, slice: &ZSlice) -> Result<(), DidntWrite> {
139            self.write_exact(slice.as_slice())
140        }
141        fn can_write(&self) -> bool {
142            self.remaining() != 0
143        }
144        /// Provides a buffer of exactly `len` uninitialized bytes to `write` to allow in-place writing.
145        /// `write` must return the number of bytes it actually wrote.
146        ///
147        /// # Safety
148        ///
149        /// Caller must ensure that `write` return an integer lesser than or equal to the length of
150        /// the slice passed in argument
151        unsafe fn with_slot<F>(&mut self, len: usize, write: F) -> Result<NonZeroUsize, DidntWrite>
152        where
153            F: FnOnce(&mut [u8]) -> usize;
154    }
155
156    impl<W: Writer + ?Sized> Writer for &mut W {
157        fn write(&mut self, bytes: &[u8]) -> Result<NonZeroUsize, DidntWrite> {
158            (**self).write(bytes)
159        }
160        fn write_exact(&mut self, bytes: &[u8]) -> Result<(), DidntWrite> {
161            (**self).write_exact(bytes)
162        }
163        fn remaining(&self) -> usize {
164            (**self).remaining()
165        }
166        fn write_u8(&mut self, byte: u8) -> Result<(), DidntWrite> {
167            (**self).write_u8(byte)
168        }
169        fn write_zslice(&mut self, slice: &ZSlice) -> Result<(), DidntWrite> {
170            (**self).write_zslice(slice)
171        }
172        fn can_write(&self) -> bool {
173            (**self).can_write()
174        }
175        unsafe fn with_slot<F>(&mut self, len: usize, write: F) -> Result<NonZeroUsize, DidntWrite>
176        where
177            F: FnOnce(&mut [u8]) -> usize,
178        {
179            // SAFETY: same precondition
180            unsafe { (**self).with_slot(len, write) }
181        }
182    }
183
184    pub trait BacktrackableWriter: Writer {
185        type Mark;
186
187        fn mark(&mut self) -> Self::Mark;
188        fn rewind(&mut self, mark: Self::Mark) -> bool;
189    }
190
191    impl<W: BacktrackableWriter + ?Sized> BacktrackableWriter for &mut W {
192        type Mark = W::Mark;
193        fn mark(&mut self) -> Self::Mark {
194            (**self).mark()
195        }
196        fn rewind(&mut self, mark: Self::Mark) -> bool {
197            (**self).rewind(mark)
198        }
199    }
200
201    pub trait HasWriter {
202        type Writer: Writer;
203
204        /// Returns the most appropriate writer for `self`
205        fn writer(self) -> Self::Writer;
206    }
207}
208
209pub mod reader {
210    use core::num::NonZeroUsize;
211
212    use crate::ZSlice;
213
214    #[derive(Debug, Clone, Copy)]
215    pub struct DidntRead;
216
217    pub trait Reader {
218        fn read(&mut self, into: &mut [u8]) -> Result<NonZeroUsize, DidntRead>;
219        fn read_exact(&mut self, into: &mut [u8]) -> Result<(), DidntRead>;
220        fn remaining(&self) -> usize;
221
222        /// Returns an iterator of `ZSlices` such that the sum of their length is _exactly_ `len`.
223        fn read_zslices<F: FnMut(ZSlice)>(
224            &mut self,
225            len: usize,
226            for_each_slice: F,
227        ) -> Result<(), DidntRead>;
228
229        /// Reads exactly `len` bytes, returning them as a single `ZSlice`.
230        fn read_zslice(&mut self, len: usize) -> Result<ZSlice, DidntRead>;
231
232        fn read_u8(&mut self) -> Result<u8, DidntRead> {
233            let mut byte = 0;
234            let read = self.read(core::slice::from_mut(&mut byte))?;
235            if read.get() == 1 {
236                Ok(byte)
237            } else {
238                Err(DidntRead)
239            }
240        }
241
242        fn can_read(&self) -> bool {
243            self.remaining() != 0
244        }
245    }
246
247    impl<R: Reader + ?Sized> Reader for &mut R {
248        fn read(&mut self, into: &mut [u8]) -> Result<NonZeroUsize, DidntRead> {
249            (**self).read(into)
250        }
251        fn read_exact(&mut self, into: &mut [u8]) -> Result<(), DidntRead> {
252            (**self).read_exact(into)
253        }
254        fn remaining(&self) -> usize {
255            (**self).remaining()
256        }
257        fn read_zslices<F: FnMut(ZSlice)>(
258            &mut self,
259            len: usize,
260            for_each_slice: F,
261        ) -> Result<(), DidntRead> {
262            (**self).read_zslices(len, for_each_slice)
263        }
264        fn read_zslice(&mut self, len: usize) -> Result<ZSlice, DidntRead> {
265            (**self).read_zslice(len)
266        }
267        fn read_u8(&mut self) -> Result<u8, DidntRead> {
268            (**self).read_u8()
269        }
270        fn can_read(&self) -> bool {
271            (**self).can_read()
272        }
273    }
274
275    pub trait BacktrackableReader: Reader {
276        type Mark;
277
278        fn mark(&mut self) -> Self::Mark;
279        fn rewind(&mut self, mark: Self::Mark) -> bool;
280    }
281
282    impl<R: BacktrackableReader + ?Sized> BacktrackableReader for &mut R {
283        type Mark = R::Mark;
284        fn mark(&mut self) -> Self::Mark {
285            (**self).mark()
286        }
287        fn rewind(&mut self, mark: Self::Mark) -> bool {
288            (**self).rewind(mark)
289        }
290    }
291
292    pub trait AdvanceableReader: Reader {
293        fn skip(&mut self, offset: usize) -> Result<(), DidntRead>;
294        fn backtrack(&mut self, offset: usize) -> Result<(), DidntRead>;
295        fn advance(&mut self, offset: isize) -> Result<(), DidntRead> {
296            if offset > 0 {
297                self.skip(offset as usize)
298            } else {
299                self.backtrack((-offset) as usize)
300            }
301        }
302    }
303
304    #[derive(Debug, Clone, Copy)]
305    pub struct DidntSiphon;
306
307    pub trait SiphonableReader: Reader {
308        fn siphon<W>(&mut self, writer: &mut W) -> Result<NonZeroUsize, DidntSiphon>
309        where
310            W: crate::writer::Writer;
311    }
312
313    pub trait HasReader {
314        type Reader: Reader;
315
316        /// Returns the most appropriate reader for `self`
317        fn reader(self) -> Self::Reader;
318    }
319}