vec_utils/vec/
general_zip.rs

1use std::alloc::Layout;
2
3use super::{r#try, Input, Output, Try};
4
5use seal::Seal;
6mod seal {
7    use super::*;
8
9    pub unsafe trait Seal {
10        const LEN: u64;
11
12        type Item;
13        type Data;
14        type Iter: Iterator<Item = Self::Item>;
15
16        fn into_data(self) -> Self::Data;
17
18        fn remaining_len(&self) -> usize;
19
20        fn into_iterator(self) -> Self::Iter;
21
22        fn check_layout<V>() -> bool;
23
24        fn max_cap<V>(data: &Self::Data, depth: &mut u64) -> Option<usize>;
25
26        unsafe fn take_output<V>(data: &mut Self::Data) -> Output<V>;
27
28        unsafe fn take_output_impl<V>(_: &mut Self::Data, min_cap: u64) -> Output<V>;
29
30        unsafe fn next_unchecked(data: &mut Self::Data) -> Self::Item;
31
32        unsafe fn drop_rest(data: &mut Self::Data, len: usize);
33    }
34}
35
36/// A specialized const-list for emulating varaidic generics
37///
38/// To overload what elements can go in this tuple, please use the
39/// [`TupleElem`](trait.TupleElem.html) trait
40///
41/// This is a sealed trait that is not meant to be extended
42pub trait Tuple: Seal {}
43
44/// This trait abstracts away elements of the input stream
45///
46/// # Safety
47///
48/// * It must be valid to call `next_unchecked` at least `len` times
49/// * `len <= capacity`
50/// * if `next_unchecked` defers to another `T: TupleElem`, then you should not call `T::next_unchecked` more than once
51///     in your own `next_unchecked`
52#[allow(clippy::len_without_is_empty)]
53pub unsafe trait TupleElem {
54    /// The items yielded from this element
55    type Item;
56
57    /// The data-segment that `Output<V>` is derived from
58    /// and yields `Item`s
59    type Data;
60
61    /// An iterator over the items in the collection
62    type Iter: Iterator<Item = Self::Item>;
63
64    /// The capacity of the data-segment
65    fn capacity(data: &Self::Data) -> usize;
66
67    /// The currently initialized length of the data-segment
68    ///
69    /// must be less than or equal to the capacity
70    fn len(&self) -> usize;
71
72    /// Convert into a raw data-segment
73    fn into_data(self) -> Self::Data;
74
75    /// Convert to an iterator if we cannot reuse the data-segment
76    fn into_iterator(self) -> Self::Iter;
77
78    /// If this returns `true` if it is safe to call
79    /// `take_output`
80    fn check_layout<V>() -> bool;
81
82    /// Try and create a new output data-segment, if the output segment
83    /// is created, then it owns it's allocation. So you must not deallocate
84    /// the allocation backing `Output<V>`
85    /// 
86    /// # Safety
87    /// 
88    /// `check_layout::<V>` must return true.
89    unsafe fn take_output<V>(data: &mut Self::Data) -> Output<V>;
90
91    /// Get the next_unchecked element
92    ///
93    /// # Safety
94    ///
95    /// This must be called *at most* `len` times
96    unsafe fn next_unchecked(data: &mut Self::Data) -> Self::Item;
97
98    /// Drop the rest of the buffer and deallocate
99    /// if `do_pick` was never called
100    ///
101    /// # Safety
102    ///
103    /// This function should only be called once, and 
104    /// `data` should not be used again
105    unsafe fn drop_rest(data: &mut Self::Data, len: usize);
106}
107
108unsafe impl<A: TupleElem> TupleElem for (A,) {
109    type Item = A::Item;
110    type Data = A::Data;
111    type Iter = A::Iter;
112
113    #[inline(always)]
114    fn capacity(data: &Self::Data) -> usize {
115        A::capacity(data)
116    }
117
118    #[inline(always)]
119    fn len(&self) -> usize {
120        A::len(&self.0)
121    }
122
123    #[inline]
124    fn into_data(self) -> Self::Data {
125        self.0.into_data()
126    }
127
128    #[inline]
129    fn into_iterator(self) -> Self::Iter {
130        self.0.into_iterator()
131    }
132
133    #[inline]
134    fn check_layout<V>() -> bool {
135        A::check_layout::<V>()
136    }
137
138    #[inline]
139    unsafe fn take_output<V>(data: &mut Self::Data) -> Output<V> {
140        A::take_output(data)
141    }
142
143    #[inline]
144    unsafe fn next_unchecked(data: &mut Self::Data) -> Self::Item {
145        A::next_unchecked(data)
146    }
147
148    #[inline]
149    unsafe fn drop_rest(data: &mut Self::Data, len: usize) {
150        A::drop_rest(data, len)
151    }
152}
153
154unsafe impl<A> TupleElem for Vec<A> {
155    type Item = A;
156    type Data = Input<A>;
157    type Iter = std::vec::IntoIter<A>;
158
159    #[inline(always)]
160    fn capacity(data: &Self::Data) -> usize {
161        data.cap
162    }
163
164    #[inline(always)]
165    fn len(&self) -> usize {
166        self.len()
167    }
168
169    #[inline]
170    fn into_data(self) -> Self::Data {
171        Input::from(self)
172    }
173
174    #[inline]
175    fn into_iterator(self) -> Self::Iter {
176        self.into_iter()
177    }
178
179    #[inline]
180    fn check_layout<V>() -> bool {
181        Layout::new::<A>() == Layout::new::<V>()
182    }
183
184    #[inline]
185    unsafe fn take_output<V>(data: &mut Self::Data) -> Output<V> {
186        debug_assert!(Layout::new::<A>() == Layout::new::<V>());
187
188        data.drop_alloc = false;
189        Output::new(data.start as *mut V, data.cap)
190    }
191
192    #[inline]
193    unsafe fn next_unchecked(data: &mut Self::Data) -> Self::Item {
194        let ptr = data.ptr;
195        data.ptr = data.ptr.add(1);
196        ptr.read()
197    }
198
199    #[inline]
200    unsafe fn drop_rest(data: &mut Self::Data, len: usize) {
201        defer! {
202            if data.drop_alloc {
203                Vec::from_raw_parts(data.start, 0, data.cap);
204            }
205        }
206
207        std::ptr::drop_in_place(std::slice::from_raw_parts_mut(data.ptr, data.len - len));
208    }
209}
210
211impl<A: TupleElem> Tuple for (A,) {}
212unsafe impl<A: TupleElem> Seal for (A,) {
213    const LEN: u64 = 0;
214
215    type Item = A::Item;
216    type Data = A::Data;
217    type Iter = A::Iter;
218
219    #[inline]
220    fn into_data(self) -> Self::Data {
221        self.0.into_data()
222    }
223
224    #[inline]
225    fn into_iterator(self) -> Self::Iter {
226        self.0.into_iterator()
227    }
228
229    #[inline]
230    fn remaining_len(&self) -> usize {
231        self.0.len()
232    }
233
234    #[inline]
235    fn check_layout<V>() -> bool {
236        A::check_layout::<V>()
237    }
238
239    #[inline]
240    fn max_cap<V>(data: &Self::Data, depth: &mut u64) -> Option<usize> {
241        if A::check_layout::<V>() {
242            *depth = Self::LEN;
243            Some(A::capacity(data))
244        } else {
245            None
246        }
247    }
248
249    #[inline]
250    unsafe fn take_output<V>(data: &mut Self::Data) -> Output<V> {
251        A::take_output::<V>(data)
252    }
253
254    #[inline]
255    unsafe fn take_output_impl<V>(data: &mut Self::Data, depth: u64) -> Output<V> {
256        debug_assert_eq!(Self::LEN, depth);
257        A::take_output(data)
258    }
259
260    #[inline]
261    unsafe fn next_unchecked(data: &mut Self::Data) -> Self::Item {
262        A::next_unchecked(data)
263    }
264
265    #[inline]
266    unsafe fn drop_rest(data: &mut Self::Data, len: usize) {
267        A::drop_rest(data, len)
268    }
269}
270
271impl<A: TupleElem, T: Tuple> Tuple for (A, T) {}
272unsafe impl<A: TupleElem, T: Seal> Seal for (A, T) {
273    const LEN: u64 = T::LEN + 1;
274
275    type Item = (A::Item, T::Item);
276    type Data = (A::Data, T::Data);
277    type Iter = std::iter::Zip<A::Iter, T::Iter>;
278
279    #[inline]
280    fn into_data(self) -> Self::Data {
281        (self.0.into_data(), self.1.into_data())
282    }
283
284    #[inline]
285    fn into_iterator(self) -> Self::Iter {
286        self.0.into_iterator().zip(self.1.into_iterator())
287    }
288
289    #[inline]
290    fn remaining_len(&self) -> usize {
291        self.0.len().min(self.1.remaining_len())
292    }
293
294    #[inline]
295    fn check_layout<V>() -> bool {
296        A::check_layout::<V>() || T::check_layout::<V>()
297    }
298
299    #[inline]
300    fn max_cap<V>((a, rest): &Self::Data, depth: &mut u64) -> Option<usize> {
301        let cap_rest = T::max_cap::<V>(rest, depth);
302
303        if A::check_layout::<V>() {
304            let cap = A::capacity(a);
305
306            if let Some(cap_rest) = cap_rest {
307                if cap_rest > cap {
308                    return Some(cap_rest);
309                }
310            }
311
312            *depth = Self::LEN;
313            Some(cap)
314        } else {
315            cap_rest
316        }
317    }
318
319    #[inline]
320    unsafe fn take_output<V>(data: &mut Self::Data) -> Output<V> {
321        let mut depth = 0;
322        let val = Self::max_cap::<V>(data, &mut depth);
323        debug_assert!(val.is_some());
324        Self::take_output_impl(data, depth)
325    }
326
327    #[inline]
328    unsafe fn take_output_impl<V>((a, rest): &mut Self::Data, depth: u64) -> Output<V> {
329        if Self::LEN == depth {
330            A::take_output(a)
331        } else {
332            T::take_output_impl(rest, depth)
333        }
334    }
335
336    #[inline]
337    unsafe fn next_unchecked((vec, rest): &mut Self::Data) -> Self::Item {
338        (A::next_unchecked(vec), T::next_unchecked(rest))
339    }
340
341    #[inline]
342    unsafe fn drop_rest((vec, rest): &mut Self::Data, len: usize) {
343        defer! {
344            T::drop_rest(rest, len);
345        }
346
347        A::drop_rest(vec, len)
348    }
349}
350
351struct ZipWithIter<V, In: Tuple> {
352    // This left buffer is the one that will be reused
353    // to write the output into
354    output: Output<V>,
355
356    // We will only read from this buffer
357    input: In::Data,
358
359    // the initial length of the input
360    initial_len: usize,
361
362    // the remaing length of the input
363    remaining_len: usize,
364
365    should_free_output: bool,
366}
367
368/// Does the work of the `try_zip_with` or `zip_with` macros.
369pub fn try_zip_with_impl<R: Try, In: Tuple>(
370    input: In,
371    f: impl FnMut(In::Item) -> R,
372) -> Result<Vec<R::Ok>, R::Error> {
373    if In::check_layout::<R::Ok>() {
374        let len = input.remaining_len();
375        let mut input = input.into_data();
376
377        ZipWithIter::<_, In> {
378            output: unsafe { In::take_output::<R::Ok>(&mut input) },
379            input,
380            initial_len: len,
381            remaining_len: len,
382            should_free_output: true,
383        }
384        .try_into_vec(f)
385    } else {
386        input.into_iterator().map(f).map(R::into_result).collect()
387    }
388}
389
390impl<V, In: Tuple> ZipWithIter<V, In> {
391    pub fn try_into_vec<R: Try<Ok = V>, F: FnMut(In::Item) -> R>(
392        mut self,
393        mut f: F,
394    ) -> Result<Vec<V>, R::Error> {
395        // this does a pointer walk and reads from left and right in lock-step
396        // then passes those values to the function to be processed
397        unsafe {
398            while let Some(remaining_len) = self.remaining_len.checked_sub(1) {
399                self.remaining_len = remaining_len;
400
401                let input = In::next_unchecked(&mut self.input);
402
403                self.output.ptr.write(r#try!(f(input)));
404                self.output.ptr = self.output.ptr.add(1);
405            }
406
407            // We don't want to drop `self` if dropping the excess elements panics
408            // as that could lead to double drops
409            self.should_free_output = false;
410            
411            let (ptr, len, cap) = (
412                self.output.start,
413                self.initial_len,
414                self.output.cap,
415            );
416
417            drop(self);
418
419            // create the vector now, so that if we panic in drop, we don't leak it
420            Ok(Vec::from_raw_parts(ptr, len, cap))
421        }
422    }
423}
424
425impl<V, In: Tuple> Drop for ZipWithIter<V, In> {
426    fn drop(&mut self) {
427        let &mut ZipWithIter {
428            ref mut output,
429            ref mut input,
430            should_free_output,
431            initial_len,
432            remaining_len,
433            ..
434        } = self;
435
436        let initialized_len = initial_len - remaining_len;
437
438        defer! {
439            if should_free_output {
440                unsafe {
441                    Vec::from_raw_parts(output.start, initialized_len - 1, output.cap);
442                }
443            }
444        }
445
446        unsafe {
447            In::drop_rest(input, initialized_len);
448        }
449    }
450}