selectMany<SubState, Result> method

StateStream<Result> selectMany<SubState, Result>(
  1. List<Selector<State, SubState>> selectors,
  2. List<Equality<SubState>?> subStateEquals,
  3. Result projector(
    1. List<SubState> subStates
    ), {
  4. Equality<Result>? equals,
})

Select many sub states and combine them by projector.

The returned Stream is a single-subscription Stream.

Implementation

StateStream<Result> selectMany<SubState, Result>(
  List<Selector<State, SubState>> selectors,
  List<Equality<SubState>?> subStateEquals,
  Result Function(List<SubState> subStates) projector, {
  Equality<Result>? equals,
}) {
  final length = selectors.length;
  if (length != subStateEquals.length) {
    throw ArgumentError(
        'selectors and subStateEquals should have same length');
  }

  if (length == 0) {
    throw ArgumentError('selectors and subStateEquals must be not empty');
  }
  if (length == 1) {
    throw ArgumentError(
        'selectors contains single element. Use select(selector) instead.');
  }

  selectors = selectors.toList(growable: false);
  subStateEquals = subStateEquals.toList(growable: false);

  if (length == 2) {
    return _select2Internal<State, SubState, SubState, Result>(
      this,
      selectors[0],
      selectors[1],
      (subState1, subState2) => projector([subState1, subState2]),
      subStateEquals[0],
      subStateEquals[1],
      equals,
    );
  }
  if (length == 3) {
    return _select3Internal<State, SubState, SubState, SubState, Result>(
      this,
      selectors[0],
      selectors[1],
      selectors[2],
      (subState1, subState2, subState3) =>
          projector([subState1, subState2, subState3]),
      subStateEquals[0],
      subStateEquals[1],
      subStateEquals[2],
      equals,
    );
  }
  if (length == 4) {
    return _select4Internal<State, SubState, SubState, SubState, SubState,
        Result>(
      this,
      selectors[0],
      selectors[1],
      selectors[2],
      selectors[3],
      (subState1, subState2, subState3, subState4) =>
          projector([subState1, subState2, subState3, subState4]),
      subStateEquals[0],
      subStateEquals[1],
      subStateEquals[2],
      subStateEquals[3],
      equals,
    );
  }

  List<SubState> selectSubStates(State state) =>
      selectors.map((s) => s(state)).toList(growable: false);

  final eqs = subStateEquals
      .map((e) => e ?? StateStream.defaultEquality)
      .toList(growable: false);

  late final indices = Iterable<int>.generate(length);
  bool subStatesEquals(List<SubState> previous, List<SubState> next) =>
      indices.every((i) => eqs[i](previous[i], next[i]));

  final currentSubStates = selectSubStates(value);

  return map(selectSubStates)
      .toStateStream(currentSubStates, equals: subStatesEquals)
      .map(projector)
      .toStateStream(projector(currentSubStates), equals: equals);
}