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}