Last active
March 29, 2023 15:16
-
-
Save roipeker/fe3a3f9ce7ab82794f69b2c919ae0b6a to your computer and use it in GitHub Desktop.
signal concept in dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/cupertino.dart'; | |
abstract class Entity { | |
late final onDispose = Signal0(); | |
late bool _disposed = false; | |
bool get disposed => _disposed; | |
@mustCallSuper | |
void dispose() { | |
if (_disposed) { | |
return; | |
} | |
onDispose.emit(); | |
onDispose.removeAll(); | |
onDispose.dispose(); | |
_disposed = true; | |
} | |
} | |
mixin EntityMixin implements Entity { | |
@override | |
final onDispose = Signal0(); | |
@override | |
bool _disposed = false; | |
@override | |
bool get disposed => _disposed; | |
@override | |
@mustCallSuper | |
void dispose() { | |
if (_disposed) { | |
return; | |
} | |
onDispose.emit(); | |
onDispose.dispose(); | |
_disposed = true; | |
} | |
} | |
class _Callback<T extends Function> { | |
final T callback; | |
final bool isOnce; | |
late final Entity? entity; | |
late bool disposed; | |
_Callback(this.callback, [this.isOnce = false, this.entity]) { | |
disposed = false; | |
} | |
/// hashcode | |
@override | |
int get hashCode => callback.hashCode; | |
/// equality | |
@override | |
bool operator ==(other) => | |
other is _Callback && | |
other.disposed == disposed && | |
other.isOnce == isOnce && | |
other.callback == callback && | |
other.entity?.hashCode == entity?.hashCode; | |
} | |
abstract class _BaseSignal { | |
// late final _listeners = <_Callback>{}; | |
Set<_Callback> _buildListeners() => <_Callback>{}; | |
late final _listeners = _buildListeners(); | |
void _dispatcher(void Function(Function callback) emitter) { | |
if (_disposed) { | |
throw StateError("Signal already disposed"); | |
} | |
final list = Set.of(_listeners); | |
for (var callback in list) { | |
if (!callback.disposed) { | |
if (callback.isOnce) { | |
_listeners.remove(callback); | |
} | |
emitter(callback.callback); | |
} | |
} | |
} | |
void _remove(Function callback) { | |
if (_disposed) { | |
throw StateError("Signal already disposed"); | |
} | |
_Callback? remove; | |
for (var c in Set.of(_listeners)) { | |
if (c.callback == callback) { | |
c.disposed = true; | |
remove = c; | |
} | |
} | |
if (remove != null) { | |
_listeners.remove(remove); | |
} | |
} | |
void _add<T extends Function>(T callback, [Entity? entity]) { | |
if (_disposed) { | |
throw StateError("Signal already disposed"); | |
} | |
_listeners.add(_Callback<T>(callback, false, entity)); | |
} | |
void _addOnce<T extends Function>(T callback, [Entity? entity]) { | |
if (_disposed) { | |
throw StateError("Signal already disposed"); | |
} | |
_listeners.add(_Callback<T>(callback, true, entity)); | |
} | |
void removeFrom(Entity entity) { | |
_Callback? remove; | |
for (var c in Set.of(_listeners)) { | |
if (c.entity == entity) { | |
c.disposed = true; | |
remove = c; | |
} | |
} | |
if (remove != null) { | |
_listeners.remove(remove); | |
} | |
} | |
void removeAll() { | |
_listeners.clear(); | |
} | |
bool _disposed = false; | |
void dispose() { | |
if (_disposed) { | |
return; | |
} | |
_listeners.clear(); | |
_disposed = true; | |
} | |
} | |
class Signal0 extends _BaseSignal { | |
/// dart analyzer complains... | |
// late final _listeners = <_Callback<VoidCallback>>{}; | |
@override | |
Set<_Callback<VoidCallback>> _buildListeners() => <_Callback<VoidCallback>>{}; | |
void add(VoidCallback callback, [Entity? entity]) { | |
_add(callback, entity); | |
} | |
void addOnce(VoidCallback callback, [Entity? entity]) { | |
_addOnce(callback, entity); | |
} | |
void remove(VoidCallback callback) { | |
_remove(callback); | |
} | |
void emit() { | |
_dispatcher((callback) { | |
callback(); | |
}); | |
} | |
} | |
class Signal1<T extends Object> extends _BaseSignal { | |
/// dart analyzer complains... | |
// late final _listeners = <_Callback<VoidCallback>>{}; | |
@override | |
Set<_Callback<ValueChanged<T>>> _buildListeners() => | |
<_Callback<ValueChanged<T>>>{}; | |
void add(ValueChanged<T> callback, [Entity? entity]) { | |
_add(callback, entity); | |
} | |
void addOnce(ValueChanged<T> callback, [Entity? entity]) { | |
_addOnce(callback, entity); | |
} | |
void remove(ValueChanged<T> callback) => _remove(callback); | |
void emit(T data) { | |
_dispatcher((callback) => callback(data)); | |
} | |
} | |
typedef ValueChanged2<T, J> = void Function(T, J); | |
class Signal2<T extends Object, J extends Object> extends _BaseSignal { | |
@override | |
Set<_Callback<ValueChanged2<T, J>>> _buildListeners() => | |
<_Callback<ValueChanged2<T, J>>>{}; | |
void add(ValueChanged2<T, J> callback, [Entity? entity]) { | |
_add(callback, entity); | |
} | |
void addOnce(ValueChanged2<T, J> callback, [Entity? entity]) { | |
_addOnce(callback, entity); | |
} | |
void remove(ValueChanged2<T, J> callback) => _remove(callback); | |
void emit(T data, J data2) => | |
_dispatcher((callback) => callback(data, data2)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment