Skip to main content

rmp/decode/
bytes.rs

1//! Implementation of the [Bytes] type
2
3use super::RmpRead;
4use crate::decode::RmpReadErr;
5use core::fmt::{Display, Formatter};
6
7/// Indicates that an error occurred reading from [Bytes]
8#[derive(Debug)]
9#[non_exhaustive]
10// NOTE: We can't use thiserror because of no_std :(
11pub enum BytesReadError {
12    /// Indicates that there were not enough bytes.
13    InsufficientBytes {
14        expected: usize,
15        actual: usize,
16        position: u64,
17    },
18}
19
20impl Display for BytesReadError {
21    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
22        match *self {
23            Self::InsufficientBytes { expected, actual, position } => {
24                write!(f, "Expected at least bytes {expected}, but only got {actual} (pos {position})")
25            },
26        }
27    }
28}
29#[cfg(feature = "std")]
30impl std::error::Error for BytesReadError {}
31impl RmpReadErr for BytesReadError {}
32
33/// A wrapper around `&[u8]` to read more efficiently.
34///
35/// This has a specialized implementation of `RmpWrite`
36/// and has error type [Infallible](core::convert::Infallible).
37///
38/// This has the additional benefit of working on `#[no_std]` (unlike the builtin Read trait)
39///
40/// See also [serde_bytes::Bytes](https://docs.rs/serde_bytes/0.11/serde_bytes/struct.Bytes.html)
41///
42/// Unlike a plain `&[u8]` this also tracks an internal offset in the input (See [`Self::position`]).
43///
44/// This is used for (limited) compatibility with [`std::io::Cursor`]. Unlike a [Cursor](std::io::Cursor) it does
45/// not support mark/reset.
46#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Hash, Ord, PartialOrd)]
47pub struct Bytes<'a> {
48    /// The internal position of the input buffer.
49    ///
50    /// This is not required for correctness.
51    /// It is only used for error reporting (and to implement [`Self::position`])
52    current_position: u64,
53    bytes: &'a [u8],
54}
55impl<'a> Bytes<'a> {
56    /// Wrap an existing bytes slice.
57    ///
58    /// This sets the internal position to zero.
59    #[inline]
60    #[must_use]
61    pub const fn new(bytes: &'a [u8]) -> Self {
62        Bytes { bytes, current_position: 0 }
63    }
64
65    /// Get a reference to the remaining bytes in the buffer.
66    #[inline]
67    #[must_use]
68    pub const fn remaining_slice(&self) -> &'a [u8] {
69        self.bytes
70    }
71
72    /// Return the position of the input buffer.
73    ///
74    /// This is not required for correctness, it only exists to help mimic
75    /// [`Cursor::position`](std::io::Cursor::position)
76    #[inline]
77    #[must_use]
78    pub const fn position(&self) -> u64 {
79        self.current_position
80    }
81}
82impl<'a> From<&'a [u8]> for Bytes<'a> {
83    #[inline]
84    fn from(bytes: &'a [u8]) -> Self {
85        Bytes { bytes, current_position: 0 }
86    }
87}
88
89impl RmpRead for Bytes<'_> {
90    type Error = BytesReadError;
91
92    #[inline]
93    fn read_u8(&mut self) -> Result<u8, Self::Error> {
94        if let Some((&first, newly_remaining)) = self.bytes.split_first() {
95            self.bytes = newly_remaining;
96            self.current_position += 1;
97            Ok(first)
98        } else {
99            Err(BytesReadError::InsufficientBytes {
100                expected: 1,
101                actual: 0,
102                position: self.current_position,
103            })
104        }
105    }
106
107    #[inline]
108    fn read_exact_buf(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
109        let to_read = buf.len();
110        if to_read <= self.bytes.len() {
111            let (src, newly_remaining) = self.bytes.split_at(to_read);
112            self.bytes = newly_remaining;
113            self.current_position += to_read as u64;
114            buf.copy_from_slice(src);
115            Ok(())
116        } else {
117            Err(BytesReadError::InsufficientBytes {
118                expected: to_read,
119                actual: self.bytes.len(),
120                position: self.current_position,
121            })
122        }
123    }
124}
125
126#[cfg(not(feature = "std"))]
127impl<'a> RmpRead for &'a [u8] {
128    type Error = BytesReadError;
129
130    fn read_u8(&mut self) -> Result<u8, Self::Error> {
131        if let Some((&first, newly_remaining)) = self.split_first() {
132            *self = newly_remaining;
133            Ok(first)
134        } else {
135            Err(BytesReadError::InsufficientBytes {
136                expected: 1,
137                actual: 0,
138                position: 0,
139            })
140        }
141    }
142
143    fn read_exact_buf(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
144        let to_read = buf.len();
145        if to_read <= self.len() {
146            let (src, newly_remaining) = self.split_at(to_read);
147            *self = newly_remaining;
148            buf.copy_from_slice(src);
149            Ok(())
150        } else {
151            Err(BytesReadError::InsufficientBytes {
152                expected: to_read,
153                actual: self.len(),
154                position: 0,
155            })
156        }
157    }
158}