1use std::mem::MaybeUninit;
5use std::num::NonZero;
6use std::ptr::NonNull;
7use std::sync::atomic::{self, AtomicUsize};
8
9use smallvec::SmallVec;
10
11use crate::mem::{Block, BlockRef, BlockRefDynamic, BlockRefVTable, BlockSize};
12use crate::{BytesView, MAX_INLINE_SPANS, Span};
13
14impl From<Vec<u8>> for BytesView {
15 fn from(value: Vec<u8>) -> Self {
19 if value.is_empty() {
20 return Self::new();
21 }
22
23 let vec_blocks = VecBlockIterator::new(value);
28
29 let blocks = vec_blocks.map(|vec| {
30 unsafe { non_empty_vec_to_immutable_block(vec) }
37 });
38
39 let spans = blocks.map(|block| {
40 let mut span_builder = block.into_span_builder();
41
42 #[expect(clippy::cast_possible_truncation, reason = "a span can never be larger than BlockSize")]
43 let len = NonZero::new(span_builder.remaining_capacity() as BlockSize).expect("splitting Vec cannot yield zero-sized chunks");
44
45 unsafe {
48 span_builder.advance(len.get() as usize);
49 }
50
51 span_builder.consume(len)
52 });
53
54 let mut spans_reversed: SmallVec<[Span; MAX_INLINE_SPANS]> = spans.collect();
58
59 spans_reversed.reverse();
61
62 Self::from_spans_reversed(spans_reversed)
63 }
64}
65
66struct VecBlock {
68 _inner: Vec<u8>,
70
71 ref_count: AtomicUsize,
72}
73
74impl VecBlock {
75 pub const fn new(inner: Vec<u8>) -> Self {
76 Self {
77 _inner: inner,
78 ref_count: AtomicUsize::new(1),
79 }
80 }
81}
82
83unsafe impl BlockRefDynamic for VecBlock {
85 type State = Self;
86
87 fn clone(state_ptr: NonNull<Self::State>) -> NonNull<Self::State> {
88 let state = unsafe { state_ptr.as_ref() };
92
93 state.ref_count.fetch_add(1, atomic::Ordering::Relaxed);
95
96 state_ptr
98 }
99
100 #[cfg_attr(test, mutants::skip)] fn drop(state_ptr: NonNull<Self::State>) {
102 let state = unsafe { state_ptr.as_ref() };
106
107 if state.ref_count.fetch_sub(1, atomic::Ordering::Release) != 1 {
109 return;
110 }
111
112 atomic::fence(atomic::Ordering::Acquire);
119
120 drop(unsafe { Box::from_raw(state_ptr.as_ptr()) });
122 }
123}
124
125unsafe fn non_empty_vec_to_immutable_block(vec: Vec<u8>) -> Block {
134 assert!(!vec.is_empty());
135
136 let len: BlockSize = vec
137 .len()
138 .try_into()
139 .expect("length of Vec<u8> instance was greater than BlockSize::MAX");
140
141 let capacity_ptr = NonNull::new(vec.as_ptr().cast_mut())
142 .expect("guarded by 'is zero sized Vec' check upstream - non-empty Vec must have non-null capacity pointer")
143 .cast::<MaybeUninit<u8>>();
144
145 let len = NonZero::new(len).expect("guarded by 'is zero sized Vec' check upstream");
146
147 let block_ptr = NonNull::new(Box::into_raw(Box::new(VecBlock::new(vec)))).expect("we just allocated it - it cannot possibly be null");
148
149 let block_ref = unsafe { BlockRef::new(block_ptr, &BLOCK_REF_FNS) };
153
154 unsafe { Block::new(capacity_ptr, len, block_ref) }
159}
160
161const BLOCK_REF_FNS: BlockRefVTable<VecBlock> = BlockRefVTable::from_trait();
162
163struct VecBlockIterator {
165 remaining: Vec<u8>,
166}
167
168impl VecBlockIterator {
169 const fn new(vec: Vec<u8>) -> Self {
170 Self { remaining: vec }
171 }
172}
173
174impl Iterator for VecBlockIterator {
175 type Item = Vec<u8>;
176
177 fn next(&mut self) -> Option<Self::Item> {
178 if self.remaining.is_empty() {
179 return None;
180 }
181
182 let bytes_to_take = self.remaining.len().min(BlockSize::MAX as usize);
183
184 let keep = self.remaining.split_off(bytes_to_take);
188 let take = std::mem::replace(&mut self.remaining, keep);
189
190 Some(take)
191 }
192
193 fn size_hint(&self) -> (usize, Option<usize>) {
194 let blocks_remaining = self.remaining.len().div_ceil(BlockSize::MAX as usize);
195 (blocks_remaining, Some(blocks_remaining))
196 }
197}
198
199#[cfg_attr(coverage_nightly, coverage(off))]
200#[cfg(test)]
201mod tests {
202 use super::*;
203
204 #[test]
205 fn vec_into_view() {
206 let vec = vec![1, 2, 3, 4, 5];
207 let mut view: BytesView = vec.into();
208 assert_eq!(view.len(), 5);
209
210 assert_eq!(view.get_byte(), 1);
211 assert_eq!(view.get_byte(), 2);
212 assert_eq!(view.get_byte(), 3);
213 assert_eq!(view.get_byte(), 4);
214 assert_eq!(view.get_byte(), 5);
215
216 assert!(view.is_empty());
217 }
218
219 #[test]
220 fn zero_sized_vec() {
221 let vec = Vec::<u8>::new();
222 let view: BytesView = vec.into();
223
224 assert_eq!(view.len(), 0);
225 assert!(view.is_empty());
226 }
227
228 #[test]
229 fn test_vec_to_view() {
230 let vec = vec![b'H', b'e', b'l', b'l', b'o', b',', b' ', b'w', b'o', b'r', b'l', b'd', b'!'];
231
232 let vec_data_ptr = vec.as_ptr();
233
234 let view: BytesView = vec.into();
235
236 assert_eq!(view.len(), 13);
237 assert_eq!(view, b"Hello, world!");
238
239 assert_eq!(view.first_slice().as_ptr(), vec_data_ptr);
241 }
242
243 #[test]
244 fn test_giant_vec_to_view() {
245 #[cfg(all(not(miri), any(target_os = "linux", target_os = "windows")))]
248 if crate::testing::system_memory() < 10_000_000_000 {
249 eprintln!("Skipping giant allocation test due to insufficient memory.");
250 return;
251 }
252
253 let vec = vec![0u8; 5_000_000_000];
254
255 let view: BytesView = vec.into();
256 assert_eq!(view.len(), 5_000_000_000);
257 assert_eq!(view.first_slice().len(), u32::MAX as usize);
258 assert_eq!(view.into_spans_reversed().len(), 2);
259 }
260
261 #[test]
262 fn test_vec_block_iterator_size_hint_single_block() {
263 let vec = vec![b'H', b'e', b'l', b'l', b'o', b',', b' ', b'w', b'o', b'r', b'l', b'd', b'!'];
264 let iterator = VecBlockIterator::new(vec);
265
266 let (min, max) = iterator.size_hint();
267 assert_eq!(min, 1);
268 assert_eq!(max, Some(1));
269 }
270
271 #[test]
272 fn test_vec_block_iterator_size_hint_multiple_blocks() {
273 let size = (BlockSize::MAX as usize) + 1000;
275 let vec = vec![0u8; size];
276
277 let iterator = VecBlockIterator::new(vec);
278
279 let (min, max) = iterator.size_hint();
280 assert_eq!(min, 2);
281 assert_eq!(max, Some(2));
282 }
283
284 #[test]
285 fn test_vec_block_iterator_size_hint_empty() {
286 let vec = Vec::new();
287 let iterator = VecBlockIterator::new(vec);
288
289 let (min, max) = iterator.size_hint();
290 assert_eq!(min, 0);
291 assert_eq!(max, Some(0));
292 }
293
294 #[test]
295 fn test_vec_block_iterator_size_hint_exact_block_size() {
296 let vec = vec![0u8; BlockSize::MAX as usize];
298
299 let iterator = VecBlockIterator::new(vec);
300
301 let (min, max) = iterator.size_hint();
302 assert_eq!(min, 1);
303 assert_eq!(max, Some(1));
304 }
305}