Add `count` and `countWhere` extensions. (#196)

* Add `count` and `countWhere` extensions.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0e5a4af..d4263e8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
 ## 1.16.0
 
 * Use a stable sort algorithm in the `IterableExtension.sortedBy` method.
+* Add `count` and `countWhere` extensions on `Iterable`.
 
 ## 1.15.0
 
diff --git a/lib/src/empty_unmodifiable_set.dart b/lib/src/empty_unmodifiable_set.dart
index 882b6c8..725dfc0 100644
--- a/lib/src/empty_unmodifiable_set.dart
+++ b/lib/src/empty_unmodifiable_set.dart
@@ -4,7 +4,8 @@
 
 import 'dart:collection';
 
-import 'package:collection/collection.dart';
+import 'unmodifiable_wrappers.dart';
+import 'wrappers.dart';
 
 /// An unmodifiable, empty set which can be constant.
 class EmptyUnmodifiableSet<E> extends IterableBase<E>
diff --git a/lib/src/iterable_extensions.dart b/lib/src/iterable_extensions.dart
index b0bf0ad..1c82bc4 100644
--- a/lib/src/iterable_extensions.dart
+++ b/lib/src/iterable_extensions.dart
@@ -18,6 +18,46 @@
 /// iterables with specific element types include those of
 /// [IterableComparableExtension] and [IterableNullableExtension].
 extension IterableExtension<T> on Iterable<T> {
+  /// Counts the elements that are equal to [value].
+  ///
+  /// Returns the number of elements of this iterable
+  /// which are equal to [value] according to their `==`
+  /// operation.
+  ///
+  /// Example:
+  /// ```dart
+  /// var nullCount = maybeValues.count(null);
+  /// ```
+  ///
+  /// Equivalent to `.countWhere((e) => e == value)`.
+  int count(T value) {
+    var result = 0;
+    for (var element in this) {
+      if (element == value) result++;
+    }
+    return result;
+  }
+
+  /// Counts the elements that satisfy [test].
+  ///
+  /// Returns the number of elements of this iterable
+  /// which [test] returns `true` for.
+  /// The test must not modify this iterable.
+  ///
+  /// Example:
+  /// ```dart
+  /// var primeCount = integers.countWhere(isPrime);
+  /// ```
+  ///
+  /// Equivalent to `.where(test).length`.
+  int countWhere(bool Function(T element) test) {
+    var result = 0;
+    for (var element in this) {
+      if (test(element)) result++;
+    }
+    return result;
+  }
+
   /// Selects [count] elements at random from this iterable.
   ///
   /// The returned list contains [count] different elements of the iterable.
diff --git a/test/extensions_test.dart b/test/extensions_test.dart
index 0ea2d95..b32a0d4 100644
--- a/test/extensions_test.dart
+++ b/test/extensions_test.dart
@@ -10,6 +10,58 @@
 void main() {
   group('Iterable', () {
     group('of any', () {
+      group('.count', () {
+        test('empty', () {
+          // Empty iterable.
+          var iterable = [1, 2, 3, 2, 3, 2].where((_) => false);
+          expect(iterable.count(1), 0);
+          expect(<int>[].count(1), 0);
+        });
+        test('none', () {
+          var iterable = [1, 2, 3, 4, 2, 3, 2].where((_) => true);
+          expect(iterable.count(0), 0);
+          expect(<int>[4].count(0), 0);
+        });
+        test('single', () {
+          var iterable = [1, 2, 3, 4, 2, 3, 2].where((_) => true);
+          expect(iterable.count(4), 1);
+          expect(<int>[4].count(4), 1);
+        });
+        test('multiple', () {
+          var iterable = [1, 2, 3, 4, 2, 3, 2].where((_) => true);
+          expect(iterable.count(2), 3);
+          expect(iterable.count(3), 2);
+          expect(<int>[2, 3, 2].count(2), 2);
+        });
+        test('uses element equality', () {
+          var iterable = <Object>[EqTo(2), 2];
+          expect(iterable.count(2), 2);
+        });
+      });
+      group('.countWhere', () {
+        test('empty', () {
+          // Empty iterable.
+          var iterable = [1, 2, 3, 2, 3, 2].where((_) => false);
+          expect(iterable.countWhere((_) => true), 0);
+          expect(<int>[].countWhere((_) => true), 0);
+        });
+        test('none', () {
+          var iterable = [1, 2, 3, 4, 2, 3, 2].where((_) => true);
+          expect(iterable.countWhere((_) => false), 0);
+          expect(<int>[4].countWhere((_) => false), 0);
+        });
+        test('single', () {
+          var iterable = [1, 2, 3, 4, 2, 3, 2].where((_) => true);
+          expect(iterable.countWhere((x) => x == 4), 1);
+          expect(<int>[4].countWhere((x) => x == 4), 1);
+        });
+        test('multiple', () {
+          var iterable = [1, 2, 3, 4, 2, 3, 2].where((_) => true);
+          expect(iterable.countWhere((x) => x == 2), 3);
+          expect(iterable.countWhere((x) => x == 3), 2);
+          expect(<int>[2, 3, 2].countWhere((x) => x == 2), 2);
+        });
+      });
       group('.whereNot', () {
         test('empty', () {
           expect(iterable([]).whereNot(unreachable), isEmpty);
@@ -1703,3 +1755,14 @@
 
 /// Tests an integer for being odd.
 bool isOdd(int x) => x.isOdd;
+
+/// Objects which claim to be equal to other values.
+class EqTo {
+  final Object? value;
+  EqTo(this.value);
+  @override
+  int get hashCode => value.hashCode;
+  @override
+  bool operator ==(Object other) =>
+      value == (other is EqTo ? other.value : other);
+}