Skip to content

Instantly share code, notes, and snippets.

@roipeker
Last active March 29, 2023 15:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save roipeker/fe3a3f9ce7ab82794f69b2c919ae0b6a to your computer and use it in GitHub Desktop.
Save roipeker/fe3a3f9ce7ab82794f69b2c919ae0b6a to your computer and use it in GitHub Desktop.
signal concept in dart
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