Skip to main content

wincode/io/
vec.rs

1use {super::*, alloc::vec::Vec};
2
3struct VecUnchecked<'a> {
4    inner: &'a mut Vec<u8>,
5}
6
7impl<'a> VecUnchecked<'a> {
8    /// # Safety
9    ///
10    /// Caller must ensure that `inner` has enough spare capacity for all writes
11    /// performed through this unchecked writer, and that those writes stay within
12    /// the trusted window reserved by `as_trusted_for`.
13    const unsafe fn new(inner: &'a mut Vec<u8>) -> Self {
14        Self { inner }
15    }
16}
17
18impl<'a> Writer for VecUnchecked<'a> {
19    #[inline]
20    fn write(&mut self, src: &[u8]) -> WriteResult<()> {
21        let cur_len = self.inner.len();
22
23        // SAFETY:
24        // - The outer `as_trusted_for` call ensured sufficient capacity for the trusted
25        //   window before constructing this writer.
26        // - The trusted-writer contract requires all writes through this writer,
27        //   including forwarded nested trusted writes, to stay within that window.
28        // - Given Rust's aliasing rules, we can assume that `src` does not overlap with
29        //   the internal buffer.
30        unsafe {
31            core::ptr::copy_nonoverlapping(
32                src.as_ptr(),
33                self.inner.as_mut_ptr().add(cur_len),
34                src.len(),
35            );
36        }
37
38        unsafe {
39            #[expect(clippy::arithmetic_side_effects)]
40            self.inner.set_len(cur_len + src.len())
41        }
42
43        Ok(())
44    }
45}
46
47/// Writer implementation for `Vec<u8>` that appends to the vector. The vector will grow as needed.
48///
49/// # Examples
50///
51/// Writing to a new vector.
52/// ```
53/// # #[cfg(feature = "alloc")] {
54/// # use wincode::io::Writer;
55/// let mut vec = Vec::new();
56/// let bytes = [1, 2, 3];
57/// vec.write(&bytes).unwrap();
58/// assert_eq!(vec, &[1, 2, 3]);
59/// # }
60/// ```
61///
62/// Writing to an existing vector.
63/// ```
64/// # #[cfg(feature = "alloc")] {
65/// # use wincode::io::Writer;
66/// let mut vec = vec![1, 2, 3];
67/// let bytes = [4, 5, 6];
68/// vec.write(&bytes).unwrap();
69/// assert_eq!(vec, &[1, 2, 3, 4, 5, 6]);
70/// # }
71/// ```
72///
73impl Writer for Vec<u8> {
74    #[inline]
75    fn write(&mut self, src: &[u8]) -> WriteResult<()> {
76        self.extend_from_slice(src);
77        Ok(())
78    }
79
80    #[inline]
81    unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> WriteResult<impl Writer> {
82        self.reserve(n_bytes);
83        // SAFETY: by calling `as_trusted_for`, caller guarantees they
84        // will fully initialize `n_bytes` of memory and will not write
85        // beyond the bounds of returned `Writer`.
86        Ok(unsafe { VecUnchecked::new(self) })
87    }
88}
89
90#[cfg(all(test, feature = "alloc"))]
91mod tests {
92    #![allow(clippy::arithmetic_side_effects)]
93    use {super::*, crate::proptest_config::proptest_cfg, alloc::vec, proptest::prelude::*};
94
95    proptest! {
96        #![proptest_config(proptest_cfg())]
97
98        #[test]
99        fn vec_writer_write_new(bytes in proptest::collection::vec(any::<u8>(), 0..=100)) {
100            let mut vec = Vec::new();
101            vec.write(&bytes).unwrap();
102            prop_assert_eq!(vec, bytes);
103        }
104
105        #[test]
106        fn vec_writer_write_existing(bytes in proptest::collection::vec(any::<u8>(), 0..=100)) {
107            let mut vec = vec![0; 5];
108            vec.write(&bytes).unwrap();
109            prop_assert_eq!(&vec[..5], &[0; 5]);
110            prop_assert_eq!(&vec[5..], bytes);
111        }
112
113        #[test]
114        fn vec_writer_trusted(bytes in proptest::collection::vec(any::<u8>(), 0..=100)) {
115            let mut vec = Vec::new();
116            let half = bytes.len() / 2;
117            let quarter = half / 2;
118            vec.write(&bytes[..half]).unwrap();
119
120            {
121                let mut t1 = unsafe { vec.as_trusted_for(bytes.len() - half) }.unwrap();
122                t1
123                    .write(&bytes[half..half + quarter])
124                    .unwrap();
125
126                let mut t2 = unsafe { t1.as_trusted_for(quarter) }.unwrap();
127                t2.write(&bytes[half + quarter..]).unwrap();
128            }
129
130            prop_assert_eq!(vec, bytes);
131        }
132
133        #[test]
134        fn vec_writer_trusted_existing(bytes in proptest::collection::vec(any::<u8>(), 0..=100)) {
135            let mut vec = vec![0; 5];
136            let half = bytes.len() / 2;
137            let quarter = half / 2;
138            vec.write(&bytes[..half]).unwrap();
139
140            {
141                let mut t1 = unsafe { vec.as_trusted_for(bytes.len() - half) }.unwrap();
142                t1
143                    .write(&bytes[half..half + quarter])
144                    .unwrap();
145
146                let mut t2 = unsafe { t1.as_trusted_for(quarter) }.unwrap();
147                t2.write(&bytes[half + quarter..]).unwrap();
148            }
149
150            prop_assert_eq!(&vec[..5], &[0; 5]);
151            prop_assert_eq!(&vec[5..], bytes);
152        }
153
154        #[test]
155        fn test_writer_write_from_t(int in any::<u64>()) {
156            let mut writer = Vec::new();
157            unsafe { writer.write_t(&int).unwrap() };
158            prop_assert_eq!(writer, int.to_le_bytes());
159        }
160
161        #[test]
162        fn test_writer_write_slice_t(ints in proptest::collection::vec(any::<u64>(), 0..=100)) {
163            let bytes = ints.iter().flat_map(|int| int.to_le_bytes()).collect::<Vec<u8>>();
164            let mut writer = Vec::new();
165            unsafe { writer.write_slice_t(&ints).unwrap() };
166            prop_assert_eq!(writer, bytes);
167        }
168    }
169
170    #[test]
171    fn vec_trusted_writer_does_not_extend_len_before_write() {
172        let mut vec = Vec::with_capacity(8);
173        {
174            let _trusted = unsafe { vec.as_trusted_for(8) }.unwrap();
175        }
176
177        assert_eq!(vec.len(), 0);
178    }
179
180    #[test]
181    fn vec_trusted_writer_extends_len_only_for_written_bytes() {
182        let mut vec = Vec::with_capacity(8);
183        {
184            let mut trusted = unsafe { vec.as_trusted_for(8) }.unwrap();
185            trusted.write(&[1, 2, 3]).unwrap();
186        }
187
188        assert_eq!(vec, [1, 2, 3]);
189    }
190}