scratchpad/
array_iter.rs

1// Copyright 2018-2021 Theodore Cipicchio
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! Consuming iterator for static arrays.
10
11use super::Array;
12use core::{mem::ManuallyDrop, ptr, slice};
13
14/// Consuming iterator for static arrays.
15pub struct ArrayIter<T>
16where
17    T: Array,
18{
19    /// Source array being consumed.
20    source: ManuallyDrop<T>,
21    /// Index of the next element to yield.
22    index: usize,
23}
24
25impl<T> ArrayIter<T>
26where
27    T: Array,
28{
29    /// Creates a new iterator consuming all elements in the given array.
30    pub fn new(source: T) -> Self {
31        Self {
32            source: ManuallyDrop::new(source),
33            index: 0,
34        }
35    }
36}
37
38impl<T> Iterator for ArrayIter<T>
39where
40    T: Array,
41{
42    type Item = T::Item;
43
44    fn next(&mut self) -> Option<Self::Item> {
45        let source = self.source.as_slice();
46        let index = self.index;
47        if index < source.len() {
48            self.index = index + 1;
49
50            Some(unsafe { ptr::read(&source[index]) })
51        } else {
52            None
53        }
54    }
55}
56
57impl<T> Drop for ArrayIter<T>
58where
59    T: Array,
60{
61    fn drop(&mut self) {
62        // Drop all unconsumed elements.
63        let source = self.source.as_mut_slice();
64        let remaining_len = source.len() - self.index;
65        unsafe {
66            // The Rust compiler and standard library try to prevent cases
67            // where the length of an allocation is larger than `isize::MAX`
68            // (see the `pointer::offset` safety documentation), so casting
69            // the source array length to an `isize` should be okay.
70            let start = source.as_mut_ptr().offset(self.index as isize);
71            let remaining = slice::from_raw_parts_mut(start, remaining_len);
72            ptr::drop_in_place(remaining);
73        }
74    }
75}