concurrency work in prep for speeding things up

refactor splash screen to process initialization in a better way
more async tools for async cubit constructors
greatly improved StateMapFollower class
This commit is contained in:
Christien Rioux 2024-04-03 21:55:49 -04:00
parent 8da1dc7d32
commit 9bb20f4dd2
47 changed files with 886 additions and 579 deletions

View file

@ -3,7 +3,9 @@ library;
export 'src/async_tag_lock.dart';
export 'src/async_value.dart';
export 'src/delayed_wait_set.dart';
export 'src/serial_future.dart';
export 'src/single_future.dart';
export 'src/single_state_processor.dart';
export 'src/single_stateless_processor.dart';
export 'src/wait_set.dart';

View file

@ -0,0 +1,18 @@
class DelayedWaitSet {
DelayedWaitSet();
void add(Future<void> Function() closure) {
_closures.add(closure);
}
Future<void> call() async {
final futures = _closures.map((c) => c()).toList();
_closures = [];
if (futures.isEmpty) {
return;
}
await futures.wait;
}
List<Future<void> Function()> _closures = [];
}

View file

@ -4,14 +4,14 @@ import 'async_tag_lock.dart';
AsyncTagLock<Object> _keys = AsyncTagLock();
// Process a single future at a time per tag
//
// The closure function is called to produce the future that is to be executed.
// If a future with a particular tag is still executing, the onBusy callback
// is called.
// When a tagged singleFuture finishes executing, the onDone callback is called.
// If an unhandled exception happens in the closure future, the onError callback
// is called.
/// Process a single future at a time per tag
///
/// The closure function is called to produce the future that is to be executed.
/// If a future with a particular tag is still executing, the onBusy callback
/// is called.
/// When a tagged singleFuture finishes executing, the onDone callback is called.
/// If an unhandled exception happens in the closure future, the onError callback
/// is called.
void singleFuture<T>(Object tag, Future<T> Function() closure,
{void Function()? onBusy,
void Function(T)? onDone,
@ -40,3 +40,6 @@ void singleFuture<T>(Object tag, Future<T> Function() closure,
}
}());
}
Future<void> singleFuturePause(Object tag) async => _keys.lockTag(tag);
void singleFutureResume(Object tag) => _keys.unlockTag(tag);

View file

@ -22,15 +22,19 @@ class SingleStateProcessor<State> {
singleFuture(this, () async {
var newState = newInputState;
var newClosure = closure;
var done = false;
while (!done) {
await closure(newState);
await newClosure(newState);
// See if there's another state change to process
final next = _nextState;
final nextState = _nextState;
final nextClosure = _nextClosure;
_nextState = null;
if (next != null) {
newState = next;
_nextClosure = null;
if (nextState != null) {
newState = nextState;
newClosure = nextClosure!;
} else {
done = true;
}
@ -38,8 +42,26 @@ class SingleStateProcessor<State> {
}, onBusy: () {
// Keep this state until we process again
_nextState = newInputState;
_nextClosure = closure;
});
}
Future<void> pause() => singleFuturePause(this);
Future<void> resume() async {
// Process any next state before resuming the singlefuture
try {
final nextState = _nextState;
final nextClosure = _nextClosure;
_nextState = null;
_nextClosure = null;
if (nextState != null) {
await nextClosure!(nextState);
}
} finally {
singleFutureResume(this);
}
}
State? _nextState;
Future<void> Function(State)? _nextClosure;
}

View file

@ -0,0 +1,18 @@
class WaitSet {
WaitSet();
void add(Future<void> Function() closure) {
_futures.add(Future.delayed(Duration.zero, closure));
}
Future<void> call() async {
final futures = _futures;
_futures = [];
if (futures.isEmpty) {
return;
}
await futures.wait;
}
List<Future<void>> _futures = [];
}