run method

Future<R> run()

Implementation

Future<R> run() {
  if (_branches.isEmpty) {
    throw StateError('Select requires at least one branch');
  }

  final completer = Completer<R>();
  final cancels = <Canceller>[];
  var resolved = false;

  void registerCanceller(Canceller c) => cancels.add(c);

  void resolve(int idx, Object? tag, FutureOr<R> res) {
    if (resolved) return;
    resolved = true;

    for (final cancel in cancels) {
      try {
        cancel();
      } catch (_) {}
    }

    Future.sync(() => res).then((v) {
      if (!completer.isCompleted) completer.complete(v);
    }).catchError((Object e, StackTrace? st) {
      if (!completer.isCompleted) completer.completeError(e, st);
    });
  }

  // Apply optional guards
  final active = <SelectBranch<R>>[];
  for (final (b, guard) in _branches) {
    if (guard?.call() == false) continue;
    active.add(b);
  }

  if (active.isEmpty) {
    return Future.error(StateError('Select has no active branches'));
  }

  // Fairness: rotate starting offset unless ordered
  if (!_ordered && active.length > 1) {
    final n = active.length;
    final offset = DateTime.now().microsecondsSinceEpoch % n;
    if (offset != 0) {
      final rotated = <SelectBranch<R>>[
        ...active.skip(offset),
        ...active.take(offset),
      ];
      active
        ..clear()
        ..addAll(rotated);
    }
  }

  // Fast path sync
  for (var i = 0; i < active.length; i++) {
    final hit = active[i].attachSync(resolve: resolve, index: i);
    if (hit && resolved) return completer.future;
  }

  // Attach branches
  for (var i = 0; i < active.length; i++) {
    active[i].attach(
      resolve: resolve,
      registerCanceller: registerCanceller,
      index: i,
    );
    if (resolved) return completer.future;
  }

  return completer.future;
}