use crate::alloc::Allocator; use core::iter::TrustedLen; use core::ptr::{self}; use core::slice::{self}; use super::{IntoIter, SetLenOnDrop, Vec}; // Specialization trait used for Vec::extend pub(super) trait SpecExtend { fn spec_extend(&mut self, iter: I); } impl SpecExtend for Vec where I: Iterator, { default fn spec_extend(&mut self, iter: I) { self.extend_desugared(iter) } } impl SpecExtend for Vec where I: TrustedLen, { default fn spec_extend(&mut self, iterator: I) { // This is the case for a TrustedLen iterator. let (low, high) = iterator.size_hint(); if let Some(additional) = high { debug_assert_eq!( low, additional, "TrustedLen iterator's size hint is not exact: {:?}", (low, high) ); self.reserve(additional); unsafe { let mut ptr = self.as_mut_ptr().add(self.len()); let mut local_len = SetLenOnDrop::new(&mut self.len); iterator.for_each(move |element| { ptr::write(ptr, element); ptr = ptr.offset(1); // Since the loop executes user code which can panic we have to bump the pointer // after each step. // NB can't overflow since we would have had to alloc the address space local_len.increment_len(1); }); } } else { // Per TrustedLen contract a `None` upper bound means that the iterator length // truly exceeds usize::MAX, which would eventually lead to a capacity overflow anyway. // Since the other branch already panics eagerly (via `reserve()`) we do the same here. // This avoids additional codegen for a fallback code path which would eventually // panic anyway. panic!("capacity overflow"); } } } impl SpecExtend> for Vec { fn spec_extend(&mut self, mut iterator: IntoIter) { unsafe { self.append_elements(iterator.as_slice() as _); } iterator.forget_remaining_elements(); } } impl<'a, T: 'a, I, A: Allocator + 'a> SpecExtend<&'a T, I> for Vec where I: Iterator, T: Clone, { default fn spec_extend(&mut self, iterator: I) { self.spec_extend(iterator.cloned()) } } impl<'a, T: 'a, A: Allocator + 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec where T: Copy, { fn spec_extend(&mut self, iterator: slice::Iter<'a, T>) { let slice = iterator.as_slice(); unsafe { self.append_elements(slice) }; } }