diff --git a/src/lib.rs b/src/lib.rs index 11343b8..9e25a71 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -805,6 +805,21 @@ impl<'a, A: Array> Drop for Drain<'a, A> } } +struct ScopeExitGuard + where F: FnMut(&Data, &mut T) +{ + value: T, + data: Data, + f: F, +} + +impl Drop for ScopeExitGuard + where F: FnMut(&Data, &mut T) +{ + fn drop(&mut self) { + (self.f)(&self.data, &mut self.value) + } +} @@ -815,9 +830,26 @@ impl<'a, A: Array> Drop for Drain<'a, A> impl Extend for ArrayVec { fn extend>(&mut self, iter: T) { let take = self.capacity() - self.len(); - for elt in iter.into_iter().take(take) { - unsafe { - self.push_unchecked(elt); + unsafe { + let len = self.len(); + let mut ptr = self.as_mut_ptr().offset(len as isize); + // Keep the length in a separate variable, write it back on scope + // exit. To help the compiler with alias analysis and stuff. + // We update the length to handle panic in the iteration of the + // user's iterator, without dropping any elements on the floor. + let mut guard = ScopeExitGuard { + value: self, + data: len, + f: |&len, self_| { + unsafe { + self_.set_len(len) + } + } + }; + for elt in iter.into_iter().take(take) { + ptr::write(ptr, elt); + ptr = ptr.offset(1); + guard.data += 1; } } }