Skip to main content

zenoh_buffers/
zslice.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//
14use alloc::{boxed::Box, sync::Arc, vec::Vec};
15use core::{
16    any::Any,
17    fmt, iter,
18    num::NonZeroUsize,
19    ops::{Bound, Deref, RangeBounds},
20};
21
22use crate::{
23    buffer::{Buffer, SplitBuffer},
24    reader::{BacktrackableReader, DidntRead, HasReader, Reader},
25    writer::{BacktrackableWriter, DidntWrite, Writer},
26    ZBuf,
27};
28
29/*************************************/
30/*           ZSLICE BUFFER           */
31/*************************************/
32pub trait ZSliceBuffer: Any + Send + Sync + fmt::Debug {
33    fn as_slice(&self) -> &[u8];
34    fn as_any(&self) -> &dyn Any;
35    fn as_any_mut(&mut self) -> &mut dyn Any;
36}
37
38impl ZSliceBuffer for Vec<u8> {
39    fn as_slice(&self) -> &[u8] {
40        self
41    }
42
43    fn as_any(&self) -> &dyn Any {
44        self
45    }
46
47    fn as_any_mut(&mut self) -> &mut dyn Any {
48        self
49    }
50}
51
52impl ZSliceBuffer for Box<[u8]> {
53    fn as_slice(&self) -> &[u8] {
54        self
55    }
56
57    fn as_any(&self) -> &dyn Any {
58        self
59    }
60
61    fn as_any_mut(&mut self) -> &mut dyn Any {
62        self
63    }
64}
65
66impl<const N: usize> ZSliceBuffer for [u8; N] {
67    fn as_slice(&self) -> &[u8] {
68        self
69    }
70
71    fn as_any(&self) -> &dyn Any {
72        self
73    }
74
75    fn as_any_mut(&mut self) -> &mut dyn Any {
76        self
77    }
78}
79
80/*************************************/
81/*               ZSLICE              */
82/*************************************/
83#[cfg(feature = "shared-memory")]
84#[derive(Copy, Clone, PartialEq, Eq)]
85#[repr(u8)]
86pub enum ZSliceKind {
87    Raw = 0,
88    ShmPtr = 1,
89}
90
91/// A cloneable wrapper to a contiguous slice of bytes.
92#[derive(Clone)]
93pub struct ZSlice {
94    buf: Arc<dyn ZSliceBuffer>,
95    start: usize,
96    end: usize,
97    #[cfg(feature = "shared-memory")]
98    pub kind: ZSliceKind,
99}
100
101impl ZSlice {
102    #[inline]
103    pub fn new(
104        buf: Arc<dyn ZSliceBuffer>,
105        start: usize,
106        end: usize,
107    ) -> Result<ZSlice, Arc<dyn ZSliceBuffer>> {
108        if start <= end && end <= buf.as_slice().len() {
109            Ok(Self {
110                buf,
111                start,
112                end,
113                #[cfg(feature = "shared-memory")]
114                kind: ZSliceKind::Raw,
115            })
116        } else {
117            Err(buf)
118        }
119    }
120
121    #[inline]
122    pub fn empty() -> Self {
123        Self::new(Arc::new(Vec::<u8>::new()), 0, 0).unwrap()
124    }
125
126    #[inline]
127    #[must_use]
128    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
129        self.buf.as_any().downcast_ref()
130    }
131
132    /// # Safety
133    ///
134    /// Buffer modification must not modify slice range.
135    #[inline]
136    #[must_use]
137    pub unsafe fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
138        Arc::get_mut(&mut self.buf)?.as_any_mut().downcast_mut()
139    }
140
141    // This method is internal and is only meant to be used in `ZBufWriter`.
142    // It's implemented in this module because it plays with `ZSlice` invariant,
143    // so it should stay in the same module.
144    // See https://github.com/eclipse-zenoh/zenoh/pull/1289#discussion_r1701796640
145    #[inline]
146    pub(crate) fn writer(&mut self) -> Option<ZSliceWriter<'_>> {
147        let vec = Arc::get_mut(&mut self.buf)?
148            .as_any_mut()
149            .downcast_mut::<Vec<u8>>()?;
150        if self.end == vec.len() {
151            Some(ZSliceWriter {
152                vec,
153                end: &mut self.end,
154            })
155        } else {
156            None
157        }
158    }
159
160    #[inline]
161    #[must_use]
162    pub const fn len(&self) -> usize {
163        self.end - self.start
164    }
165
166    #[inline]
167    #[must_use]
168    pub const fn is_empty(&self) -> bool {
169        self.len() == 0
170    }
171
172    #[inline]
173    #[must_use]
174    pub fn as_slice(&self) -> &[u8] {
175        // SAFETY: bounds checks are performed at `ZSlice` construction via `make()` or `subslice()`.
176        unsafe { self.buf.as_slice().get_unchecked(self.start..self.end) }
177    }
178
179    pub fn subslice(&self, range: impl RangeBounds<usize>) -> Option<Self> {
180        let start = match range.start_bound() {
181            Bound::Included(&n) => n,
182            Bound::Excluded(&n) => n + 1,
183            Bound::Unbounded => 0,
184        };
185        let end = match range.end_bound() {
186            Bound::Included(&n) => n + 1,
187            Bound::Excluded(&n) => n,
188            Bound::Unbounded => self.len(),
189        };
190        if start <= end && end <= self.len() {
191            Some(ZSlice {
192                buf: self.buf.clone(),
193                start: self.start + start,
194                end: self.start + end,
195                #[cfg(feature = "shared-memory")]
196                kind: self.kind,
197            })
198        } else {
199            None
200        }
201    }
202}
203
204impl Deref for ZSlice {
205    type Target = [u8];
206
207    fn deref(&self) -> &Self::Target {
208        self.as_slice()
209    }
210}
211
212impl AsRef<[u8]> for ZSlice {
213    fn as_ref(&self) -> &[u8] {
214        self
215    }
216}
217
218impl<Rhs: AsRef<[u8]> + ?Sized> PartialEq<Rhs> for ZSlice {
219    fn eq(&self, other: &Rhs) -> bool {
220        self.as_slice() == other.as_ref()
221    }
222}
223
224impl Eq for ZSlice {}
225
226#[cfg(feature = "std")]
227impl std::hash::Hash for ZSlice {
228    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
229        self.as_slice().hash(state);
230    }
231}
232
233impl fmt::Display for ZSlice {
234    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
235        write!(f, "{:02x?}", self.as_slice())
236    }
237}
238
239impl fmt::Debug for ZSlice {
240    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
241        write!(f, "{:02x?}", self.as_slice())
242    }
243}
244
245// From impls
246impl<T> From<Arc<T>> for ZSlice
247where
248    T: ZSliceBuffer + 'static,
249{
250    fn from(buf: Arc<T>) -> Self {
251        let end = buf.as_slice().len();
252        Self {
253            buf,
254            start: 0,
255            end,
256            #[cfg(feature = "shared-memory")]
257            kind: ZSliceKind::Raw,
258        }
259    }
260}
261
262impl<T> From<T> for ZSlice
263where
264    T: ZSliceBuffer + 'static,
265{
266    fn from(buf: T) -> Self {
267        Self::from(Arc::new(buf))
268    }
269}
270
271// Buffer
272impl Buffer for ZSlice {
273    fn len(&self) -> usize {
274        ZSlice::len(self)
275    }
276}
277
278impl Buffer for &ZSlice {
279    fn len(&self) -> usize {
280        ZSlice::len(self)
281    }
282}
283
284impl Buffer for &mut ZSlice {
285    fn len(&self) -> usize {
286        ZSlice::len(self)
287    }
288}
289
290// SplitBuffer
291impl SplitBuffer for ZSlice {
292    type Slices<'a> = iter::Once<&'a [u8]>;
293
294    fn slices(&self) -> Self::Slices<'_> {
295        iter::once(self.as_slice())
296    }
297}
298
299#[derive(Debug)]
300pub(crate) struct ZSliceWriter<'a> {
301    vec: &'a mut Vec<u8>,
302    end: &'a mut usize,
303}
304
305impl Writer for ZSliceWriter<'_> {
306    fn write(&mut self, bytes: &[u8]) -> Result<NonZeroUsize, DidntWrite> {
307        let len = self.vec.write(bytes)?;
308        *self.end += len.get();
309        Ok(len)
310    }
311
312    fn write_exact(&mut self, bytes: &[u8]) -> Result<(), DidntWrite> {
313        self.write(bytes).map(|_| ())
314    }
315
316    fn remaining(&self) -> usize {
317        self.vec.remaining()
318    }
319
320    unsafe fn with_slot<F>(&mut self, len: usize, write: F) -> Result<NonZeroUsize, DidntWrite>
321    where
322        F: FnOnce(&mut [u8]) -> usize,
323    {
324        // SAFETY: same precondition as the enclosing function
325        let len = unsafe { self.vec.with_slot(len, write) }?;
326        *self.end += len.get();
327        Ok(len)
328    }
329}
330
331impl BacktrackableWriter for ZSliceWriter<'_> {
332    type Mark = usize;
333
334    fn mark(&mut self) -> Self::Mark {
335        *self.end
336    }
337
338    fn rewind(&mut self, mark: Self::Mark) -> bool {
339        assert!(mark <= self.vec.len());
340        self.vec.truncate(mark);
341        *self.end = mark;
342        true
343    }
344}
345
346// Reader
347impl HasReader for &mut ZSlice {
348    type Reader = Self;
349
350    fn reader(self) -> Self::Reader {
351        self
352    }
353}
354
355impl Reader for ZSlice {
356    #[inline(always)]
357    fn read(&mut self, into: &mut [u8]) -> Result<NonZeroUsize, DidntRead> {
358        let mut reader = self.as_slice().reader();
359        let len = reader.read(into)?;
360        // we trust `Reader` impl for `&[u8]` to not overflow the size of the slice
361        self.start += len.get();
362        Ok(len)
363    }
364
365    #[inline(always)]
366    fn read_exact(&mut self, into: &mut [u8]) -> Result<(), DidntRead> {
367        let mut reader = self.as_slice().reader();
368        reader.read_exact(into)?;
369        // we trust `Reader` impl for `&[u8]` to not overflow the size of the slice
370        self.start += into.len();
371        Ok(())
372    }
373
374    #[inline(always)]
375    fn remaining(&self) -> usize {
376        self.len()
377    }
378
379    #[inline(always)]
380    fn read_zbuf(&mut self, len: usize) -> Result<ZBuf, DidntRead> {
381        Ok(self.read_zslice(len)?.into())
382    }
383
384    fn read_zslices<F: FnMut(ZSlice)>(&mut self, len: usize, mut f: F) -> Result<(), DidntRead> {
385        let zslice = self.read_zslice(len)?;
386        f(zslice);
387        Ok(())
388    }
389
390    #[inline(always)]
391    fn read_zslice(&mut self, len: usize) -> Result<ZSlice, DidntRead> {
392        let res = self.subslice(..len).ok_or(DidntRead)?;
393        self.start += len;
394        Ok(res)
395    }
396
397    #[inline(always)]
398    fn read_u8(&mut self) -> Result<u8, DidntRead> {
399        let mut reader = self.as_slice().reader();
400        let res = reader.read_u8()?;
401        // we trust `Reader` impl for `&[u8]` to not overflow the size of the slice
402        self.start += 1;
403        Ok(res)
404    }
405
406    #[inline(always)]
407    fn can_read(&self) -> bool {
408        !self.is_empty()
409    }
410}
411
412impl BacktrackableReader for ZSlice {
413    type Mark = usize;
414
415    fn mark(&mut self) -> Self::Mark {
416        self.start
417    }
418
419    fn rewind(&mut self, mark: Self::Mark) -> bool {
420        assert!(mark <= self.end);
421        self.start = mark;
422        true
423    }
424}
425
426#[cfg(feature = "std")]
427impl std::io::Read for &mut ZSlice {
428    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
429        match <Self as Reader>::read(self, buf) {
430            Ok(n) => Ok(n.get()),
431            Err(_) => Err(std::io::Error::new(
432                std::io::ErrorKind::UnexpectedEof,
433                "UnexpectedEof",
434            )),
435        }
436    }
437}
438
439#[cfg(feature = "test")]
440impl ZSlice {
441    #[doc(hidden)]
442    pub fn rand(len: usize) -> Self {
443        use rand::Rng;
444
445        let mut rng = rand::thread_rng();
446        (0..len).map(|_| rng.gen()).collect::<Vec<u8>>().into()
447    }
448}
449
450#[cfg(test)]
451mod tests {
452    use super::*;
453
454    #[test]
455    fn zslice() {
456        let buf = crate::vec::uninit(16);
457        let mut zslice: ZSlice = buf.clone().into();
458        assert_eq!(buf.as_slice(), zslice.as_slice());
459
460        // SAFETY: buffer slize size is not modified
461        let mut_slice = unsafe { zslice.downcast_mut::<Vec<u8>>() }.unwrap();
462
463        mut_slice[..buf.len()].clone_from_slice(&buf[..]);
464
465        assert_eq!(buf.as_slice(), zslice.as_slice());
466    }
467
468    #[test]
469    fn hash() {
470        use std::{
471            collections::hash_map::DefaultHasher,
472            hash::{Hash, Hasher},
473        };
474
475        let buf = vec![1, 2, 3, 4, 5];
476        let mut buf_hasher = DefaultHasher::new();
477        buf.hash(&mut buf_hasher);
478        let buf_hash = buf_hasher.finish();
479
480        let zslice: ZSlice = buf.clone().into();
481        let mut zslice_hasher = DefaultHasher::new();
482        zslice.hash(&mut zslice_hasher);
483        let zslice_hash = zslice_hasher.finish();
484
485        assert_eq!(buf_hash, zslice_hash);
486    }
487}