diff --git a/src/vec.rs b/src/vec.rs index 5d7e3991..e8f82c9f 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -310,6 +310,66 @@ where } } +/// An iterator that moves out of an [`Vec`][`Vec`]. +/// +/// This struct is created by calling the `into_iter` method on [`Vec`][`Vec`]. +/// +/// [`Vec`]: (https://doc.rust-lang.org/std/vec/struct.Vec.html) +/// +pub struct IntoIter +where + N: ArrayLength, +{ + vec: Vec, + next: usize, +} + +impl Iterator for IntoIter +where + N: ArrayLength, +{ + type Item = T; + fn next(&mut self) -> Option { + if self.next < self.vec.len() { + let buffer = self.vec.buffer.as_slice(); + let item = unsafe {ptr::read(buffer.get_unchecked(self.next))}; + self.next += 1; + Some(item) + } else { + None + } + } +} + +impl Drop for IntoIter +where + N: ArrayLength, +{ + fn drop(&mut self) { + unsafe { + // Drop all the elements that have not been moved out of vec + ptr::drop_in_place(&mut self.vec[self.next..]); + // Prevent dropping of other elements + self.vec.len = 0; + } + } +} + +impl IntoIterator for Vec +where + N: ArrayLength, +{ + type Item = T; + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + IntoIter { + vec: self, + next: 0, + } + } +} + impl PartialEq> for Vec where N1: ArrayLength, @@ -433,26 +493,33 @@ mod tests { use consts::*; use Vec; + macro_rules! droppable { + () => ( + struct Droppable; + impl Droppable { + fn new() -> Self { + unsafe { + COUNT += 1; + } + Droppable + } + } + impl Drop for Droppable { + fn drop(&mut self) { + unsafe { + COUNT -= 1; + } + } + } + + static mut COUNT: i32 = 0; + ) + } + #[test] fn drop() { - struct Droppable; - impl Droppable { - fn new() -> Self { - unsafe { - COUNT += 1; - } - Droppable - } - } - impl Drop for Droppable { - fn drop(&mut self) { - unsafe { - COUNT -= 1; - } - } - } - static mut COUNT: i32 = 0; + droppable!(); { let mut v: Vec = Vec::new(); @@ -533,6 +600,62 @@ mod tests { assert_eq!(items.next(), None); } + #[test] + fn iter_move() { + let mut v: Vec = Vec::new(); + v.push(0).unwrap(); + v.push(1).unwrap(); + v.push(2).unwrap(); + v.push(3).unwrap(); + + let mut items = v.into_iter(); + + assert_eq!(items.next(), Some(0)); + assert_eq!(items.next(), Some(1)); + assert_eq!(items.next(), Some(2)); + assert_eq!(items.next(), Some(3)); + assert_eq!(items.next(), None); + } + + #[test] + fn iter_move_drop() { + + droppable!(); + + { + let mut vec: Vec = Vec::new(); + vec.push(Droppable::new()).ok().unwrap(); + vec.push(Droppable::new()).ok().unwrap(); + let mut items = vec.into_iter(); + // Move all + let _ = items.next(); + let _ = items.next(); + } + + assert_eq!(unsafe { COUNT }, 0); + + { + let mut vec: Vec = Vec::new(); + vec.push(Droppable::new()).ok().unwrap(); + vec.push(Droppable::new()).ok().unwrap(); + let _items = vec.into_iter(); + // Move none + } + + assert_eq!(unsafe { COUNT }, 0); + + { + let mut vec: Vec = Vec::new(); + vec.push(Droppable::new()).ok().unwrap(); + vec.push(Droppable::new()).ok().unwrap(); + let mut items = vec.into_iter(); + let _ = items.next(); // Move partly + } + + assert_eq!(unsafe { COUNT }, 0); + + } + #[test] fn push_and_pop() { let mut v: Vec = Vec::new();