Skip to main content

slice_codec/buffer/
vec.rs

1// Copyright (c) ZeroC, Inc.
2
3//! TODO maybe write a comment explaining this module?
4
5use super::*;
6use crate::{Error, ErrorKind, Result};
7use alloc::vec::Vec;
8use core::mem::MaybeUninit;
9use core::{debug_assert, debug_assert_eq};
10
11/// A wrapper around a [`Vec<u8>`] that implements [`OutputTarget`].
12///
13/// The implementation will automatically grow the Vec as needed.
14#[derive(Debug)]
15pub struct VecOutputTarget<'a> {
16    /// The underlying buffer that this type wraps.
17    buffer: &'a mut Vec<u8>,
18}
19
20impl<'a> VecOutputTarget<'a> {
21    /// Attempts to ensure there are at least `requested` unwritten bytes available in the buffer.
22    ///
23    /// If there is already `requested`-many bytes in the underlying Vec's spare capacity, this is no-op.
24    /// Otherwise, it will attempt to allocate (at least) `requested`-many bytes of additional capacity.
25    ///
26    /// If there was insufficient capacity, and the allocation failed, this will return an [`ErrorKind::UnexpectedEob`]
27    /// error. Otherwise it will return `Ok`.
28    ///
29    /// This function is only used internally to ensure there is enough capacity before attempting a write operation.
30    fn ensure_buffer_has_at_least(&mut self, requested: usize) -> Result<()> {
31        // Use `try_reserve` to ensure there is sufficient space in the buffer. It will re-allocate if necessary.
32        self.buffer.try_reserve(requested).map_err(|_err| {
33            // If an error occurred, we wrap it in our own `UnexpectedEob` error and return it.
34            let remaining = self.remaining();
35            let kind = ErrorKind::UnexpectedEob { requested, remaining };
36            Error::new_with_source(kind, _err)
37        })
38    }
39}
40
41impl OutputTarget for VecOutputTarget<'_> {
42    fn remaining(&self) -> usize {
43        self.buffer.capacity() - self.buffer.len()
44    }
45
46    fn write_byte(&mut self, byte: u8) -> Result<()> {
47        self.ensure_buffer_has_at_least(1)?;
48
49        // SAFETY: the above function call guarantees there's enough space in `self.buffer` to write a single byte.
50        unsafe {
51            debug_assert!(self.buffer.spare_capacity_mut().get_mut(0).is_some());
52            let target = self.buffer.spare_capacity_mut().get_unchecked_mut(0);
53            target.write(byte);
54
55            let old_length = self.buffer.len();
56            self.buffer.set_len(old_length + 1);
57            Ok(())
58        }
59    }
60
61    fn write_bytes_exact(&mut self, bytes: &[u8]) -> Result<()> {
62        let count = bytes.len();
63        self.ensure_buffer_has_at_least(count)?;
64
65        // SAFETY: the above function call guarantees there's enough spare capacity in `self.buffer` to write `bytes`,
66        // and we know the slice cannot overlap because the mutable borrow of `self` guarantees exclusive access.
67        unsafe {
68            debug_assert!(self.buffer.spare_capacity_mut().get_mut(..count).is_some());
69            let target_slice = self.buffer.spare_capacity_mut().get_unchecked_mut(..count);
70
71            debug_assert_eq!(target_slice.len(), count);
72            // SAFETY: `MaybeUninit<T>` is guaranteed to have the same memory layout as `T`.
73            let source: &[MaybeUninit<u8>] = core::mem::transmute(bytes);
74
75            core::ptr::copy_nonoverlapping(source.as_ptr(), target_slice.as_mut_ptr(), count);
76
77            let old_length = self.buffer.len();
78            self.buffer.set_len(old_length + count);
79            Ok(())
80        }
81    }
82
83    fn write_bytes_into_reserved_exact(&mut self, reservation: &mut Reservation, bytes: &[u8]) -> Result<()> {
84        // Get a mutable slice of the buffer - one that corresponds to the reserved range.
85        let Some(reserved_slice) = self.buffer.get_mut(reservation.range()) else {
86            let error = ErrorKind::InvalidReservation {
87                buffer_len: self.buffer.len(),
88                reserved_range: reservation.range(),
89            };
90            return Err(error.into());
91        };
92
93        // Ensure there's enough space remaining in the reservation.
94        if reserved_slice.len() < bytes.len() {
95            let error = ErrorKind::UnexpectedEob {
96                requested: bytes.len(),
97                remaining: reserved_slice.len(),
98            };
99            return Err(error.into());
100        }
101
102        // SAFETY: we just checked that there's enough space in `reserved_slice` to write `bytes`,
103        // and we know the slices cannot overlap because the mutable borrow of `self` guarantees exclusive access.
104        unsafe {
105            core::ptr::copy_nonoverlapping(bytes.as_ptr(), reserved_slice.as_mut_ptr(), bytes.len());
106            reservation.0.start += bytes.len();
107            Ok(())
108        }
109    }
110
111    fn reserve_space(&mut self, count: usize) -> Result<Reservation> {
112        self.ensure_buffer_has_at_least(count)?;
113
114        // SAFETY: the above function call guarantees there's enough spare capacity in `self.buffer` for `count` bytes,
115        // and `0x00` is a valid memory representation for a `u8`.
116        unsafe {
117            let pos = self.buffer.len();
118            let end = pos + count;
119            debug_assert!(self.buffer.spare_capacity_mut().get(..count).is_some());
120            let target_offset = self.buffer.as_mut_ptr().add(pos);
121
122            // Defensively zero the reserved memory, since `Vec` doesn't guarantee that memory between `length` and
123            // `capacity` is initialized. Then advance past the reserved memory with `set_len`.
124            core::ptr::write_bytes(target_offset, 0, count);
125            self.buffer.set_len(end);
126
127            Ok(Reservation(pos..end))
128        }
129    }
130}
131
132impl<'a> From<&'a mut Vec<u8>> for VecOutputTarget<'a> {
133    /// Creates a new [`VecOutputTarget`] that wraps the provided vector.
134    fn from(value: &'a mut Vec<u8>) -> Self {
135        Self { buffer: value }
136    }
137}
138
139// Allows users to create an [`Encoder`] directly from a vector,
140// without needing to construct an intermediate [`VecOutputTarget`].
141impl<'a, T> From<T> for crate::encoder::Encoder<VecOutputTarget<'a>>
142where
143    T: Into<VecOutputTarget<'a>>,
144{
145    fn from(value: T) -> Self {
146        crate::encoder::Encoder::new(value.into())
147    }
148}
149
150#[cfg(test)]
151#[cfg(feature = "alloc")]
152mod tests {
153    use super::*;
154    use alloc::vec;
155
156    /// Verifies that [`ensure_buffer_has_at_least`] returns the correct number of remaining bytes in the buffer
157    /// when the remaining bytes number are greater than or equal to the number of requested bytes.
158    #[test]
159    fn ensure_buffer_has_at_least_returns_ok() {
160        // Arrange
161        let mut buffer = vec![115, 108, 105, 99, 101];
162        let mut target = VecOutputTarget::from(&mut buffer);
163
164        // Act
165        let result = target.ensure_buffer_has_at_least(5);
166
167        // Assert
168        assert!(result.is_ok());
169    }
170
171    /// Verifies that [`ensure_buffer_has_at_least`] returns an error when the remaining bytes number are less
172    /// than the number of requested bytes.
173    #[test]
174    #[ignore = "TODO: See https://github.com/icerpc/slice-rust/issues/3"]
175    fn ensure_buffer_has_at_least_returns_error() {}
176
177    /// Verifies that [`write_byte`] writes the correct byte to the buffer.
178    #[test]
179    fn write_byte_writes_correct_byte() {
180        // Arrange
181        let mut buffer = Vec::new();
182        let mut target = VecOutputTarget::from(&mut buffer);
183
184        // Act
185        let result = target.write_byte(115);
186
187        // Assert
188        assert!(result.is_ok());
189        assert_eq!(target.buffer, &[115]);
190        assert_eq!(target.remaining(), buffer.capacity() - 1);
191    }
192
193    /// Verifies that [`write_bytes_exact`] writes the correct bytes to the buffer.
194    #[test]
195    fn write_bytes_exact_writes_correct_bytes() {
196        // Arrange
197        let mut buffer = Vec::new();
198        let mut target = VecOutputTarget::from(&mut buffer);
199
200        // Act
201        let result = target.write_bytes_exact(&[115, 108, 105, 99, 101]);
202
203        // Assert
204        assert!(result.is_ok());
205        assert_eq!(target.buffer, &[115, 108, 105, 99, 101]);
206        assert_eq!(target.buffer.len(), 5);
207        assert_eq!(target.remaining(), target.buffer.capacity() - 5);
208    }
209
210    /// Verifies that [`reserve_space`] reserves the correct number of bytes in the buffer and advances the
211    /// position past the reserved space so that the next write operation will not write into the reserved
212    /// space.
213    #[test]
214    fn reserve_space_reserves_correct_space() {
215        // Arrange
216        let mut buffer = Vec::new();
217        let mut target = VecOutputTarget::from(&mut buffer);
218
219        // Act
220        let reserve_result = target.reserve_space(3);
221        let write_result = target.write_byte(99);
222
223        // Assert
224        assert!(reserve_result.is_ok());
225        assert!(write_result.is_ok());
226
227        assert_eq!(reserve_result.unwrap().range(), 0..3);
228        assert_eq!(target.buffer.len(), 4);
229        assert_eq!(target.remaining(), target.buffer.capacity() - 4);
230        assert_eq!(buffer, [0, 0, 0, 99]);
231    }
232
233    /// Verifies that [`write_bytes_into_reserved_exact`] writes the correct bytes to the reserved space in the
234    /// buffer and does not advance the position past the reserved space.
235    #[test]
236    fn write_bytes_into_reserved_exact_writes_correct_bytes() {
237        // Arrange
238        let mut buffer = Vec::new();
239        let mut target = VecOutputTarget::from(&mut buffer);
240
241        // Should advance the position to 3.
242        let mut reservation = target.reserve_space(3).unwrap();
243
244        // Write a byte to ensure the position is advanced.
245        let _ = target.write_bytes_exact(&[99]);
246
247        // Act
248        let result = target.write_bytes_into_reserved_exact(&mut reservation, &[115, 108, 105]);
249
250        // Write a byte to ensure the position was not advanced.
251        let _ = target.write_byte(101);
252
253        // Assert
254        assert!(result.is_ok());
255        assert_eq!(target.buffer, &[115, 108, 105, 99, 101]);
256        assert_eq!(target.buffer.len(), 5);
257        assert_eq!(target.remaining(), target.buffer.capacity() - 5);
258    }
259}