deepEquals function

bool deepEquals(
  1. dynamic a,
  2. 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;
}