deepEquals function
bool
deepEquals(
- dynamic a,
- dynamic b
)
Implementation
bool deepEquals(dynamic a, dynamic b) {
// Fast identical reference or both null
if (identical(a, b)) return true;
if (a == null || b == null) return a == b;
// Normalize numeric types (int vs double) treating 1 and 1.0 as equal
bool numEquals(dynamic x, dynamic y) {
if (x is num && y is num) {
// Avoid precision issues by comparing as double with a tiny tolerance
final dx = x.toDouble();
final dy = y.toDouble();
return (dx - dy).abs() < 1e-9;
}
return false;
}
// DateTime equality by moment (accounts for timezone differences via UTC)
if (a is DateTime && b is DateTime) {
return a.toUtc().isAtSameMomentAs(b.toUtc());
}
// Numeric cross-type equality
if (numEquals(a, b)) return true;
// Realm collections or generic Iterables may not be List; normalize
if (a is Iterable &&
b is Iterable &&
a.runtimeType != List &&
b.runtimeType != List) {
a = a.toList();
b = b.toList();
}
// Map deep compare
if (a is Map && b is Map) {
if (a.length != b.length) return false;
for (final k in a.keys) {
if (!b.containsKey(k)) return false;
if (!deepEquals(a[k], b[k])) return false;
}
// Also ensure b doesn't have extra keys (length check already done)
return true;
}
// List / Iterable ordered deep compare
if (a is List && b is List) {
if (a.length != b.length) return false;
for (var i = 0; i < a.length; i++) {
if (!deepEquals(a[i], b[i])) return false;
}
return true;
}
// Fallback to == (covers primitives & objects implementing ==)
return a == b;
}