Created
April 25, 2020 15:50
-
-
Save rhalff/5b809c2296e847f9a652c6a7cc009cd0 to your computer and use it in GitHub Desktop.
Equatable Annotation
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:collection/collection.dart'; | |
import 'package:meta/meta.dart' show immutable; | |
////////////////////////////////////////////// | |
// Public Api | |
////////////////////////////////////////////// | |
@immutable | |
@equatableProps | |
class SomeObject extends $_SomeObjectEquatable { | |
final int one; | |
final int two; | |
final int three; | |
final int four; | |
final int five; | |
const SomeObject({ | |
this.one, | |
this.two, | |
this.three, | |
this.four, | |
this.five, | |
}); | |
} | |
///////////////////////////////////////// | |
// Main test. | |
///////////////////////////////////////// | |
void main() { | |
var a = SomeObject(one: 1, two: 2, three: 3); | |
print(a.props); | |
var b = SomeObject(one: 1, two: 2, three: 3); | |
print(b.props); | |
var c = SomeObject(one: 2, two: 2, three: 3, four: 4, five: 5); | |
print(c.props); | |
var d = SomeObject(one: 2, two: 2, three: 3, four: 4, five: 5); | |
print(d.props); | |
print(a == b); | |
print(a == c); | |
print(b == c); | |
print(c == d); | |
} | |
/////////////////////////////////////////////////// | |
// Annotation | |
// (should also take some params to select props) | |
/////////////////////////////////////////////////// | |
class EquatableProps { | |
const EquatableProps(); | |
} | |
const equatableProps = EquatableProps(); | |
///////////////////////////////////////// | |
// simple_object.g.dart (generated code) | |
///////////////////////////////////////// | |
class $_SomeObjectEquatable extends $_EquatableBase { | |
const $_SomeObjectEquatable(); | |
List<Object> getProps(o) => [ | |
o.one, | |
o.two, | |
o.three, | |
o.four, | |
o.five, | |
]; | |
} | |
//////////////////////////////////// | |
// equatable_base.dart | |
//////////////////////////////////// | |
abstract class $_EquatableBase { | |
const $_EquatableBase(); | |
bool get stringify => false; | |
List<Object> getProps(dynamic o); // => []; | |
static bool compare(dynamic _this, Object other) => | |
identical(_this, other) || | |
other is $_EquatableBase && | |
_this.runtimeType == other.runtimeType && | |
equals(_this.props, other.props); | |
@override | |
String toString() => stringify | |
? mapPropsToString(runtimeType, getProps(this)) | |
: '$runtimeType'; | |
List<Object> get props => getProps(this); | |
@override | |
bool operator ==(Object other) => compare(this, other); | |
@override | |
int get hashCode => runtimeType.hashCode ^ mapPropsToHashCode(getProps(this)); | |
} | |
/////////////////////////////// | |
/// equatable_utils.dart | |
////////////////////////////// | |
/// Returns a `hashCode` for [props]. | |
int mapPropsToHashCode(Iterable props) => | |
_finish(props?.fold(0, _combine) ?? 0); | |
const DeepCollectionEquality _equality = DeepCollectionEquality(); | |
/// Determines whether [list1] and [list2] are equal. | |
bool equals(List list1, List list2) { | |
if (identical(list1, list2)) return true; | |
if (list1 == null || list2 == null) return false; | |
final length = list1.length; | |
if (length != list2.length) return false; | |
for (var i = 0; i < length; i++) { | |
final unit1 = list1[i]; | |
final unit2 = list2[i]; | |
if (unit1 is Iterable || unit1 is Map) { | |
if (!_equality.equals(unit1, unit2)) return false; | |
} else if (unit1?.runtimeType != unit2?.runtimeType) { | |
return false; | |
} else if (unit1 != unit2) { | |
return false; | |
} | |
} | |
return true; | |
} | |
/// Jenkins Hash Functions | |
/// https://en.wikipedia.org/wiki/Jenkins_hash_function | |
int _combine(int hash, dynamic object) { | |
if (object is Map) { | |
object.forEach((key, value) { | |
hash = hash ^ _combine(hash, [key, value]); | |
}); | |
return hash; | |
} | |
final objectHashCode = | |
object is Iterable ? mapPropsToHashCode(object) : object.hashCode; | |
hash = 0x1fffffff & (hash + objectHashCode); | |
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); | |
return hash ^ (hash >> 6); | |
} | |
int _finish(int hash) { | |
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); | |
hash = hash ^ (hash >> 11); | |
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); | |
} | |
/// Returns a string for [props]. | |
String mapPropsToString(Type runtimeType, List<Object> props) => | |
'$runtimeType${props?.map((prop) => prop?.toString() ?? '') ?? '()'}'; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment