until<TSuper extends Object, TSub extends TSuper> method

Resolvable<TSub> until<TSuper extends Object, TSub extends TSuper>({
  1. Entity groupEntity = const DefaultEntity(),
  2. bool traverse = true,
})

Waits until a dependency of type TSuper or its subtype TSub is registered. TSuper should typically be the most general type expected.

Implementation

Resolvable<TSub> until<TSuper extends Object, TSub extends TSuper>({
  Entity groupEntity = const DefaultEntity(),
  bool traverse = true,
}) {
  final typeEntity = TypeEntity(TSuper);
  final g = groupEntity.preferOverDefault(focusGroup);
  // Already-registered fast path: bail out with the resolved Resolvable.
  if (get<TSuper>(groupEntity: g, traverse: traverse)
      case Some(value: final r)) {
    return r.transf();
  }
  final completer = switch (getSyncOrNone<ReservedSafeCompleter<TSuper>>(
    groupEntity: g,
    traverse: traverse,
  )) {
    Some(value: final c) => c,
    None() => _seedCompleter<TSuper>(typeEntity, g, traverse),
  };
  return completer
      .resolvable()
      .then((_) {
        unregister<ReservedSafeCompleter<TSuper>>(
          groupEntity: g,
          traverse: traverse,
        ).end();
        // The completer was resolved because `_maybeFinish` saw a matching
        // register — so `get<TSuper>` should find it. If a concurrent
        // unregister wiped the slot between completion and now, surface an
        // Err Resolvable instead of throwing — callers chained off the
        // outer `.flatten().transf()` then see a normal failure.
        return switch (get<TSuper>(groupEntity: g, traverse: traverse)) {
          Some(value: final r) => r,
          None() => Sync<TSuper>.err(
              Err('until<$TSuper>: completer resolved but post-resolution '
                  'lookup returned None (raced with unregister).'),
            ),
        };
      })
      .flatten()
      .transf();
}