Skip to content
306 changes: 165 additions & 141 deletions library/core/src/iter/traits/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -461,182 +461,165 @@ impl Extend<()> for () {

macro_rules! spec_tuple_impl {
(
[$($params_:tt)*],
(
$ty_name:ident, $var_name:ident, $extend_ty_name: ident,
$trait_name:ident, $default_fn_name:ident, $cnt:tt
$params:tt, $SpecTupleExtendN:tt, $default_extend_tuple_n:tt
),
$($remainder:tt,)*
) => {
spec_tuple_impl!(
$trait_name,
$default_fn_name,
$SpecTupleExtendN,
$default_extend_tuple_n,
$($params_,)*
$params
);
spec_tuple_impl!(
[$($params_)* $params],
$($remainder,)*
);
};
( [$($params_:tt)*], ) => { };
(
$SpecTupleExtendN:tt, $default_extend_tuple_n:tt,
$params:tt
) => {
spec_tuple_impl!(
$SpecTupleExtendN,
$default_extend_tuple_n,
#special_case_1_tuple
#[doc(fake_variadic)]
#[doc = "This trait is implemented for tuples up to twelve items long. The `impl`s for \
1- and 3- through 12-ary tuples were stabilized after 2-tuples, in \
1.85.0."]
=> ($ty_name, $var_name, $extend_ty_name, $cnt),
=> $params,
);
};
(
(
$ty_name:ident, $var_name:ident, $extend_ty_name: ident,
$trait_name:ident, $default_fn_name:ident, $cnt:tt
),
$(
(
$ty_names:ident, $var_names:ident, $extend_ty_names:ident,
$trait_names:ident, $default_fn_names:ident, $cnts:tt
),
)*
$SpecTupleExtendN:tt, $default_extend_tuple_n:tt,
$($params:tt),+
) => {
spec_tuple_impl!(
$(
(
$ty_names, $var_names, $extend_ty_names,
$trait_names, $default_fn_names, $cnts
),
)*
);
spec_tuple_impl!(
$trait_name,
$default_fn_name,
$SpecTupleExtendN,
$default_extend_tuple_n,
#normal_case
#[doc(hidden)]
=> (
$ty_name, $var_name, $extend_ty_name, $cnt
),
$(
(
$ty_names, $var_names, $extend_ty_names, $cnts
),
)*
=> $($params,)+
);
};
(
$trait_name:ident, $default_fn_name:ident, #[$meta:meta]
$SpecTupleExtendN:tt, $default_extend_tuple_n:tt,
#$skip_specialization_trait_for_1_tuple:tt
#[$meta:meta]
$(#[$doctext:meta])? => $(
(
$ty_names:ident, $var_names:ident, $extend_ty_names:ident, $cnts:tt
$T:ident, $var_names:ident, $ExtendT:ident, $cnt:tt
),
)*
) => {
#[$meta]
$(#[$doctext])?
#[stable(feature = "extend_for_tuple", since = "1.56.0")]
impl<$($ty_names,)* $($extend_ty_names,)*> Extend<($($ty_names,)*)> for ($($extend_ty_names,)*)
impl<$($T,)* $($ExtendT,)*> Extend<($($T,)*)> for ($($ExtendT,)*)
where
$($extend_ty_names: Extend<$ty_names>,)*
$($ExtendT: Extend<$T>,)*
{
/// Allows to `extend` a tuple of collections that also implement `Extend`.
///
/// See also: [`Iterator::unzip`]
///
/// # Examples
/// ```
/// // Example given for a 2-tuple, but 1- through 12-tuples are supported
/// let mut tuple = (vec![0], vec![1]);
/// tuple.extend([(2, 3), (4, 5), (6, 7)]);
/// assert_eq!(tuple.0, [0, 2, 4, 6]);
/// assert_eq!(tuple.1, [1, 3, 5, 7]);
///
/// // also allows for arbitrarily nested tuples as elements
/// let mut nested_tuple = (vec![1], (vec![2], vec![3]));
/// nested_tuple.extend([(4, (5, 6)), (7, (8, 9))]);
///
/// let (a, (b, c)) = nested_tuple;
/// assert_eq!(a, [1, 4, 7]);
/// assert_eq!(b, [2, 5, 8]);
/// assert_eq!(c, [3, 6, 9]);
/// ```
fn extend<T: IntoIterator<Item = ($($ty_names,)*)>>(&mut self, into_iter: T) {
let ($($var_names,)*) = self;
let iter = into_iter.into_iter();
$trait_name::extend(iter, $($var_names,)*);
}
spec_tuple_impl!(
#$skip_specialization_trait_for_1_tuple

fn extend_one(&mut self, item: ($($ty_names,)*)) {
$(self.$cnts.extend_one(item.$cnts);)*
fn extend<I: IntoIterator<Item = ($($T,)*)>>(&mut self, into_iter: I) {
let ($($var_names,)*) = self;
let iter = into_iter.into_iter();
$SpecTupleExtendN::extend(iter, $($var_names,)*);
}
);

fn extend_one(&mut self, item: ($($T,)*)) {
$(self.$cnt.extend_one(item.$cnt);)*
}

fn extend_reserve(&mut self, additional: usize) {
$(self.$cnts.extend_reserve(additional);)*
$(self.$cnt.extend_reserve(additional);)*
}

unsafe fn extend_one_unchecked(&mut self, item: ($($ty_names,)*)) {
unsafe fn extend_one_unchecked(&mut self, item: ($($T,)*)) {
// SAFETY: Those are our safety preconditions, and we correctly forward `extend_reserve`.
unsafe {
$(self.$cnts.extend_one_unchecked(item.$cnts);)*
$(self.$cnt.extend_one_unchecked(item.$cnt);)*
}
}
}

trait $trait_name<$($ty_names),*> {
fn extend(self, $($var_names: &mut $ty_names,)*);
}
spec_tuple_impl!(
#$skip_specialization_trait_for_1_tuple

fn $default_fn_name<$($ty_names,)* $($extend_ty_names,)*>(
iter: impl Iterator<Item = ($($ty_names,)*)>,
$($var_names: &mut $extend_ty_names,)*
) where
$($extend_ty_names: Extend<$ty_names>,)*
{
fn extend<'a, $($ty_names,)*>(
$($var_names: &'a mut impl Extend<$ty_names>,)*
) -> impl FnMut((), ($($ty_names,)*)) + 'a {
#[allow(non_snake_case)]
move |(), ($($extend_ty_names,)*)| {
$($var_names.extend_one($extend_ty_names);)*
}
trait $SpecTupleExtendN<$($T),*> {
fn extend(self, $($var_names: &mut $T,)*);
}

let (lower_bound, _) = iter.size_hint();
if lower_bound > 0 {
$($var_names.extend_reserve(lower_bound);)*
}
fn $default_extend_tuple_n<$($T,)* $($ExtendT,)*>(
iter: impl Iterator<Item = ($($T,)*)>,
$($var_names: &mut $ExtendT,)*
) where
$($ExtendT: Extend<$T>,)*
{
fn extend<'a, $($T,)*>(
$($var_names: &'a mut impl Extend<$T>,)*
) -> impl FnMut((), ($($T,)*)) + 'a {
move |(), item| {
$($var_names.extend_one(item.$cnt);)*
}
}

iter.fold((), extend($($var_names,)*));
}
let (lower_bound, _) = iter.size_hint();
if lower_bound > 0 {
$($var_names.extend_reserve(lower_bound);)*
}

impl<$($ty_names,)* $($extend_ty_names,)* Iter> $trait_name<$($extend_ty_names),*> for Iter
where
$($extend_ty_names: Extend<$ty_names>,)*
Iter: Iterator<Item = ($($ty_names,)*)>,
{
default fn extend(self, $($var_names: &mut $extend_ty_names),*) {
$default_fn_name(self, $($var_names),*);
iter.fold((), extend($($var_names,)*));
}
}

impl<$($ty_names,)* $($extend_ty_names,)* Iter> $trait_name<$($extend_ty_names),*> for Iter
where
$($extend_ty_names: Extend<$ty_names>,)*
Iter: TrustedLen<Item = ($($ty_names,)*)>,
{
fn extend(self, $($var_names: &mut $extend_ty_names,)*) {
fn extend<'a, $($ty_names,)*>(
$($var_names: &'a mut impl Extend<$ty_names>,)*
) -> impl FnMut((), ($($ty_names,)*)) + 'a {
#[allow(non_snake_case)]
// SAFETY: We reserve enough space for the `size_hint`, and the iterator is
// `TrustedLen` so its `size_hint` is exact.
move |(), ($($extend_ty_names,)*)| unsafe {
$($var_names.extend_one_unchecked($extend_ty_names);)*
}
impl<$($T,)* $($ExtendT,)* Iter> $SpecTupleExtendN<$($ExtendT),*> for Iter
where
$($ExtendT: Extend<$T>,)*
Iter: Iterator<Item = ($($T,)*)>,
{
default fn extend(self, $($var_names: &mut $ExtendT),*) {
$default_extend_tuple_n(self, $($var_names),*);
}
}

let (lower_bound, upper_bound) = self.size_hint();
impl<$($T,)* $($ExtendT,)* Iter> $SpecTupleExtendN<$($ExtendT),*> for Iter
where
$($ExtendT: Extend<$T>,)*
Iter: TrustedLen<Item = ($($T,)*)>,
{
fn extend(self, $($var_names: &mut $ExtendT,)*) {
fn extend<'a, $($T,)*>(
$($var_names: &'a mut impl Extend<$T>,)*
) -> impl FnMut((), ($($T,)*)) + 'a {
// SAFETY: We reserve enough space for the `size_hint`, and the iterator is
// `TrustedLen` so its `size_hint` is exact.
move |(), item| unsafe {
$($var_names.extend_one_unchecked(item.$cnt);)*
}
}

if upper_bound.is_none() {
// We cannot reserve more than `usize::MAX` items, and this is likely to go out of memory anyway.
$default_fn_name(self, $($var_names,)*);
return;
}
let (lower_bound, upper_bound) = self.size_hint();

if lower_bound > 0 {
$($var_names.extend_reserve(lower_bound);)*
}
if upper_bound.is_none() {
// We cannot reserve more than `usize::MAX` items, and this is likely to go out of memory anyway.
$default_extend_tuple_n(self, $($var_names,)*);
return;
}

if lower_bound > 0 {
$($var_names.extend_reserve(lower_bound);)*
}

self.fold((), extend($($var_names,)*));
self.fold((), extend($($var_names,)*));
}
}
}
);

/// This implementation turns an iterator of tuples into a tuple of types which implement
/// [`Default`] and [`Extend`].
Expand All @@ -661,32 +644,73 @@ macro_rules! spec_tuple_impl {
#[$meta]
$(#[$doctext])?
#[stable(feature = "from_iterator_for_tuple", since = "1.79.0")]
impl<$($ty_names,)* $($extend_ty_names,)*> FromIterator<($($extend_ty_names,)*)> for ($($ty_names,)*)
impl<$($T,)* $($ExtendT,)*> FromIterator<($($ExtendT,)*)> for ($($T,)*)
where
$($ty_names: Default + Extend<$extend_ty_names>,)*
$($T: Default + Extend<$ExtendT>,)*
{
fn from_iter<Iter: IntoIterator<Item = ($($extend_ty_names,)*)>>(iter: Iter) -> Self {
let mut res = <($($ty_names,)*)>::default();
fn from_iter<Iter: IntoIterator<Item = ($($ExtendT,)*)>>(iter: Iter) -> Self {
let mut res = <($($T,)*)>::default();
res.extend(iter);

res
}
}

};
(
#special_case_1_tuple
fn $($t:tt)*
) => {
/// Allows to `extend` a tuple of collections that also implement `Extend`.
///
/// See also: [`Iterator::unzip`]
///
/// # Examples
/// ```
/// // Example given for a 2-tuple, but 1- through 12-tuples are supported
/// let mut tuple = (vec![0], vec![1]);
/// tuple.extend([(2, 3), (4, 5), (6, 7)]);
/// assert_eq!(tuple.0, [0, 2, 4, 6]);
/// assert_eq!(tuple.1, [1, 3, 5, 7]);
///
/// // also allows for arbitrarily nested tuples as elements
/// let mut nested_tuple = (vec![1], (vec![2], vec![3]));
/// nested_tuple.extend([(4, (5, 6)), (7, (8, 9))]);
///
/// let (a, (b, c)) = nested_tuple;
/// assert_eq!(a, [1, 4, 7]);
/// assert_eq!(b, [2, 5, 8]);
/// assert_eq!(c, [3, 6, 9]);
/// ```
fn extend<I: IntoIterator<Item = (T,)>>(&mut self, iter: I) {
self.0.extend(iter.into_iter().map(|(a,)| a));
}
};
(
#special_case_1_tuple
$($t:tt)*
) => {
// no specialization traits
};
(
#normal_case
$($t:tt)*
) => {
$($t)*
};
}

spec_tuple_impl!(
(L, l, EL, TraitL, default_extend_tuple_l, 11),
(K, k, EK, TraitK, default_extend_tuple_k, 10),
(J, j, EJ, TraitJ, default_extend_tuple_j, 9),
(I, i, EI, TraitI, default_extend_tuple_i, 8),
(H, h, EH, TraitH, default_extend_tuple_h, 7),
(G, g, EG, TraitG, default_extend_tuple_g, 6),
(F, f, EF, TraitF, default_extend_tuple_f, 5),
(E, e, EE, TraitE, default_extend_tuple_e, 4),
(D, d, ED, TraitD, default_extend_tuple_d, 3),
(C, c, EC, TraitC, default_extend_tuple_c, 2),
(B, b, EB, TraitB, default_extend_tuple_b, 1),
(A, a, EA, TraitA, default_extend_tuple_a, 0),
[],
((T, t, ExtendT, 0), @, @),
((U, u, ExtendU, 1), SpecTupleExtend2, default_extend_tuple_2),
((V, v, ExtendV, 2), SpecTupleExtend3, default_extend_tuple_3),
((W, w, ExtendW, 3), SpecTupleExtend4, default_extend_tuple_4),
((X, x, ExtendX, 4), SpecTupleExtend5, default_extend_tuple_5),
((Y, y, ExtendY, 5), SpecTupleExtend6, default_extend_tuple_6),
((Z, z, ExtendZ, 6), SpecTupleExtend7, default_extend_tuple_7),
((A, a, ExtendA, 7), SpecTupleExtend8, default_extend_tuple_8),
((B, b, ExtendB, 8), SpecTupleExtend9, default_extend_tuple_9),
((C, c, ExtendC, 9), SpecTupleExtend10, default_extend_tuple_10),
((D, d, ExtendD, 10), SpecTupleExtend11, default_extend_tuple_11),
((E, e, ExtendE, 11), SpecTupleExtend12, default_extend_tuple_12),
);
Loading
Loading