1use {super::*, alloc::vec::Vec};
2
3struct VecUnchecked<'a> {
4 inner: &'a mut Vec<u8>,
5}
6
7impl<'a> VecUnchecked<'a> {
8 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 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
47impl 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 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}