Skip to content

Commit 8d5eb8b

Browse files
authored
SWIFT-268 Store bson_oid_t in ObjectId rather than creating one each time we need it (#238)
This also removes init(fromString:) and init?(ifValid:) from ObjectId and replaces it with a single init?(_: String)
1 parent 18145aa commit 8d5eb8b

File tree

6 files changed

+86
-82
lines changed

6 files changed

+86
-82
lines changed

Sources/MongoSwift/APM.swift

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,10 @@ public struct ServerDescriptionChangedEvent: MongoEvent, InitializableFromOpaque
163163
fileprivate init(_ event: OpaquePointer) {
164164
self.connectionId = ConnectionId(mongoc_apm_server_changed_get_host(event))
165165
var oid = bson_oid_t()
166-
mongoc_apm_server_changed_get_topology_id(event, &oid)
167-
self.topologyId = ObjectId(fromPointer: &oid)
166+
withUnsafeMutablePointer(to: &oid) { oidPtr in
167+
mongoc_apm_server_changed_get_topology_id(event, oidPtr)
168+
}
169+
self.topologyId = ObjectId(bsonOid: oid)
168170
self.previousDescription = ServerDescription(mongoc_apm_server_changed_get_previous_description(event))
169171
self.newDescription = ServerDescription(mongoc_apm_server_changed_get_new_description(event))
170172
}
@@ -188,8 +190,10 @@ public struct ServerOpeningEvent: MongoEvent, InitializableFromOpaquePointer {
188190
fileprivate init(_ event: OpaquePointer) {
189191
self.connectionId = ConnectionId(mongoc_apm_server_opening_get_host(event))
190192
var oid = bson_oid_t()
191-
mongoc_apm_server_opening_get_topology_id(event, &oid)
192-
self.topologyId = ObjectId(fromPointer: &oid)
193+
withUnsafeMutablePointer(to: &oid) { oidPtr in
194+
mongoc_apm_server_opening_get_topology_id(event, oidPtr)
195+
}
196+
self.topologyId = ObjectId(bsonOid: oid)
193197
}
194198
}
195199

@@ -211,8 +215,10 @@ public struct ServerClosedEvent: MongoEvent, InitializableFromOpaquePointer {
211215
fileprivate init(_ event: OpaquePointer) {
212216
self.connectionId = ConnectionId(mongoc_apm_server_closed_get_host(event))
213217
var oid = bson_oid_t()
214-
mongoc_apm_server_closed_get_topology_id(event, &oid)
215-
self.topologyId = ObjectId(fromPointer: &oid)
218+
withUnsafeMutablePointer(to: &oid) { oidPtr in
219+
mongoc_apm_server_closed_get_topology_id(event, oidPtr)
220+
}
221+
self.topologyId = ObjectId(bsonOid: oid)
216222
}
217223
}
218224

@@ -236,8 +242,10 @@ public struct TopologyDescriptionChangedEvent: MongoEvent, InitializableFromOpaq
236242
/// Initializes a TopologyDescriptionChangedEvent from an OpaquePointer to a mongoc_apm_topology_changed_t
237243
fileprivate init(_ event: OpaquePointer) {
238244
var oid = bson_oid_t()
239-
mongoc_apm_topology_changed_get_topology_id(event, &oid)
240-
self.topologyId = ObjectId(fromPointer: &oid)
245+
withUnsafeMutablePointer(to: &oid) { oidPtr in
246+
mongoc_apm_topology_changed_get_topology_id(event, oidPtr)
247+
}
248+
self.topologyId = ObjectId(bsonOid: oid)
241249
self.previousDescription = TopologyDescription(mongoc_apm_topology_changed_get_previous_description(event))
242250
self.newDescription = TopologyDescription(mongoc_apm_topology_changed_get_new_description(event))
243251
}
@@ -257,8 +265,10 @@ public struct TopologyOpeningEvent: MongoEvent, InitializableFromOpaquePointer {
257265
/// Initializes a TopologyOpeningEvent from an OpaquePointer to a mongoc_apm_topology_opening_t
258266
fileprivate init(_ event: OpaquePointer) {
259267
var oid = bson_oid_t()
260-
mongoc_apm_topology_opening_get_topology_id(event, &oid)
261-
self.topologyId = ObjectId(fromPointer: &oid)
268+
withUnsafeMutablePointer(to: &oid) { oidPtr in
269+
mongoc_apm_topology_opening_get_topology_id(event, oidPtr)
270+
}
271+
self.topologyId = ObjectId(bsonOid: oid)
262272
}
263273
}
264274

@@ -276,8 +286,10 @@ public struct TopologyClosedEvent: MongoEvent, InitializableFromOpaquePointer {
276286
/// Initializes a TopologyClosedEvent from an OpaquePointer to a mongoc_apm_topology_closed_t
277287
fileprivate init(_ event: OpaquePointer) {
278288
var oid = bson_oid_t()
279-
mongoc_apm_topology_closed_get_topology_id(event, &oid)
280-
self.topologyId = ObjectId(fromPointer: &oid)
289+
withUnsafeMutablePointer(to: &oid) { oidPtr in
290+
mongoc_apm_topology_closed_get_topology_id(event, oidPtr)
291+
}
292+
self.topologyId = ObjectId(bsonOid: oid)
281293
}
282294
}
283295

Sources/MongoSwift/BSON/BSONValue.swift

Lines changed: 45 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -463,9 +463,10 @@ public struct DBPointer: BSONValue, Codable, Equatable {
463463
}
464464

465465
public func encode(to storage: DocumentStorage, forKey key: String) throws {
466-
var oid = try ObjectId.toLibBSONType(self.id.oid) // TODO: use the stored bson_oid_t (SWIFT-268)
467-
guard bson_append_dbpointer(storage.pointer, key, Int32(key.utf8.count), self.ref, &oid) else {
468-
throw bsonTooLargeError(value: self, forKey: key)
466+
try withUnsafePointer(to: id.oid) { oidPtr in
467+
guard bson_append_dbpointer(storage.pointer, key, Int32(key.utf8.count), self.ref, oidPtr) else {
468+
throw bsonTooLargeError(value: self, forKey: key)
469+
}
469470
}
470471
}
471472

@@ -490,7 +491,7 @@ public struct DBPointer: BSONValue, Codable, Equatable {
490491
throw wrongIterTypeError(iter, expected: DBPointer.self)
491492
}
492493

493-
return DBPointer(ref: String(cString: collectionP), id: ObjectId(fromPointer: oidP))
494+
return DBPointer(ref: String(cString: collectionP), id: ObjectId(bsonOid: oidP.pointee))
494495
}
495496
}
496497
}
@@ -870,36 +871,47 @@ public struct ObjectId: BSONValue, Equatable, CustomStringConvertible, Codable {
870871
public var bsonType: BSONType { return .objectId }
871872

872873
/// This `ObjectId`'s data represented as a `String`.
873-
public let oid: String
874+
public var hex: String {
875+
var str = Data(count: 25)
876+
return str.withUnsafeMutableBytes { (rawBuffer: UnsafeMutablePointer<Int8>) in
877+
withUnsafePointer(to: self.oid) { oidPtr in
878+
bson_oid_to_string(oidPtr, rawBuffer)
879+
}
880+
return String(cString: rawBuffer)
881+
}
882+
}
874883

875884
/// The timestamp used to create this `ObjectId`
876-
public let timestamp: UInt32
885+
public var timestamp: UInt32 {
886+
return withUnsafePointer(to: self.oid) { oidPtr in UInt32(bson_oid_get_time_t(oidPtr)) }
887+
}
877888

878-
/// Initializes a new `ObjectId`.
879-
public init() {
880-
var oid_t = bson_oid_t()
881-
bson_oid_init(&oid_t, nil)
882-
self.init(fromPointer: &oid_t)
889+
public var description: String {
890+
return self.hex
883891
}
884892

885-
/// Initializes an `ObjectId` from the provided `String`. Assumes that the given string is a valid ObjectId.
886-
/// - SeeAlso: https://github.com/mongodb/specifications/blob/master/source/objectid.rst
887-
public init(fromString oid: String) {
893+
internal let oid: bson_oid_t
894+
895+
/// Initializes a new `ObjectId`.
896+
public init() {
897+
var oid = bson_oid_t()
898+
bson_oid_init(&oid, nil)
888899
self.oid = oid
889-
var oid_t = bson_oid_t()
890-
bson_oid_init_from_string(&oid_t, oid)
891-
self.timestamp = UInt32(bson_oid_get_time_t(&oid_t))
892900
}
893901

894-
/// Initializes an `ObjectId` from the provided `String`. Returns `nil` if the string is not a valid
895-
/// ObjectId.
902+
/// Initializes an `ObjectId` from the provided hex `String`. Returns `nil` if the string is not a valid ObjectId.
896903
/// - SeeAlso: https://github.com/mongodb/specifications/blob/master/source/objectid.rst
897-
public init?(ifValid oid: String) {
898-
if !bson_oid_is_valid(oid, oid.utf8.count) {
904+
public init?(_ hex: String) {
905+
guard bson_oid_is_valid(hex, hex.utf8.count) else {
899906
return nil
900-
} else {
901-
self.init(fromString: oid)
902907
}
908+
var oid_t = bson_oid_t()
909+
bson_oid_init_from_string(&oid_t, hex)
910+
self.oid = oid_t
911+
}
912+
913+
internal init(bsonOid oid_t: bson_oid_t) {
914+
self.oid = oid_t
903915
}
904916

905917
public init(from decoder: Decoder) throws {
@@ -910,35 +922,12 @@ public struct ObjectId: BSONValue, Equatable, CustomStringConvertible, Codable {
910922
throw bsonEncodingUnsupportedError(value: self, at: to.codingPath)
911923
}
912924

913-
/// Initializes an `ObjectId` from an `UnsafePointer<bson_oid_t>` by copying the data
914-
/// from it to a `String`
915-
internal init(fromPointer oid_t: UnsafePointer<bson_oid_t>) {
916-
var str = Data(count: 25)
917-
self.oid = str.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<Int8>) in
918-
bson_oid_to_string(oid_t, bytes)
919-
return String(cString: bytes)
920-
}
921-
self.timestamp = UInt32(bson_oid_get_time_t(oid_t))
922-
}
923-
924-
/// Returns the provided string as a `bson_oid_t`.
925-
/// - Throws:
926-
/// - `UserError.invalidArgumentError` if the parameter string does not correspond to a valid `ObjectId`.
927-
internal static func toLibBSONType(_ str: String) throws -> bson_oid_t {
928-
var value = bson_oid_t()
929-
if !bson_oid_is_valid(str, str.utf8.count) {
930-
throw UserError.invalidArgumentError(message: "ObjectId string is invalid")
931-
}
932-
bson_oid_init_from_string(&value, str)
933-
return value
934-
}
935-
936925
public func encode(to storage: DocumentStorage, forKey key: String) throws {
937-
// create a new bson_oid_t with self.oid
938-
var oid = try ObjectId.toLibBSONType(self.oid)
939926
// encode the bson_oid_t to the bson_t
940-
guard bson_append_oid(storage.pointer, key, Int32(key.utf8.count), &oid) else {
941-
throw bsonTooLargeError(value: self, forKey: key)
927+
try withUnsafePointer(to: self.oid) { oidPtr in
928+
guard bson_append_oid(storage.pointer, key, Int32(key.utf8.count), oidPtr) else {
929+
throw bsonTooLargeError(value: self, forKey: key)
930+
}
942931
}
943932
}
944933

@@ -947,16 +936,16 @@ public struct ObjectId: BSONValue, Equatable, CustomStringConvertible, Codable {
947936
guard let oid = bson_iter_oid(iterPtr) else {
948937
throw wrongIterTypeError(iter, expected: ObjectId.self)
949938
}
950-
return self.init(fromPointer: oid)
939+
return self.init(bsonOid: oid.pointee)
951940
}
952941
}
953942

954-
public var description: String {
955-
return self.oid
956-
}
957-
958943
public static func == (lhs: ObjectId, rhs: ObjectId) -> Bool {
959-
return lhs.oid == rhs.oid
944+
return withUnsafePointer(to: lhs.oid) { lhsOidPtr in
945+
withUnsafePointer(to: rhs.oid) { rhsOidPtr in
946+
bson_oid_equal(lhsOidPtr, rhsOidPtr)
947+
}
948+
}
960949
}
961950
}
962951

Sources/MongoSwift/BSON/Overwritable.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,9 @@ extension Decimal128: Overwritable {
6464

6565
extension ObjectId: Overwritable {
6666
internal func writeToCurrentPosition(of iter: DocumentIterator) throws {
67-
var encoded = try ObjectId.toLibBSONType(self.oid)
68-
iter.withMutableBSONIterPointer { iterPtr in bson_iter_overwrite_oid(iterPtr, &encoded) }
67+
withUnsafePointer(to: self.oid) { oidPtr in
68+
iter.withMutableBSONIterPointer { iterPtr in bson_iter_overwrite_oid(iterPtr, oidPtr) }
69+
}
6970
}
7071
}
7172

Tests/MongoSwiftTests/BSONValueTests.swift

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,8 @@ final class BSONValueTests: MongoSwiftTestCase {
121121

122122
// initialize a new oid with the oid_t ptr
123123
// expect the values to be equal
124-
let objectId = ObjectId(fromPointer: &oid_t)
125-
expect(objectId.oid).to(equal(oid))
124+
let objectId = ObjectId(bsonOid: oid_t)
125+
expect(objectId.hex).to(equal(oid))
126126
expect(objectId.timestamp).to(equal(timestamp))
127127

128128
// round trip the objectId.
@@ -135,13 +135,15 @@ final class BSONValueTests: MongoSwiftTestCase {
135135
return
136136
}
137137

138-
expect(_id.oid).to(equal(objectId.oid))
138+
expect(_id).to(equal(objectId))
139+
expect(_id.hex).to(equal(objectId.hex))
139140
expect(_id.timestamp).to(equal(objectId.timestamp))
140141

141142
// expect that we can pull the correct timestamp if
142143
// initialized from the original string
143-
let objectIdFromString = ObjectId(fromString: oid)
144-
expect(objectIdFromString.oid).to(equal(oid))
144+
let objectIdFromString = ObjectId(oid)!
145+
expect(objectIdFromString).to(equal(objectId))
146+
expect(objectIdFromString.hex).to(equal(oid))
145147
expect(objectIdFromString.timestamp).to(equal(timestamp))
146148
}
147149

Tests/MongoSwiftTests/CodecTests.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ final class CodecTests: MongoSwiftTestCase {
298298
doc: ["x": 1],
299299
arr: [1, 2],
300300
binary: try Binary(base64: "//8=", subtype: .generic),
301-
oid: ObjectId(fromString: "507f1f77bcf86cd799439011"),
301+
oid: ObjectId("507f1f77bcf86cd799439011")!,
302302
bool: true,
303303
date: Date(timeIntervalSinceReferenceDate: 5000),
304304
code: CodeWithScope(code: "hi", scope: ["x": 1]),
@@ -312,7 +312,7 @@ final class CodecTests: MongoSwiftTestCase {
312312
regex: RegularExpression(pattern: "^abc", options: "imx"),
313313
symbol: Symbol("i am a symbol"),
314314
undefined: BSONUndefined(),
315-
dbpointer: DBPointer(ref: "some.namespace", id: ObjectId(fromString: "507f1f77bcf86cd799439011")),
315+
dbpointer: DBPointer(ref: "some.namespace", id: ObjectId("507f1f77bcf86cd799439011")!),
316316
null: BSONNull())
317317
}
318318

@@ -397,7 +397,7 @@ final class CodecTests: MongoSwiftTestCase {
397397
expect(try decoder.decode(Int32.self, from: "42")).to(equal(Int32(42)))
398398
expect(try decoder.decode(Int32.self, from: "{\"$numberInt\": \"42\"}")).to(equal(Int32(42)))
399399

400-
let oid = ObjectId(fromString: "507f1f77bcf86cd799439011")
400+
let oid = ObjectId("507f1f77bcf86cd799439011")!
401401
expect(try decoder.decode(ObjectId.self, from: "{\"$oid\": \"507f1f77bcf86cd799439011\"}")).to(equal(oid))
402402

403403
expect(try decoder.decode(String.self, from: "\"somestring\"")).to(equal("somestring"))
@@ -581,7 +581,7 @@ final class CodecTests: MongoSwiftTestCase {
581581
let oid = ObjectId()
582582

583583
expect(try decoder.decode(AnyBSONValue.self,
584-
from: "{\"$oid\": \"\(oid.oid)\"}").value).to(bsonEqual(oid))
584+
from: "{\"$oid\": \"\(oid.hex)\"}").value).to(bsonEqual(oid))
585585

586586
let wrappedOid: Document = ["x": oid]
587587
expect(try encoder.encode(AnyBSONStruct(oid))).to(equal(wrappedOid))

Tests/MongoSwiftTests/DocumentTests.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ final class DocumentTests: MongoSwiftTestCase {
7474
"timestamp": Timestamp(timestamp: 5, inc: 10),
7575
"nestedarray": [[1, 2], [Int32(3), Int32(4)]] as [[Int32]],
7676
"nesteddoc": ["a": 1, "b": 2, "c": false, "d": [3, 4]] as Document,
77-
"oid": ObjectId(fromString: "507f1f77bcf86cd799439011"),
77+
"oid": ObjectId("507f1f77bcf86cd799439011")!,
7878
"regex": RegularExpression(pattern: "^abc", options: "imx"),
7979
"array1": [1, 2],
8080
"array2": ["string1", "string2"],
@@ -139,7 +139,7 @@ final class DocumentTests: MongoSwiftTestCase {
139139
expect(doc["maxkey"]).to(bsonEqual(MaxKey()))
140140
expect(doc["date"]).to(bsonEqual(Date(timeIntervalSince1970: 500.004)))
141141
expect(doc["timestamp"]).to(bsonEqual(Timestamp(timestamp: 5, inc: 10)))
142-
expect(doc["oid"]).to(bsonEqual(ObjectId(fromString: "507f1f77bcf86cd799439011")))
142+
expect(doc["oid"]).to(bsonEqual(ObjectId("507f1f77bcf86cd799439011")!))
143143

144144
let regex = doc["regex"] as? RegularExpression
145145
expect(regex).to(equal(RegularExpression(pattern: "^abc", options: "imx")))
@@ -190,7 +190,7 @@ final class DocumentTests: MongoSwiftTestCase {
190190
expect(DocumentTests.testDoc.maxkey).to(bsonEqual(MaxKey()))
191191
expect(DocumentTests.testDoc.date).to(bsonEqual(Date(timeIntervalSince1970: 500.004)))
192192
expect(DocumentTests.testDoc.timestamp).to(bsonEqual(Timestamp(timestamp: 5, inc: 10)))
193-
expect(DocumentTests.testDoc.oid).to(bsonEqual(ObjectId(fromString: "507f1f77bcf86cd799439011")))
193+
expect(DocumentTests.testDoc.oid).to(bsonEqual(ObjectId("507f1f77bcf86cd799439011")!))
194194

195195
let codewscope = DocumentTests.testDoc.codewscope as? CodeWithScope
196196
expect(codewscope?.code).to(equal("console.log(x);"))

0 commit comments

Comments
 (0)