iteratorValueProvider<T> function

OffsetIteratorAsyncValue<T> Function(OffsetIterator<T> iterator) iteratorValueProvider<T>(
  1. ProviderRef<OffsetIteratorAsyncValue<T>> ref, {
  2. int initialDemand = 1,
})

Pulls an OffsetIterator on demand, and exposes the most recently pulled OffsetIteratorAsyncValue.

Implementation

OffsetIteratorAsyncValue<T> Function(
  OffsetIterator<T> iterator,
) iteratorValueProvider<T>(
  ProviderRef<OffsetIteratorAsyncValue<T>> ref, {
  int initialDemand = 1,
}) =>
    (iterator) {
      var canSetValue = false;
      var disposed = false;
      ref.onDispose(() => disposed = true);

      bool shouldPullMore(int remaining) =>
          !disposed && remaining > 0 && !iterator.drained;

      late Future<void> Function() maybePull;

      Future<void> doPull(int remaining) =>
          Future.value(iterator.pull()).then((value) {
            if (disposed) return null;

            final pullMore = shouldPullMore(remaining - 1);

            if (canSetValue) {
              ref.state = OffsetIteratorAsyncValue(
                value
                    .p(O.map(AsyncValue.data))
                    .p(O.alt(() => O.fromNullable(ref.state.value)))
                    .p(O.getOrElse(AsyncValue.loading)),
                iterator.hasMore(),
                pullMore,
                maybePull,
              );
            }

            return pullMore ? doPull(remaining - 1) : Future.value();
          }).catchError((err, stack) {
            if (disposed) return null;

            ref.state = OffsetIteratorAsyncValue(
              AsyncValue.error(err, stackTrace: stack),
              iterator.hasMore(),
              false,
              maybePull,
            );

            return null;
          });

      maybePull = () {
        if (!shouldPullMore(1)) return Future.value();
        return doPull(1);
      };

      if (shouldPullMore(initialDemand)) {
        doPull(initialDemand);
      }

      canSetValue = true;

      return OffsetIteratorAsyncValue(
        iterator.value.p(O.fold(
          () => const AsyncValue.loading(),
          (v) => AsyncValue.data(v),
        )),
        iterator.hasMore(),
        initialDemand > 0,
        maybePull,
      );
    };