/**
   * Returns a new {@link DecomposableMatchBuilder1} that further decomposes the first element of
   * this match builder.
   *
   * <p>The first element is decomposed to 0 elements.
   */
  public DecomposableMatchBuilder1<T, B> decomposeFirst(DecomposableMatchBuilder0<A> a) {
    Objects.requireNonNull(a);

    Map<Integer, DecomposableMatchBuilder> buildersByIndex =
        Maps.treeMapOf(extractedIndexes.first(), a);

    List<Matcher<Object>> matchers = getChildMatchers(buildersByIndex);

    NestedFieldExtractor<T> nestedFieldExtractor = getNestedFieldExtractor(buildersByIndex);

    return new DecomposableMatchBuilder1<>(
        matchers, extractedIndexes.second(), nestedFieldExtractor);
  }
  /**
   * Returns a new {@link DecomposableMatchBuilder0} that further decomposes the first and second
   * elements of this match builder.
   *
   * <p>The first element is decomposed to 0 elements, and the second element is decomposed to 0
   * elements.
   */
  public DecomposableMatchBuilder0<T> decomposeFirstAndSecond(
      DecomposableMatchBuilder0<A> first, DecomposableMatchBuilder0<B> second) {
    Objects.requireNonNull(first);
    Objects.requireNonNull(second);

    Map<Integer, DecomposableMatchBuilder> buildersByIndex =
        Maps.treeMapOf(extractedIndexes.first(), first, extractedIndexes.second(), second);

    List<Matcher<Object>> matchers = getChildMatchers(buildersByIndex);

    NestedFieldExtractor<T> nestedFieldExtractor = getNestedFieldExtractor(buildersByIndex);

    return new DecomposableMatchBuilder0<>(matchers, nestedFieldExtractor);
  }
  /**
   * Returns a new {@link DecomposableMatchBuilder2} that further decomposes the first element of
   * this match builder.
   *
   * <p>The first element is decomposed to 1 element.
   */
  public <A1> DecomposableMatchBuilder2<T, A1, B> decomposeFirst(
      DecomposableMatchBuilder1<A, A1> a) {
    Objects.requireNonNull(a);

    Map<Integer, DecomposableMatchBuilder> buildersByIndex =
        Maps.treeMapOf(extractedIndexes.first(), a);

    List<Matcher<Object>> matchers = getChildMatchers(buildersByIndex);

    Tuple2<Integer, Integer> newIndexes =
        Tuple2.of(this.extractedIndexes.first() + a.extractedIndex, this.extractedIndexes.second());

    NestedFieldExtractor<T> nestedFieldExtractor = getNestedFieldExtractor(buildersByIndex);

    return new DecomposableMatchBuilder2<>(matchers, newIndexes, nestedFieldExtractor);
  }
  /**
   * Returns a new {@link DecomposableMatchBuilder2} that further decomposes the second element of
   * this match builder.
   *
   * <p>The second element is decomposed to 2 elements.
   */
  public <B1, B2> DecomposableMatchBuilder3<T, A, B1, B2> decomposeSecond(
      DecomposableMatchBuilder2<B, B1, B2> b) {
    Objects.requireNonNull(b);

    Map<Integer, DecomposableMatchBuilder> buildersByIndex =
        Maps.treeMapOf(extractedIndexes.second(), b);

    List<Matcher<Object>> matchers = getChildMatchers(buildersByIndex);

    Tuple3<Integer, Integer, Integer> newIndexes =
        Tuple3.of(
            this.extractedIndexes.first(),
            this.extractedIndexes.second() + b.extractedIndexes.first(),
            this.extractedIndexes.second() + b.extractedIndexes.second());

    NestedFieldExtractor<T> nestedFieldExtractor = getNestedFieldExtractor(buildersByIndex);

    return new DecomposableMatchBuilder3<>(matchers, newIndexes, nestedFieldExtractor);
  }
  /**
   * Returns a new {@link DecomposableMatchBuilder0} that further decomposes the first and second
   * elements of this match builder.
   *
   * <p>The first element is decomposed to 1 element, and the second element is decomposed to 1
   * element.
   */
  public <A1, B1> DecomposableMatchBuilder2<T, A1, B1> decomposeFirstAndSecond(
      DecomposableMatchBuilder1<A, A1> a, DecomposableMatchBuilder1<B, B1> b) {
    Objects.requireNonNull(a);
    Objects.requireNonNull(b);

    Map<Integer, DecomposableMatchBuilder> buildersByIndex =
        Maps.treeMapOf(extractedIndexes.first(), a, extractedIndexes.second(), b);

    List<Matcher<Object>> matchers = getChildMatchers(buildersByIndex);

    // The number of matchers in 'first' tells the number of elements before the start of the
    // decomposition of the 'second'.
    Tuple2<Integer, Integer> newIndexes =
        Tuple2.of(
            extractedIndexes.first() + a.extractedIndex,
            a.fieldMatchers.size() - 1 + extractedIndexes.second() + b.extractedIndex);

    NestedFieldExtractor<T> nestedFieldExtractor = getNestedFieldExtractor(buildersByIndex);

    return new DecomposableMatchBuilder2<>(matchers, newIndexes, nestedFieldExtractor);
  }