class RuntimeCommandRegistry { final Set _handles = {}; final Map> _handlesById = {}; final Map> _handlesByGroup = {}; final Map> _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> index, String? key, RuntimeCommandHandle handle, ) { if (key == null) { return; } index.putIfAbsent(key, () => {}).add(handle); } void _cancelAll(Set? 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> 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 _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(); } }