147 lines
3.4 KiB
Dart
147 lines
3.4 KiB
Dart
class RuntimeCommandRegistry {
|
|
final Set<RuntimeCommandHandle> _handles = {};
|
|
final Map<String, Set<RuntimeCommandHandle>> _handlesById = {};
|
|
final Map<String, Set<RuntimeCommandHandle>> _handlesByGroup = {};
|
|
final Map<String, Set<RuntimeCommandHandle>> _handlesByScope = {};
|
|
bool _disposed = false;
|
|
|
|
int get activeHandleCount => _handles.length;
|
|
|
|
RuntimeCommandHandle create({String? id, String? group, String? scope}) {
|
|
if (_disposed) {
|
|
throw StateError('RuntimeCommandRegistry has been disposed');
|
|
}
|
|
|
|
late final RuntimeCommandHandle handle;
|
|
handle = RuntimeCommandHandle._(
|
|
id: id,
|
|
group: group,
|
|
scope: scope,
|
|
onComplete: _unregister,
|
|
);
|
|
_handles.add(handle);
|
|
_index(_handlesById, id, handle);
|
|
_index(_handlesByGroup, group, handle);
|
|
_index(_handlesByScope, scope, handle);
|
|
return handle;
|
|
}
|
|
|
|
void cancelId(String id) {
|
|
_cancelAll(_handlesById[id]);
|
|
}
|
|
|
|
void cancelGroup(String group) {
|
|
_cancelAll(_handlesByGroup[group]);
|
|
}
|
|
|
|
void cancelScope(String scope) {
|
|
_cancelAll(_handlesByScope[scope]);
|
|
}
|
|
|
|
void dispose() {
|
|
if (_disposed) {
|
|
return;
|
|
}
|
|
_disposed = true;
|
|
_cancelAll(_handles);
|
|
_handles.clear();
|
|
_handlesById.clear();
|
|
_handlesByGroup.clear();
|
|
_handlesByScope.clear();
|
|
}
|
|
|
|
void _index(
|
|
Map<String, Set<RuntimeCommandHandle>> index,
|
|
String? key,
|
|
RuntimeCommandHandle handle,
|
|
) {
|
|
if (key == null) {
|
|
return;
|
|
}
|
|
index.putIfAbsent(key, () => {}).add(handle);
|
|
}
|
|
|
|
void _cancelAll(Set<RuntimeCommandHandle>? handles) {
|
|
final snapshot = handles?.toList(growable: false) ?? const [];
|
|
for (final handle in snapshot) {
|
|
handle.cancel();
|
|
}
|
|
}
|
|
|
|
void _unregister(RuntimeCommandHandle handle) {
|
|
_handles.remove(handle);
|
|
_unindex(_handlesById, handle.id, handle);
|
|
_unindex(_handlesByGroup, handle.group, handle);
|
|
_unindex(_handlesByScope, handle.scope, handle);
|
|
}
|
|
|
|
void _unindex(
|
|
Map<String, Set<RuntimeCommandHandle>> index,
|
|
String? key,
|
|
RuntimeCommandHandle handle,
|
|
) {
|
|
if (key == null) {
|
|
return;
|
|
}
|
|
final handles = index[key];
|
|
handles?.remove(handle);
|
|
if (handles != null && handles.isEmpty) {
|
|
index.remove(key);
|
|
}
|
|
}
|
|
}
|
|
|
|
class RuntimeCommandHandle {
|
|
RuntimeCommandHandle._({
|
|
required this.id,
|
|
required this.group,
|
|
required this.scope,
|
|
required void Function(RuntimeCommandHandle handle) onComplete,
|
|
}) : _onComplete = onComplete;
|
|
|
|
final String? id;
|
|
final String? group;
|
|
final String? scope;
|
|
final void Function(RuntimeCommandHandle handle) _onComplete;
|
|
final List<void Function()> _cancelCallbacks = [];
|
|
bool _cancelled = false;
|
|
bool _completed = false;
|
|
|
|
bool get isCancelled => _cancelled;
|
|
|
|
bool get isCompleted => _completed;
|
|
|
|
void addCancelCallback(void Function() callback) {
|
|
if (_cancelled) {
|
|
callback();
|
|
return;
|
|
}
|
|
if (_completed) {
|
|
return;
|
|
}
|
|
_cancelCallbacks.add(callback);
|
|
}
|
|
|
|
void complete() {
|
|
if (_completed) {
|
|
return;
|
|
}
|
|
_completed = true;
|
|
_cancelCallbacks.clear();
|
|
_onComplete(this);
|
|
}
|
|
|
|
void cancel() {
|
|
if (_cancelled || _completed) {
|
|
return;
|
|
}
|
|
_cancelled = true;
|
|
final callbacks = _cancelCallbacks.toList(growable: false);
|
|
_cancelCallbacks.clear();
|
|
for (final callback in callbacks) {
|
|
callback();
|
|
}
|
|
complete();
|
|
}
|
|
}
|