Skip to main content

vortex_buffer/
trusted_len.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4/// Trait for all types which have a known upper-bound.
5///
6/// Functions that receive a `TrustedLen` iterator can assume that it's `size_hint` is exact,
7/// and can pre-allocate memory, unroll loops, or otherwise optimize their implementations
8/// accordingly.
9///
10/// # Safety
11///
12/// The type which implements this trait must provide an exact `Some` upper-bound for its
13/// `size_hint` method. Failure to do so can trigger undefined behavior in users of the trait.
14pub unsafe trait TrustedLen: Iterator {}
15
16/// An adapter that turns any iterator into a `TrustedLen` iterator.
17///
18/// # Safety
19///
20/// The caller must guarantee that the wrapped iterator does indeed have an exact length.
21pub struct TrustedLenAdapter<I> {
22    inner: I,
23    len: usize,
24    #[cfg(debug_assertions)]
25    count: usize,
26}
27
28impl<I: Iterator> Iterator for TrustedLenAdapter<I> {
29    type Item = I::Item;
30
31    #[inline]
32    fn next(&mut self) -> Option<Self::Item> {
33        let item = self.inner.next();
34        #[cfg(debug_assertions)]
35        {
36            if item.is_some() {
37                self.count += 1;
38                assert!(
39                    self.count <= self.len,
40                    "TrustedLenAdapter: iterator yielded more items than promised"
41                );
42            } else {
43                assert_eq!(
44                    self.len, self.count,
45                    "TrustedLenAdapter: iterator ended early"
46                );
47            }
48        }
49        item
50    }
51
52    #[inline]
53    fn size_hint(&self) -> (usize, Option<usize>) {
54        (self.len, Some(self.len))
55    }
56}
57
58unsafe impl<I: Iterator> TrustedLen for TrustedLenAdapter<I> {}
59
60/// Extension trait for wrapping any iterator in a [`TrustedLenAdapter`].
61pub trait TrustedLenExt: Iterator + Sized {
62    /// Wraps this iterator in a `TrustedLenAdapter`.
63    ///
64    /// # Safety
65    ///
66    /// The caller must guarantee that the iterator does indeed have an exact length.
67    unsafe fn trusted_len(self) -> TrustedLenAdapter<Self> {
68        let (lower_bound, upper_bound_opt) = self.size_hint();
69        if let Some(upper_bound) = upper_bound_opt {
70            assert_eq!(
71                lower_bound, upper_bound,
72                "TrustedLenExt: iterator size hints must match if upper bound is given"
73            );
74        }
75
76        TrustedLenAdapter {
77            inner: self,
78            len: lower_bound,
79            #[cfg(debug_assertions)]
80            count: 0,
81        }
82    }
83}
84
85impl<I: Iterator> TrustedLenExt for I {}
86
87macro_rules! impl_for_range {
88    ($($typ:ty),*) => {
89        $(
90            unsafe impl TrustedLen for std::ops::Range<$typ> {}
91            unsafe impl TrustedLen for std::ops::RangeInclusive<$typ> {}
92            // StepBy
93            // This is only fine for iterators that are TrustedRandomAccess but instead of adding another trait we just declare step by of ranges as supported
94            unsafe impl TrustedLen for std::iter::StepBy<std::ops::Range<$typ>> {}
95            unsafe impl TrustedLen for std::iter::StepBy<std::ops::RangeInclusive<$typ>> {}
96        )*
97    };
98}
99
100impl_for_range!(u8, u16, u32, u64, i8, i16, i32, i64, usize);
101
102// std::slice related types
103unsafe impl<T> TrustedLen for std::slice::Iter<'_, T> {}
104
105unsafe impl<T> TrustedLen for std::slice::IterMut<'_, T> {}
106
107// Iterator types
108unsafe impl<B, I, F> TrustedLen for std::iter::Map<I, F>
109where
110    I: TrustedLen,
111    F: FnMut(I::Item) -> B,
112{
113}
114
115unsafe impl<I> TrustedLen for std::iter::Skip<I> where I: TrustedLen {}
116
117unsafe impl<'a, I, T: 'a> TrustedLen for std::iter::Copied<I>
118where
119    I: TrustedLen<Item = &'a T>,
120    T: Copy,
121{
122}
123
124unsafe impl<'a, I, T: 'a> TrustedLen for std::iter::Cloned<I>
125where
126    I: TrustedLen<Item = &'a T>,
127    T: Clone,
128{
129}
130
131unsafe impl<T> TrustedLen for std::vec::IntoIter<T> {}
132
133// Arrays
134unsafe impl<T, const N: usize> TrustedLen for std::array::IntoIter<T, N> {}
135
136// Buffer
137unsafe impl<T> TrustedLen for crate::Iter<'_, T> {}
138unsafe impl<T: Copy> TrustedLen for crate::BufferIterator<T> {}
139
140// ProcessResults
141unsafe impl<'a, I, T: 'a, E: 'a> TrustedLen for itertools::ProcessResults<'a, I, E> where
142    I: TrustedLen<Item = Result<T, E>>
143{
144}
145
146// Enumerate
147unsafe impl<I, T> TrustedLen for std::iter::Enumerate<I> where I: TrustedLen<Item = T> {}
148
149// Zip
150//
151// Both halves must be `TrustedLen`. `Zip::size_hint` reports `min(a_upper, b_upper)`, so an
152// untrusted `U` that under-reports its upper bound while yielding more items makes the `Zip`
153// under-report too. `BufferMut::extend_trusted` reserves exactly that many slots and then
154// writes without bounds checks, so an unconstrained `U` turns a safe `Iterator` impl into an
155// out-of-bounds heap write.
156/// A `Zip` is only `TrustedLen` when both halves are, so it cannot be built from an iterator
157/// without an exact upper bound, such as [`std::iter::repeat`]:
158///
159/// ```compile_fail
160/// use vortex_buffer::trusted_len::TrustedLen;
161///
162/// fn assert_trusted_len<I: TrustedLen>(_: I) {}
163/// assert_trusted_len([1u8, 2, 3].into_iter().zip(std::iter::repeat(0u8)));
164/// ```
165///
166/// Bound the other half instead, e.g. with [`std::iter::repeat_n`]:
167///
168/// ```
169/// use vortex_buffer::trusted_len::TrustedLen;
170///
171/// fn assert_trusted_len<I: TrustedLen>(_: I) {}
172/// assert_trusted_len([1u8, 2, 3].into_iter().zip(std::iter::repeat_n(0u8, 3)));
173/// ```
174unsafe impl<T, U> TrustedLen for std::iter::Zip<T, U>
175where
176    T: TrustedLen,
177    U: TrustedLen,
178{
179}
180
181unsafe impl<T: Clone> TrustedLen for std::iter::RepeatN<T> {}
182
183// Arrow bit iterators
184unsafe impl<'a> TrustedLen for crate::bit::BitIterator<'a> {}
185unsafe impl<'a> TrustedLen for crate::bit::BitChunkIterator<'a> {}
186unsafe impl<'a> TrustedLen for crate::bit::UnalignedBitChunkIterator<'a> {}