Skip to content

Commit ebd7d2b

Browse files
shahngitbot
authored and
gitbot
committed
Add Extend impls for tuples of arity 1 through 12
1 parent 7e1238c commit ebd7d2b

File tree

1 file changed

+138
-110
lines changed

1 file changed

+138
-110
lines changed

core/src/iter/traits/collect.rs

+138-110
Original file line numberDiff line numberDiff line change
@@ -492,131 +492,159 @@ impl Extend<()> for () {
492492
fn extend_one(&mut self, _item: ()) {}
493493
}
494494

495-
#[stable(feature = "extend_for_tuple", since = "1.56.0")]
496-
impl<A, B, ExtendA, ExtendB> Extend<(A, B)> for (ExtendA, ExtendB)
497-
where
498-
ExtendA: Extend<A>,
499-
ExtendB: Extend<B>,
500-
{
501-
/// Allows to `extend` a tuple of collections that also implement `Extend`.
502-
///
503-
/// See also: [`Iterator::unzip`]
504-
///
505-
/// # Examples
506-
/// ```
507-
/// let mut tuple = (vec![0], vec![1]);
508-
/// tuple.extend([(2, 3), (4, 5), (6, 7)]);
509-
/// assert_eq!(tuple.0, [0, 2, 4, 6]);
510-
/// assert_eq!(tuple.1, [1, 3, 5, 7]);
511-
///
512-
/// // also allows for arbitrarily nested tuples as elements
513-
/// let mut nested_tuple = (vec![1], (vec![2], vec![3]));
514-
/// nested_tuple.extend([(4, (5, 6)), (7, (8, 9))]);
515-
///
516-
/// let (a, (b, c)) = nested_tuple;
517-
/// assert_eq!(a, [1, 4, 7]);
518-
/// assert_eq!(b, [2, 5, 8]);
519-
/// assert_eq!(c, [3, 6, 9]);
520-
/// ```
521-
fn extend<T: IntoIterator<Item = (A, B)>>(&mut self, into_iter: T) {
522-
let (a, b) = self;
523-
let iter = into_iter.into_iter();
524-
SpecTupleExtend::extend(iter, a, b);
525-
}
495+
macro_rules! spec_tuple_impl {
496+
( ($ty_name:ident, $var_name:ident, $extend_ty_name: ident, $trait_name:ident, $default_fn_name:ident, $cnt:tt), ) => {
497+
spec_tuple_impl!($trait_name, $default_fn_name, #[stable(feature = "extend_for_more_tuples", since = "CURRENT_RUSTC_VERSION")] #[doc(fake_variadic)] #[doc = "This trait is implemented for tuples up to twelve items long."] => ($ty_name, $var_name, $extend_ty_name, $cnt),);
498+
};
499+
// Special case (A, B) as this was stabilized earlier
500+
( ($ty_name:ident, $var_name:ident, $extend_ty_name: ident, $trait_name:ident, $default_fn_name:ident, $cnt:tt),
501+
($ty_names:ident, $var_names:ident, $extend_ty_names: ident, $trait_names:ident, $default_fn_names:ident, $cnts:tt),) => {
526502

527-
fn extend_one(&mut self, item: (A, B)) {
528-
self.0.extend_one(item.0);
529-
self.1.extend_one(item.1);
530-
}
503+
spec_tuple_impl!(($ty_names, $var_names, $extend_ty_names, $trait_names, $default_fn_names, $cnts),);
504+
spec_tuple_impl!($trait_name, $default_fn_name, #[stable(feature = "extend_for_tuple", since = "1.56.0")] => ($ty_name, $var_name, $extend_ty_name, $cnt), ($ty_names, $var_names, $extend_ty_names, $cnts),);
505+
};
506+
( ($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),)*) => {
531507

532-
fn extend_reserve(&mut self, additional: usize) {
533-
self.0.extend_reserve(additional);
534-
self.1.extend_reserve(additional);
535-
}
508+
spec_tuple_impl!($(($ty_names, $var_names, $extend_ty_names, $trait_names, $default_fn_names, $cnts),)*);
509+
spec_tuple_impl!($trait_name, $default_fn_name, #[stable(feature = "extend_for_more_tuples", since = "CURRENT_RUSTC_VERSION")] #[doc(hidden)] => ($ty_name, $var_name, $extend_ty_name, $cnt), $(($ty_names, $var_names, $extend_ty_names, $cnts),)*);
510+
};
511+
($trait_name:ident, $default_fn_name:ident, #[$stable:meta] $(#[$meta:meta] $(#[$doctext:meta])?)? => $(($ty_names:ident, $var_names:ident, $extend_ty_names:ident, $cnts:tt),)*) => {
512+
$(#[$meta]
513+
$(#[$doctext])?
514+
)?
515+
#[$stable]
516+
impl<$($ty_names,)* $($extend_ty_names,)*> Extend<($($ty_names,)*)> for ($($extend_ty_names,)*)
517+
where
518+
$($extend_ty_names: Extend<$ty_names>,)*
519+
{
520+
/// Allows to `extend` a tuple of collections that also implement `Extend`.
521+
///
522+
/// See also: [`Iterator::unzip`]
523+
///
524+
/// # Examples
525+
/// ```
526+
/// // Example given for a 2-tuple, but 1- through 12-tuples are supported
527+
/// let mut tuple = (vec![0], vec![1]);
528+
/// tuple.extend([(2, 3), (4, 5), (6, 7)]);
529+
/// assert_eq!(tuple.0, [0, 2, 4, 6]);
530+
/// assert_eq!(tuple.1, [1, 3, 5, 7]);
531+
///
532+
/// // also allows for arbitrarily nested tuples as elements
533+
/// let mut nested_tuple = (vec![1], (vec![2], vec![3]));
534+
/// nested_tuple.extend([(4, (5, 6)), (7, (8, 9))]);
535+
///
536+
/// let (a, (b, c)) = nested_tuple;
537+
/// assert_eq!(a, [1, 4, 7]);
538+
/// assert_eq!(b, [2, 5, 8]);
539+
/// assert_eq!(c, [3, 6, 9]);
540+
/// ```
541+
fn extend<T: IntoIterator<Item = ($($ty_names,)*)>>(&mut self, into_iter: T) {
542+
let ($($var_names,)*) = self;
543+
let iter = into_iter.into_iter();
544+
$trait_name::extend(iter, $($var_names,)*);
545+
}
536546

537-
unsafe fn extend_one_unchecked(&mut self, item: (A, B)) {
538-
// SAFETY: Those are our safety preconditions, and we correctly forward `extend_reserve`.
539-
unsafe {
540-
self.0.extend_one_unchecked(item.0);
541-
self.1.extend_one_unchecked(item.1);
542-
}
543-
}
544-
}
547+
fn extend_one(&mut self, item: ($($ty_names,)*)) {
548+
$(self.$cnts.extend_one(item.$cnts);)*
549+
}
545550

546-
fn default_extend_tuple<A, B, ExtendA, ExtendB>(
547-
iter: impl Iterator<Item = (A, B)>,
548-
a: &mut ExtendA,
549-
b: &mut ExtendB,
550-
) where
551-
ExtendA: Extend<A>,
552-
ExtendB: Extend<B>,
553-
{
554-
fn extend<'a, A, B>(
555-
a: &'a mut impl Extend<A>,
556-
b: &'a mut impl Extend<B>,
557-
) -> impl FnMut((), (A, B)) + 'a {
558-
move |(), (t, u)| {
559-
a.extend_one(t);
560-
b.extend_one(u);
551+
fn extend_reserve(&mut self, additional: usize) {
552+
$(self.$cnts.extend_reserve(additional);)*
553+
}
554+
555+
unsafe fn extend_one_unchecked(&mut self, item: ($($ty_names,)*)) {
556+
// SAFETY: Those are our safety preconditions, and we correctly forward `extend_reserve`.
557+
unsafe {
558+
$(self.$cnts.extend_one_unchecked(item.$cnts);)*
559+
}
560+
}
561561
}
562-
}
563562

564-
let (lower_bound, _) = iter.size_hint();
565-
if lower_bound > 0 {
566-
a.extend_reserve(lower_bound);
567-
b.extend_reserve(lower_bound);
568-
}
563+
trait $trait_name<$($ty_names),*> {
564+
fn extend(self, $($var_names: &mut $ty_names,)*);
565+
}
569566

570-
iter.fold((), extend(a, b));
571-
}
567+
fn $default_fn_name<$($ty_names,)* $($extend_ty_names,)*>(
568+
iter: impl Iterator<Item = ($($ty_names,)*)>,
569+
$($var_names: &mut $extend_ty_names,)*
570+
) where
571+
$($extend_ty_names: Extend<$ty_names>,)*
572+
{
573+
fn extend<'a, $($ty_names,)*>(
574+
$($var_names: &'a mut impl Extend<$ty_names>,)*
575+
) -> impl FnMut((), ($($ty_names,)*)) + 'a {
576+
#[allow(non_snake_case)]
577+
move |(), ($($extend_ty_names,)*)| {
578+
$($var_names.extend_one($extend_ty_names);)*
579+
}
580+
}
572581

573-
trait SpecTupleExtend<A, B> {
574-
fn extend(self, a: &mut A, b: &mut B);
575-
}
582+
let (lower_bound, _) = iter.size_hint();
583+
if lower_bound > 0 {
584+
$($var_names.extend_reserve(lower_bound);)*
585+
}
576586

577-
impl<A, B, ExtendA, ExtendB, Iter> SpecTupleExtend<ExtendA, ExtendB> for Iter
578-
where
579-
ExtendA: Extend<A>,
580-
ExtendB: Extend<B>,
581-
Iter: Iterator<Item = (A, B)>,
582-
{
583-
default fn extend(self, a: &mut ExtendA, b: &mut ExtendB) {
584-
default_extend_tuple(self, a, b);
585-
}
586-
}
587+
iter.fold((), extend($($var_names,)*));
588+
}
587589

588-
impl<A, B, ExtendA, ExtendB, Iter> SpecTupleExtend<ExtendA, ExtendB> for Iter
589-
where
590-
ExtendA: Extend<A>,
591-
ExtendB: Extend<B>,
592-
Iter: TrustedLen<Item = (A, B)>,
593-
{
594-
fn extend(self, a: &mut ExtendA, b: &mut ExtendB) {
595-
fn extend<'a, A, B>(
596-
a: &'a mut impl Extend<A>,
597-
b: &'a mut impl Extend<B>,
598-
) -> impl FnMut((), (A, B)) + 'a {
599-
// SAFETY: We reserve enough space for the `size_hint`, and the iterator is `TrustedLen`
600-
// so its `size_hint` is exact.
601-
move |(), (t, u)| unsafe {
602-
a.extend_one_unchecked(t);
603-
b.extend_one_unchecked(u);
590+
impl<$($ty_names,)* $($extend_ty_names,)* Iter> $trait_name<$($extend_ty_names),*> for Iter
591+
where
592+
$($extend_ty_names: Extend<$ty_names>,)*
593+
Iter: Iterator<Item = ($($ty_names,)*)>,
594+
{
595+
default fn extend(self, $($var_names: &mut $extend_ty_names),*) {
596+
$default_fn_name(self, $($var_names),*);
604597
}
605598
}
606599

607-
let (lower_bound, upper_bound) = self.size_hint();
600+
impl<$($ty_names,)* $($extend_ty_names,)* Iter> $trait_name<$($extend_ty_names),*> for Iter
601+
where
602+
$($extend_ty_names: Extend<$ty_names>,)*
603+
Iter: TrustedLen<Item = ($($ty_names,)*)>,
604+
{
605+
fn extend(self, $($var_names: &mut $extend_ty_names,)*) {
606+
fn extend<'a, $($ty_names,)*>(
607+
$($var_names: &'a mut impl Extend<$ty_names>,)*
608+
) -> impl FnMut((), ($($ty_names,)*)) + 'a {
609+
#[allow(non_snake_case)]
610+
// SAFETY: We reserve enough space for the `size_hint`, and the iterator is `TrustedLen`
611+
// so its `size_hint` is exact.
612+
move |(), ($($extend_ty_names,)*)| unsafe {
613+
$($var_names.extend_one_unchecked($extend_ty_names);)*
614+
}
615+
}
608616

609-
if upper_bound.is_none() {
610-
// We cannot reserve more than `usize::MAX` items, and this is likely to go out of memory anyway.
611-
default_extend_tuple(self, a, b);
612-
return;
613-
}
617+
let (lower_bound, upper_bound) = self.size_hint();
614618

615-
if lower_bound > 0 {
616-
a.extend_reserve(lower_bound);
617-
b.extend_reserve(lower_bound);
618-
}
619+
if upper_bound.is_none() {
620+
// We cannot reserve more than `usize::MAX` items, and this is likely to go out of memory anyway.
621+
$default_fn_name(self, $($var_names,)*);
622+
return;
623+
}
619624

620-
self.fold((), extend(a, b));
625+
if lower_bound > 0 {
626+
$($var_names.extend_reserve(lower_bound);)*
627+
}
628+
629+
self.fold((), extend($($var_names,)*));
630+
}
621631
}
632+
633+
};
622634
}
635+
636+
spec_tuple_impl!(
637+
(M, m, EM, TraitM, default_extend_tuple_m, 12),
638+
(L, l, EL, TraitL, default_extend_tuple_l, 11),
639+
(K, k, EK, TraitK, default_extend_tuple_k, 10),
640+
(J, j, EJ, TraitJ, default_extend_tuple_j, 9),
641+
(I, i, EI, TraitI, default_extend_tuple_i, 8),
642+
(H, h, EH, TraitH, default_extend_tuple_h, 7),
643+
(G, g, EG, TraitG, default_extend_tuple_g, 6),
644+
(F, f, EF, TraitF, default_extend_tuple_f, 5),
645+
(E, e, EE, TraitE, default_extend_tuple_e, 4),
646+
(D, d, ED, TraitD, default_extend_tuple_d, 3),
647+
(C, c, EC, TraitC, default_extend_tuple_c, 2),
648+
(B, b, EB, TraitB, default_extend_tuple_b, 1),
649+
(A, a, EA, TraitA, default_extend_tuple_a, 0),
650+
);

0 commit comments

Comments
 (0)