@@ -56,29 +56,53 @@ public protocol BSONValue {
5656 var bsonType : BSONType { get }
5757
5858 /**
59- * Given the `DocumentStorage` backing a `Document`, appends this `BSONValue` to the end.
60- *
61- * - Parameters:
62- * - storage: A `DocumentStorage` to write to.
63- * - key: A `String`, the key under which to store the value.
64- *
65- * - Throws:
66- * - `RuntimeError.internalError` if the `DocumentStorage` would exceed the maximum size by encoding this
67- * key-value pair.
68- * - `UserError.logicError` if the value is an `Array` and it contains a non-`BSONValue` element.
69- */
59+ * Given the `DocumentStorage` backing a `Document`, appends this `BSONValue` to the end.
60+ *
61+ * - Parameters:
62+ * - storage: A `DocumentStorage` to write to.
63+ * - key: A `String`, the key under which to store the value.
64+ *
65+ * - Throws:
66+ * - `RuntimeError.internalError` if the `DocumentStorage` would exceed the maximum size by encoding this
67+ * key-value pair.
68+ * - `UserError.logicError` if the value is an `Array` and it contains a non-`BSONValue` element.
69+ */
7070 func encode( to storage: DocumentStorage , forKey key: String ) throws
7171
7272 /**
73- * Given a `DocumentIterator` known to have a next value of this type,
74- * initializes the value.
75- *
76- * - Throws: `UserError.logicError` if the current type of the `DocumentIterator` does not correspond to the
77- * associated type of this `BSONValue`.
78- */
73+ * Function to test equality with another `BSONValue`. This function tests for exact BSON equality.
74+ * This means that differing types with equivalent value are not equivalent.
75+ *
76+ * e.g.
77+ * 4.0 (Double) != 4 (Int)
78+ *
79+ * - Parameters:
80+ * - other: The right-hand-side `BSONValue` to compare.
81+ *
82+ * - Returns: `true` if `self` is equal to `rhs`, `false` otherwise.
83+ */
84+ func bsonEquals( _ other: BSONValue ? ) -> Bool
85+
86+ /**
87+ * Given a `DocumentIterator` known to have a next value of this type,
88+ * initializes the value.
89+ *
90+ * - Throws: `UserError.logicError` if the current type of the `DocumentIterator` does not correspond to the
91+ * associated type of this `BSONValue`.
92+ */
7993 static func from( iterator iter: DocumentIterator ) throws -> Self
8094}
8195
96+ extension BSONValue where Self: Equatable {
97+ /// Default implementation of `bsonEquals` for `BSONValue`s that conform to `Equatable`.
98+ public func bsonEquals( _ other: BSONValue ? ) -> Bool {
99+ guard let otherAsSelf = other as? Self else {
100+ return false
101+ }
102+ return self == otherAsSelf
103+ }
104+ }
105+
82106/// An extension of `Array` to represent the BSON array type.
83107extension Array : BSONValue {
84108 public var bsonType : BSONType { return . array }
@@ -130,6 +154,13 @@ extension Array: BSONValue {
130154 throw bsonTooLargeError ( value: self , forKey: key)
131155 }
132156 }
157+
158+ public func bsonEquals( _ other: BSONValue ? ) -> Bool {
159+ guard let otherArr = other as? [ BSONValue ] , let selfArr = self as? [ BSONValue ] else {
160+ return false
161+ }
162+ return self . count == otherArr. count && zip ( selfArr, otherArr) . allSatisfy { lhs, rhs in lhs. bsonEquals ( rhs) }
163+ }
133164}
134165
135166/// A struct to represent the BSON null type.
@@ -1082,8 +1113,6 @@ public struct BSONUndefined: BSONValue, Equatable, Codable {
10821113 }
10831114}
10841115
1085- // See https://github.com/realm/SwiftLint/issues/461
1086- // swiftlint:disable cyclomatic_complexity
10871116/**
10881117 * A helper function to test equality between two `BSONValue`s. This function tests for exact BSON equality.
10891118 * This means that differing types with equivalent value are not equivalent.
@@ -1100,33 +1129,9 @@ public struct BSONUndefined: BSONValue, Equatable, Codable {
11001129 *
11011130 * - Returns: `true` if `lhs` is equal to `rhs`, `false` otherwise.
11021131 */
1132+ @available ( * , deprecated, message: " Use lhs.bsonEquals(rhs) instead " )
11031133public func bsonEquals( _ lhs: BSONValue , _ rhs: BSONValue ) -> Bool {
1104- switch ( lhs, rhs) {
1105- case let ( l as Int , r as Int ) : return l == r
1106- case let ( l as Int32 , r as Int32 ) : return l == r
1107- case let ( l as Int64 , r as Int64 ) : return l == r
1108- case let ( l as Double , r as Double ) : return l == r
1109- case let ( l as Decimal128 , r as Decimal128 ) : return l == r
1110- case let ( l as Bool , r as Bool ) : return l == r
1111- case let ( l as String , r as String ) : return l == r
1112- case let ( l as RegularExpression , r as RegularExpression ) : return l == r
1113- case let ( l as Timestamp , r as Timestamp ) : return l == r
1114- case let ( l as Date , r as Date ) : return l == r
1115- case ( _ as MinKey , _ as MinKey ) : return true
1116- case ( _ as MaxKey , _ as MaxKey ) : return true
1117- case let ( l as ObjectId , r as ObjectId ) : return l == r
1118- case let ( l as CodeWithScope , r as CodeWithScope ) : return l == r
1119- case let ( l as Binary , r as Binary ) : return l == r
1120- case ( _ as BSONNull , _ as BSONNull ) : return true
1121- case let ( l as Document , r as Document ) : return l == r
1122- case let ( l as [ BSONValue ] , r as [ BSONValue ] ) : // TODO: SWIFT-242
1123- return l. count == r. count && zip ( l, r) . reduce ( true , { prev, next in prev && bsonEquals ( next. 0 , next. 1 ) } )
1124- case ( _ as [ Any ] , _ as [ Any ] ) : return false
1125- case let ( l as Symbol , r as Symbol ) : return l == r
1126- case let ( l as DBPointer , r as DBPointer ) : return l == r
1127- case ( _ as BSONUndefined , _ as BSONUndefined ) : return true
1128- default : return false
1129- }
1134+ return lhs. bsonEquals ( rhs)
11301135}
11311136
11321137/**
@@ -1139,6 +1144,7 @@ public func bsonEquals(_ lhs: BSONValue, _ rhs: BSONValue) -> Bool {
11391144 *
11401145 * - Returns: True if lhs is equal to rhs, false otherwise.
11411146 */
1147+ @available ( * , deprecated, message: " use lhs?.bsonEquals(rhs) instead " )
11421148public func bsonEquals( _ lhs: BSONValue ? , _ rhs: BSONValue ? ) -> Bool {
11431149 guard let left = lhs, let right = rhs else {
11441150 return lhs == nil && rhs == nil
0 commit comments