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

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

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

    Tuple3<Integer, Integer, Integer> newIndexes =
        Tuple3.of(
            this.extractedIndexes.first() + a.extractedIndexes.first(),
            this.extractedIndexes.first() + a.extractedIndexes.second(),
            a.fieldMatchers.size() - 1 + this.extractedIndexes.second());

    NestedFieldExtractor<T> nestedFieldExtractor = getNestedFieldExtractor(buildersByIndex);

    return new DecomposableMatchBuilder3<>(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 2
   * elements.
   */
  public <A1, B1, B2> DecomposableMatchBuilder3<T, A1, B1, B2> decomposeFirstAndSecond(
      DecomposableMatchBuilder1<A, A1> a, DecomposableMatchBuilder2<B, B1, B2> 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'.
    Tuple3<Integer, Integer, Integer> newIndexes =
        Tuple3.of(
            extractedIndexes.first() + a.extractedIndex,
            a.fieldMatchers.size() - 1 + extractedIndexes.second() + b.extractedIndexes.first(),
            a.fieldMatchers.size() - 1 + extractedIndexes.second() + b.extractedIndexes.second());

    NestedFieldExtractor<T> nestedFieldExtractor = getNestedFieldExtractor(buildersByIndex);

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