synchronizeStreamIterators<T, K extends Comparable<K>> function

Future<PageSyncStat> synchronizeStreamIterators<T, K extends Comparable<K>>(
  1. StreamIterator<T> source,
  2. StreamIterator<T> target,
  3. K keyFn(
    1. T item
    ),
  4. {Future<bool> onlySource(
    1. T item
    )?,
  5. Future<bool> onlyTarget(
    1. T item
    )?,
  6. Future<bool> matched(
    1. T source,
    2. T target
    )?}
)

Synchronize two StreamIterators that are ordered with their keys in ascending order.

Implementation

Future<PageSyncStat> synchronizeStreamIterators<T, K extends Comparable<K>>(
  StreamIterator<T> source,
  StreamIterator<T> target,
  K Function(T item) keyFn, {
  Future<bool> Function(T item)? onlySource,
  Future<bool> Function(T item)? onlyTarget,
  Future<bool> Function(T source, T target)? matched,
}) async {
  var onlySourceCount = 0;
  var onlyTargetCount = 0;
  var matchingKeyCount = 0;
  var synchronizedCount = 0;

  T? targetItem;
  K? targetKey;
  var hasTarget = true;
  Future moveTarget() async {
    if (hasTarget) {
      if (await target.moveNext()) {
        targetItem = target.current;
        targetKey = keyFn(targetItem as T);
      } else {
        targetItem = null;
        targetKey = null;
        hasTarget = false;
      }
    }
  }

  await moveTarget();

  while (await source.moveNext()) {
    final sourceItem = source.current;
    final sourceKey = keyFn(sourceItem);
    while (hasTarget && sourceKey.compareTo(targetKey!) > 0) {
      final s = onlyTarget == null ? null : await onlyTarget(targetItem as T);
      onlyTargetCount++;
      if (s == true) {
        synchronizedCount++;
      }
      await moveTarget();
    }
    if (hasTarget && sourceKey.compareTo(targetKey!) == 0) {
      final s =
          matched == null ? null : await matched(sourceItem, targetItem as T);
      matchingKeyCount++;
      if (s == true) {
        synchronizedCount++;
      }
      await moveTarget();
      continue;
    }
    final s = onlySource == null ? null : await onlySource(sourceItem);
    onlySourceCount++;
    if (s == true) {
      synchronizedCount++;
    }
  }
  while (hasTarget) {
    final s = onlyTarget == null ? null : await onlyTarget(targetItem as T);
    onlyTargetCount++;
    if (s == true) {
      synchronizedCount++;
    }
    await moveTarget();
  }
  return PageSyncStat(
    onlySourceCount: onlySourceCount,
    onlyTargetCount: onlyTargetCount,
    matchingKeyCount: matchingKeyCount,
    synchronizedCount: synchronizedCount,
  );
}