dependsOn<S extends HypenGeneratedData, I, O> method

O dependsOn<S extends HypenGeneratedData, I, O>(
  1. Object key,
  2. S build(), {
  3. required O select(
    1. S origin,
    2. I snapshot
    ),
  4. Stream<O> pipe(
    1. Stream<O> source
    )?,
  5. Object? actionKey,
})

Implementation

O dependsOn<S extends HypenGeneratedData, I, O>(
  Object key,
  S Function() build, {
  required O Function(S origin, I snapshot) select,
  Stream<O> Function(Stream<O> source)? pipe,
  Object? actionKey,
}) {
  final data = _addDependency(key, build, actionKey: actionKey);

  if (!isBuilding) {
    return select(data, data.$snapshot() as I);
  }

  final currentLinearIndex = linearDependencyIndex;
  final currentNestedIndex = _resetOrIncNestedDepIdx();
  final Object? prevRootKey = _changeRootkey(key);
  final rootKey = _rootKey;

  linearDependencyIndex++;
  if (_isNewSelection(rootKey, currentNestedIndex) &&
      depStreams.length <= currentLinearIndex) {
    final source = data.$stream as HypenStream<I>;

    final selectedStream = source.map<O>((s) {
      // setup selected item key
      _rootKey = rootKey;
      nestedDependencyIndex = currentNestedIndex;
      isBuilding = true;
      final ret = select(data, s);
      isBuilding = false;
      return ret;
    });
    final piped = (pipe ?? (s) => s)(selectedStream);
    depStreams.add(
      piped.listen((s) {
        preventAccess[rootKey]![currentNestedIndex] = null;
        _changeSelectedData(rootKey, currentNestedIndex, s);
        _markParentsNeedRebuild(rootKey, currentNestedIndex);
        _resetSelf();
      }),
    );
  }

  O? ret;
  try {
    if (_isNewSelection(rootKey, currentNestedIndex)) {
      // increase the cache size
      final needsRebuild = this.needsRebuild[rootKey] ??= [];
      final selectedData = this.selectedData[rootKey] ??= [];
      final preventAccess = this.preventAccess[rootKey] ??= [];

      needsRebuild.add(true);
      selectedData.add(null);
      preventAccess.add(null);
    }

    if (preventAccess[rootKey]?[currentLinearIndex] case Object e) {
      throw e;
    }

    if (_needsRebuild(rootKey, currentNestedIndex)) {
      ret = select(data, data.$snapshot() as I);
      _changeSelectedData(rootKey, currentNestedIndex, ret);
    } else {
      ret = selectedData[rootKey]![currentNestedIndex] as O;
    }
    _resetRootKey(prevRootKey);
  } catch (e) {
    preventAccess[rootKey]![currentNestedIndex] = e;
    _initializeFlags();
    rethrow;
  }

  return ret as O;
}