more refactor and dhtrecord multiple-open support

This commit is contained in:
Christien Rioux 2024-02-24 22:27:59 -05:00
parent c4c7b264aa
commit e262b0f777
19 changed files with 782 additions and 419 deletions

View file

@ -10,41 +10,20 @@ class AsyncTransformerCubit<T, S> extends Cubit<AsyncValue<T>> {
_subscription = input.stream.listen(_asyncTransform);
}
void _asyncTransform(AsyncValue<S> newInputState) {
// Use a singlefuture here to ensure we get dont lose any updates
// If the input stream gives us an update while we are
// still processing the last update, the most recent input state will
// be saved and processed eventually.
singleFuture(this, () async {
var newState = newInputState;
var done = false;
while (!done) {
// Emit the transformed state
try {
if (newState is AsyncLoading) {
return AsyncValue<T>.loading();
}
if (newState is AsyncError) {
final newStateError = newState as AsyncError<S>;
return AsyncValue<T>.error(
newStateError.error, newStateError.stackTrace);
}
_singleStateProcessor.updateState(newInputState, closure: (newState) async {
// Emit the transformed state
try {
if (newState is AsyncLoading<S>) {
emit(const AsyncValue.loading());
} else if (newState is AsyncError<S>) {
emit(AsyncValue.error(newState.error, newState.stackTrace));
} else {
final transformedState = await transform(newState.data!.value);
emit(transformedState);
} on Exception catch (e, st) {
emit(AsyncValue.error(e, st));
}
// See if there's another state change to process
final next = _nextInputState;
_nextInputState = null;
if (next != null) {
newState = next;
} else {
done = true;
}
} on Exception catch (e, st) {
emit(AsyncValue.error(e, st));
}
}, onBusy: () {
// Keep this state until we process again
_nextInputState = newInputState;
});
}
@ -56,7 +35,8 @@ class AsyncTransformerCubit<T, S> extends Cubit<AsyncValue<T>> {
}
Cubit<AsyncValue<S>> input;
AsyncValue<S>? _nextInputState;
final SingleStateProcessor<AsyncValue<S>> _singleStateProcessor =
SingleStateProcessor();
Future<AsyncValue<T>> Function(S) transform;
late final StreamSubscription<AsyncValue<S>> _subscription;
}

View file

@ -30,49 +30,29 @@ abstract mixin class StateFollower<S extends Object, K, V> {
Future<void> updateState(K key, V value);
void _updateFollow(S newInputState) {
// Use a singlefuture here to ensure we get dont lose any updates
// If the input stream gives us an update while we are
// still processing the last update, the most recent input state will
// be saved and processed eventually.
final newInputStateMap = getStateMap(newInputState);
singleFuture(this, () async {
var newStateMap = newInputStateMap;
var done = false;
while (!done) {
for (final k in _lastInputStateMap.keys) {
if (!newStateMap.containsKey(k)) {
// deleted
await removeFromState(k);
}
}
for (final newEntry in newStateMap.entries) {
final v = _lastInputStateMap.get(newEntry.key);
if (v == null || v != newEntry.value) {
// added or changed
await updateState(newEntry.key, newEntry.value);
}
}
// Keep this state map for the next time
_lastInputStateMap = newStateMap;
// See if there's another state change to process
final next = _nextInputStateMap;
_nextInputStateMap = null;
if (next != null) {
newStateMap = next;
} else {
done = true;
_singleStateProcessor.updateState(getStateMap(newInputState),
closure: (newStateMap) async {
for (final k in _lastInputStateMap.keys) {
if (!newStateMap.containsKey(k)) {
// deleted
await removeFromState(k);
}
}
}, onBusy: () {
// Keep this state until we process again
_nextInputStateMap = newInputStateMap;
for (final newEntry in newStateMap.entries) {
final v = _lastInputStateMap.get(newEntry.key);
if (v == null || v != newEntry.value) {
// added or changed
await updateState(newEntry.key, newEntry.value);
}
}
// Keep this state map for the next time
_lastInputStateMap = newStateMap;
});
}
late IMap<K, V> _lastInputStateMap;
IMap<K, V>? _nextInputStateMap;
final SingleStateProcessor<IMap<K, V>> _singleStateProcessor =
SingleStateProcessor();
late final StreamSubscription<S> _subscription;
}