uninit_tools/
buffers.rs

1use core::mem::MaybeUninit;
2
3use crate::buffer::Buffer;
4use crate::initializer::BuffersInitializer;
5use crate::traits::{Initialize, InitializeVectored};
6use crate::wrappers::{AssertInit, SingleVector};
7
8pub struct Buffers<T> {
9    initializer: BuffersInitializer<T>,
10    // TODO: Use a trait to omit this field when the type already is initialized.
11    // NOTE: We use this counter __only internally__. Namely, in order to avoid unnecessary bounds
12    // checking when indexing buffers, this must not be changed to any arbitrary value.
13    // TODO: Use some integer generic type (or perhaps simply a platform-specific type alias), to
14    // reduce the memory footprint when IOV_MAX happens to be less than 65536. Or at least just
15    // 32-bit.
16    items_filled_for_vector: usize,
17    // TODO: Use specialization to omit this field when there is only one buffer..
18    vectors_filled: usize,
19}
20
21impl<T> Buffers<T> {
22    #[inline]
23    pub const fn from_initializer(initializer: BuffersInitializer<T>) -> Self {
24        Self {
25            initializer,
26            items_filled_for_vector: 0,
27            vectors_filled: 0,
28        }
29    }
30    #[inline]
31    pub const fn new(inner: T) -> Self {
32        Self::from_initializer(BuffersInitializer::uninit(inner))
33    }
34    #[inline]
35    pub const fn initializer(&self) -> &BuffersInitializer<T> {
36        &self.initializer
37    }
38    #[inline]
39    pub fn initializer_mut(&mut self) -> &mut BuffersInitializer<T> {
40        &mut self.initializer
41    }
42    #[inline]
43    pub fn into_initializer(self) -> BuffersInitializer<T> {
44        let Self { initializer, .. } = self;
45
46        initializer
47    }
48    #[inline]
49    pub fn into_inner(self) -> T {
50        self.into_initializer().into_inner()
51    }
52    #[inline]
53    pub const fn vectors_filled(&self) -> usize {
54        self.vectors_filled
55    }
56}
57impl<T, Item> Buffers<T>
58where
59    T: InitializeVectored,
60    T::UninitVector: Initialize<Item = Item>,
61{
62    #[inline]
63    pub fn all_previously_filled_vectors(&self) -> &[AssertInit<T::UninitVector>] {
64        self.debug_assert_validity();
65
66        unsafe {
67            let filled = {
68                let src = self.initializer().all_uninit_vectors();
69
70                core::slice::from_raw_parts(src.as_ptr(), self.vectors_filled())
71            };
72
73            AssertInit::cast_from_slices(filled)
74        }
75    }
76    #[inline]
77    pub fn all_previously_filled_vectors_mut(&mut self) -> &[AssertInit<T::UninitVector>] {
78        self.debug_assert_validity();
79
80        unsafe {
81            let ptr = { self.initializer_mut().all_uninit_vectors_mut().as_mut_ptr() };
82            let filled = core::slice::from_raw_parts_mut(ptr, self.vectors_filled());
83            AssertInit::cast_from_slices_mut(filled)
84        }
85    }
86    #[inline]
87    pub fn current_vector_all(&self) -> Option<&[MaybeUninit<Item>]> {
88        self.debug_assert_validity();
89
90        let all_vectors = self.initializer().all_uninit_vectors();
91
92        if self.vectors_filled == all_vectors.len() {
93            None
94        } else {
95            Some(unsafe { all_vectors.get_unchecked(self.vectors_filled) }.as_maybe_uninit_slice())
96        }
97    }
98    /// Get the entire current vector as a mutable possibly-uninitialized slice, or None if all
99    /// vectors are already filled.
100    ///
101    /// # Safety
102    ///
103    /// The caller must not allow the returned slice to be de-initialized in safe code.
104    #[inline]
105    pub unsafe fn current_vector_all_mut(&mut self) -> Option<&mut [MaybeUninit<Item>]> {
106        self.debug_assert_validity();
107
108        let all_vectors_mut = self.initializer.all_uninit_vectors_mut();
109
110        if self.vectors_filled == all_vectors_mut.len() {
111            None
112        } else {
113            Some(
114                all_vectors_mut
115                    .get_unchecked_mut(self.vectors_filled)
116                    .as_maybe_uninit_slice_mut(),
117            )
118        }
119    }
120    #[inline]
121    pub fn current_vector_init_uninit_parts(&self) -> Option<(&[Item], &[MaybeUninit<Item>])> {
122        self.debug_assert_validity();
123
124        let ordering = self
125            .vectors_filled()
126            .cmp(&self.initializer().vectors_initialized());
127
128        match ordering {
129            // The current vector is filled, but there are one or more vectors in front of it, that
130            // are already initialized. We can thus simply assume that the current vector is
131            // completely initialized.
132            core::cmp::Ordering::Less => Some((
133                unsafe { crate::cast_uninit_to_init_slice(self.current_vector_all()?) },
134                &[],
135            )),
136
137            // The current vector (when tracking how they're filled) is behind one in front of it
138            // that is not yet initialized. This cannot happen, and is library UB.
139            core::cmp::Ordering::Greater => unsafe { core::hint::unreachable_unchecked() },
140
141            // If the current vector is both in the initializing and in the filling phase, then we
142            // will need to split it according to the initializer.
143            core::cmp::Ordering::Equal => self.initializer().current_vector_init_uninit_parts(),
144        }
145    }
146    #[inline]
147    pub fn current_vector_init_uninit_parts_mut(
148        &mut self,
149    ) -> Option<(&mut [Item], &mut [MaybeUninit<Item>])> {
150        self.debug_assert_validity();
151
152        let ordering = self
153            .vectors_filled()
154            .cmp(&self.initializer().vectors_initialized());
155
156        match ordering {
157            // NOTE: See current_vector_init_uninit_parts. I'm lazy and I don't strive to avoid
158            // redundancy, except at the API level :-)
159            core::cmp::Ordering::Less => Some((
160                unsafe { crate::cast_uninit_to_init_slice_mut(self.current_vector_all_mut()?) },
161                &mut [],
162            )),
163            core::cmp::Ordering::Greater => unsafe { core::hint::unreachable_unchecked() },
164            core::cmp::Ordering::Equal => self
165                .initializer_mut()
166                .current_vector_init_uninit_parts_mut(),
167        }
168    }
169    #[inline]
170    pub fn current_vector_filled_part(&self) -> Option<&[Item]> {
171        self.debug_assert_validity();
172
173        let base_ptr = { self.current_vector_all()?.as_ptr() };
174
175        Some(unsafe {
176            core::slice::from_raw_parts(base_ptr as *const Item, self.items_filled_for_vector)
177        })
178    }
179    #[inline]
180    pub fn current_vector_filled_part_mut(&mut self) -> Option<&mut [Item]> {
181        self.debug_assert_validity();
182
183        unsafe {
184            let base_ptr = { self.current_vector_all_mut()?.as_mut_ptr() };
185            Some(core::slice::from_raw_parts_mut(
186                base_ptr as *mut Item,
187                self.items_filled_for_vector,
188            ))
189        }
190    }
191    #[inline]
192    pub fn current_vector_unfilled_all_part(&self) -> Option<&[MaybeUninit<Item>]> {
193        self.debug_assert_validity();
194
195        let (base_ptr, base_len) = {
196            let all = self.current_vector_all()?;
197            (all.as_ptr(), all.len())
198        };
199
200        Some(unsafe {
201            let ptr = base_ptr.add(self.items_filled_for_vector);
202            let len = base_len - self.items_filled_for_vector;
203
204            core::slice::from_raw_parts(ptr, len)
205        })
206    }
207    /// Retrieve all of the unfilled part as a single possibly-uninitialized mutable reference.
208    // TODO: explain better
209    /// # Safety
210    ///
211    /// Since the returned slice could contain both the unfilled but initialized, and the unfilled
212    /// and uninitialized, this allows it to overlap. Thus, the caller must not de-initialize the
213    /// resulting slice in any way, in safe code.
214    #[inline]
215    pub unsafe fn current_vector_unfilled_all_part_mut(
216        &mut self,
217    ) -> Option<&mut [MaybeUninit<Item>]> {
218        self.debug_assert_validity();
219
220        let (base_ptr, base_len) = {
221            let all = self.current_vector_all_mut()?;
222            (all.as_mut_ptr(), all.len())
223        };
224
225        Some({
226            let ptr = base_ptr.add(self.items_filled_for_vector);
227            let len = base_len - self.items_filled_for_vector;
228
229            core::slice::from_raw_parts_mut(ptr, len)
230        })
231    }
232    #[inline]
233    pub fn all_next_unfilled_vectors(&self) -> &[T::UninitVector] {
234        self.debug_assert_validity();
235
236        let total_vector_count = self.total_vector_count();
237        let vectors_filled = self.vectors_filled();
238        let after_vectors_filled = vectors_filled + 1;
239
240        let is_within =
241            vectors_filled != total_vector_count && after_vectors_filled != total_vector_count;
242
243        if is_within {
244            unsafe {
245                let (src_ptr, src_len) = {
246                    let src = self.initializer().all_uninit_vectors();
247
248                    (src.as_ptr(), src.len())
249                };
250
251                // SAFETY: See safe docs for all_next_unfilled_vectors_mut.
252                let ptr = src_ptr.add(after_vectors_filled);
253                let len = src_len - after_vectors_filled;
254
255                core::slice::from_raw_parts(ptr, len)
256            }
257        } else {
258            &[]
259        }
260    }
261    #[inline]
262    pub fn all_next_unfilled_vectors_mut(&mut self) -> &mut [T::UninitVector] {
263        self.debug_assert_validity();
264
265        let total_vector_count = self.total_vector_count();
266        let vectors_filled = self.vectors_filled();
267        let after_vectors_filled = vectors_filled + 1;
268
269        let is_within =
270            vectors_filled != total_vector_count && after_vectors_filled != total_vector_count;
271
272        if is_within {
273            unsafe {
274                let src_ptr = { self.initializer_mut().all_uninit_vectors_mut().as_mut_ptr() };
275                // SAFETY: Since the number of vectors filled can __never__ be larger than the total
276                // number of vectors, we can assume that `vectors_filled + 1 < total_vector_count`,
277                // means that it must be less. Therefore, it resides in the same allocated object
278                // as the original slice, making ptr::add safe.
279                let ptr = src_ptr.add(after_vectors_filled);
280                let len = total_vector_count - after_vectors_filled;
281
282                core::slice::from_raw_parts_mut(ptr, len)
283            }
284        } else {
285            &mut []
286        }
287    }
288    /// Return all vectors that have been fully filled, sequentially, as well as the filled part of
289    /// the current vector in progress.
290    pub fn all_filled_vectors(&self) -> (&[AssertInit<T::UninitVector>], &[Item]) {
291        // TODO: Distinguish between None and Some(&[]). Do we really want optional values, when
292        // empty slices work too?
293        (
294            self.all_previously_filled_vectors(),
295            self.current_vector_filled_part().unwrap_or(&[]),
296        )
297    }
298    /// For the current vector, return the unfilled and initialized part, the unfilled but
299    /// initialized part, and the unfilled and uninitialized part, in that order.
300    ///
301    /// Note that unlike [`current_vector_all_mut`](Self::current_vector_all_mut), the exclusive
302    /// aliasing rules that come with mutable references are not needed here. The same result as
303    /// calling this can be achieved by calling the finer-grained methods that access the
304    /// individual parts of the current vector.
305    // FIXME: which ones?
306    pub fn current_vector_parts(&self) -> Option<VectorParts<'_, Item>> {
307        self.debug_assert_validity();
308
309        unsafe {
310            let (src_ptr, src_len) = {
311                let src = self.current_vector_all()?;
312
313                (src.as_ptr(), src.len())
314            };
315
316            let filled_base_ptr = src_ptr as *const Item;
317            let filled_len = self.items_filled_for_vector;
318
319            let init_len = self
320                .initializer()
321                .items_initialized_for_vector_unchecked(self.vectors_filled);
322
323            let unfilled_init_base_ptr = src_ptr.add(self.items_filled_for_vector) as *const Item;
324            let unfilled_init_len = init_len - filled_len;
325
326            let unfilled_uninit_base_ptr = src_ptr.add(init_len);
327            let unfilled_uninit_len = src_len - init_len;
328
329            let filled = core::slice::from_raw_parts(filled_base_ptr, filled_len);
330            let unfilled_init =
331                core::slice::from_raw_parts(unfilled_init_base_ptr, unfilled_init_len);
332            let unfilled_uninit =
333                core::slice::from_raw_parts(unfilled_uninit_base_ptr, unfilled_uninit_len);
334
335            Some(VectorParts {
336                filled,
337                unfilled_init,
338                unfilled_uninit,
339            })
340        }
341    }
342    /// For the current vector, return the unfilled and initialized part, the unfilled but
343    /// initialized part, and the unfilled and uninitialized part mutably, in that order.
344    pub fn current_vector_parts_mut(&mut self) -> Option<VectorPartsMut<'_, Item>> {
345        self.debug_assert_validity();
346
347        unsafe {
348            let (src_ptr, src_len) = {
349                let src = self.current_vector_all_mut()?;
350
351                (src.as_mut_ptr(), src.len())
352            };
353
354            let filled_base_ptr = src_ptr as *mut Item;
355            let filled_len = self.items_filled_for_vector;
356
357            let init_len = self
358                .initializer()
359                .items_initialized_for_vector_unchecked(self.vectors_filled);
360
361            let unfilled_init_base_ptr = src_ptr.add(self.items_filled_for_vector) as *mut Item;
362            let unfilled_init_len = init_len - filled_len;
363
364            let unfilled_uninit_base_ptr = src_ptr.add(init_len);
365            let unfilled_uninit_len = src_len - init_len;
366
367            let filled = core::slice::from_raw_parts_mut(filled_base_ptr, filled_len);
368            let unfilled_init =
369                core::slice::from_raw_parts_mut(unfilled_init_base_ptr, unfilled_init_len);
370            let unfilled_uninit =
371                core::slice::from_raw_parts_mut(unfilled_uninit_base_ptr, unfilled_uninit_len);
372
373            Some(VectorPartsMut {
374                filled,
375                unfilled_init,
376                unfilled_uninit,
377            })
378        }
379    }
380    fn debug_assert_validity(&self) {
381        debug_assert!(self.items_filled_for_vector <= isize::MAX as usize);
382        debug_assert!(self.vectors_filled <= self.initializer().total_vector_count());
383        debug_assert!(self.vectors_filled <= self.initializer().vectors_initialized());
384        // TODO
385    }
386    #[inline]
387    pub fn total_vector_count(&self) -> usize {
388        self.initializer().total_vector_count()
389    }
390    #[inline]
391    pub fn vectors_remaining(&self) -> usize {
392        self.total_vector_count()
393            .wrapping_sub(self.vectors_filled())
394    }
395    pub fn count_remaining_items_to_fill(&self) -> usize {
396        self.remaining_for_current_vector()
397            + self
398                .all_next_unfilled_vectors()
399                .iter()
400                .map(|unfilled_vector| unfilled_vector.as_maybe_uninit_slice().len())
401                .sum::<usize>()
402    }
403    pub fn count_total_items_in_all_vectors(&self) -> usize {
404        self.initializer().count_total_items_in_all_vectors()
405    }
406    /// Get the number of items that remain before the current vector becomes fully filled.
407    ///
408    /// If there is no current vector, which is the condition when all vectors have been filled,
409    /// then this returns zero.
410    #[inline]
411    pub fn remaining_for_current_vector(&self) -> usize {
412        self.current_vector_all().map_or(0, |current_vector| {
413            current_vector.len() - self.items_filled_for_vector
414        })
415    }
416    /// Advance the current vector by `count` items.
417    ///
418    /// # Panics
419    ///
420    /// This will panic if the initialized part of the current vector is exceeded. When calling
421    /// this in FFI contexts, you must call the advance functions in the initializer before calling
422    /// this.
423    pub fn advance_current_vector(&mut self, count: usize) {
424        let current_vector_all_len = match self.current_vector_all() {
425            Some(current) => current.len(),
426            None => panic!(
427                "cannot advance the current vector by {} B, since no vectors were left",
428                count
429            ),
430        };
431
432        let ordering = Ord::cmp(
433            &self.vectors_filled(),
434            &self.initializer().vectors_initialized(),
435        );
436
437        let end = self.items_filled_for_vector + count;
438
439        match ordering {
440            core::cmp::Ordering::Equal => {
441                assert!(
442                    end <= self.initializer().items_initialized_for_current_vector(),
443                    "cannot advance the fill count beyond the initialized part"
444                );
445                debug_assert!(end <= current_vector_all_len);
446            }
447            core::cmp::Ordering::Less => {
448                assert!(
449                    end <= current_vector_all_len,
450                    "cannot advance the current vector beyond the end"
451                );
452            }
453            core::cmp::Ordering::Greater => unsafe { core::hint::unreachable_unchecked() },
454        }
455
456        self.items_filled_for_vector += end;
457
458        if self.items_filled_for_vector == current_vector_all_len {
459            self.vectors_filled += 1;
460            self.items_filled_for_vector = 0;
461        }
462    }
463    pub fn advance_to_current_vector_end(&mut self) {
464        let current_vector_all = match self.current_vector_all() {
465            Some(current) => current,
466            None => {
467                panic!("cannot advance the current vector to end, when there are no vectors left")
468            }
469        };
470
471        let ordering = Ord::cmp(
472            &self.vectors_filled(),
473            &self.initializer().vectors_initialized(),
474        );
475
476        match ordering {
477            core::cmp::Ordering::Equal => assert_eq!(
478                self.initializer().items_initialized_for_current_vector(),
479                current_vector_all.len()
480            ),
481            core::cmp::Ordering::Less => (),
482            core::cmp::Ordering::Greater => unsafe { core::hint::unreachable_unchecked() },
483        }
484
485        self.vectors_filled += 1;
486        self.items_filled_for_vector = 0;
487    }
488}
489impl<T> Buffers<T>
490where
491    T: InitializeVectored,
492    T::UninitVector: Initialize<Item = u8>,
493{
494    pub fn with_current_vector_unfilled_zeroed(&mut self) -> Option<&mut [u8]> {
495        let _ = self.current_vector_all()?;
496
497        let ordering = Ord::cmp(
498            &self.vectors_filled(),
499            &self.initializer().vectors_initialized(),
500        );
501
502        match ordering {
503            // If the current vector is not fully initialized, we must first initialize the rest,
504            // before returning the vector as initialized.
505            core::cmp::Ordering::Equal => {
506                self.initializer_mut().zero_current_vector_uninit_part();
507            }
508            // No need to initialize anything since the initialized vectors are already ahead of
509            // the vectors that need to be filled.
510            core::cmp::Ordering::Less => (),
511            core::cmp::Ordering::Greater => unsafe { core::hint::unreachable_unchecked() },
512        }
513
514        Some(unsafe {
515            let current_vector_all = self.current_vector_all_mut().expect(
516                "expected the current vector to exist, since an earlier check has been done",
517            );
518
519            crate::cast_uninit_to_init_slice_mut(current_vector_all)
520        })
521    }
522}
523impl<T> Buffers<SingleVector<T>>
524where
525    T: Initialize,
526{
527    pub fn from_single_buffer(buffer: Buffer<T>) -> Self {
528        let Buffer {
529            initializer,
530            items_filled,
531        } = buffer;
532
533        Self {
534            initializer: BuffersInitializer::from_single_buffer_initializer(initializer),
535            items_filled_for_vector: items_filled,
536            vectors_filled: 0,
537        }
538    }
539}
540#[derive(Clone, Copy, Debug, Default)]
541pub struct VectorParts<'a, Item> {
542    pub filled: &'a [Item],
543    pub unfilled_init: &'a [Item],
544    pub unfilled_uninit: &'a [MaybeUninit<Item>],
545}
546#[derive(Debug, Default)]
547pub struct VectorPartsMut<'a, Item> {
548    pub filled: &'a mut [Item],
549    pub unfilled_init: &'a mut [Item],
550    pub unfilled_uninit: &'a mut [MaybeUninit<Item>],
551}
552
553pub struct BuffersRef<'buffers, T> {
554    inner: &'buffers mut Buffers<T>,
555}
556impl<T> Buffers<T> {
557    #[inline]
558    pub fn by_ref(&mut self) -> BuffersRef<'_, T> {
559        BuffersRef { inner: self }
560    }
561}
562impl<'buffers, T> BuffersRef<'buffers, T> {
563    #[inline]
564    pub fn by_ref(&mut self) -> BuffersRef<'_, T> {
565        BuffersRef { inner: self.inner }
566    }
567}
568impl<'buffers, T> BuffersRef<'buffers, T>
569where
570    T: InitializeVectored,
571{
572    pub fn with_current_vector_unfilled_zeroed(&mut self) -> Option<&mut [u8]>
573    where
574        T::UninitVector: Initialize<Item = u8>,
575    {
576        self.inner.with_current_vector_unfilled_zeroed()
577    }
578    pub fn advance_current_vector(&mut self, count: usize) {
579        self.inner.advance_current_vector(count)
580    }
581    pub fn advance_to_current_vector_end(&mut self) {
582        self.inner.advance_to_current_vector_end()
583    }
584}
585
586#[cfg(test)]
587mod tests {
588    use super::*;
589
590    #[test]
591    fn baisc_buffers_ops() {
592        let mut a = [MaybeUninit::<u8>::uninit(); 32];
593        let mut b = [MaybeUninit::uninit(); 8];
594        let mut c = [MaybeUninit::uninit(); 16];
595        let mut d = [MaybeUninit::uninit(); 9];
596
597        let vectors = [&mut a[..], &mut b[..], &mut c[..], &mut d[..]];
598        let buffers = Buffers::new(vectors);
599
600        assert_eq!(buffers.vectors_filled(), 0);
601        //assert_eq!(buffers.vectors_remaining(), 4);
602    }
603    #[test]
604    fn with_current_vector_unfilled_zeroed() {
605        let mut a = [MaybeUninit::<u8>::uninit(); 32];
606        let mut b = [MaybeUninit::uninit(); 8];
607        let mut c = [MaybeUninit::uninit(); 16];
608        let mut d = [MaybeUninit::uninit(); 9];
609
610        let mut vectors = [&mut a[..], &mut b[..], &mut c[..], &mut d[..]];
611        let mut buffers = Buffers::new(&mut vectors[..]);
612        let text = b"Hello, world!";
613
614        while let Some(slice) = buffers.with_current_vector_unfilled_zeroed() {
615            let to_copy = core::cmp::min(slice.len(), text.len());
616            slice[..to_copy].copy_from_slice(&text[..to_copy]);
617            buffers.advance_to_current_vector_end();
618        }
619        // TODO: Check that the vectors have the correct values.
620    }
621}