run method
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;
}