Skip to content

Commit fcec7f2

Browse files
author
Pouya Yarandi
committed
Fix comments
1 parent d564895 commit fcec7f2

File tree

5 files changed

+117
-48
lines changed

5 files changed

+117
-48
lines changed

Sources/SwiftProtobuf/GetPathDecoder.swift

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,21 @@
1414

1515
import Foundation
1616

17+
// Decoder that captures value of a message field from the given path
1718
struct GetPathDecoder<T: Message>: Decoder {
1819

20+
// The path only including sub-paths
1921
private let nextPath: [String]
20-
private var number: Int?
2122

22-
private var _value: Any?
23-
private var _hasPath: Bool = false
23+
// Field number should be captured by decoder
24+
private var number: Int?
2425

25-
internal var value: Any? {
26-
_value
27-
}
26+
// Captured value after decoding will be stored in this property
27+
private(set) var value: Any?
2828

29-
internal var hasPath: Bool {
30-
_hasPath
31-
}
29+
// While decoding this property becomes true if the path exists
30+
// Note that a property value could be nil while its path is found
31+
private(set) var hasPath: Bool = false
3232

3333
internal init(path: [String]) throws {
3434
guard let firstComponent = path.first,
@@ -50,8 +50,8 @@ struct GetPathDecoder<T: Message>: Decoder {
5050
guard nextPath.isEmpty else {
5151
throw PathDecodingError.pathNotFound
5252
}
53-
self._value = value
54-
self._hasPath = true
53+
self.value = value
54+
self.hasPath = true
5555
}
5656

5757
mutating func decodeSingularFloatField(value: inout Float) throws {
@@ -260,8 +260,8 @@ struct GetPathDecoder<T: Message>: Decoder {
260260
var tmp = M()
261261
try tmp.decodeMessage(decoder: &decoder)
262262
}
263-
self._value = decoder.value
264-
self._hasPath = decoder.hasPath
263+
self.value = decoder.value
264+
self.hasPath = decoder.hasPath
265265
}
266266

267267
mutating func decodeRepeatedMessageField<M>(value: inout [M]) throws {
@@ -301,7 +301,11 @@ struct GetPathDecoder<T: Message>: Decoder {
301301
values: inout ExtensionFieldValueSet,
302302
messageType: Message.Type,
303303
fieldNumber: Int
304-
) throws {}
304+
) throws {
305+
preconditionFailure(
306+
"Path decoder should never decode an extension field"
307+
)
308+
}
305309

306310
}
307311

Sources/SwiftProtobuf/Google_Protobuf_FieldMask+Extensions.swift

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -283,8 +283,7 @@ extension Google_Protobuf_FieldMask {
283283
let set = mask.pathsSet
284284
var _paths: [String] = []
285285
var _buffer = Set<String>()
286-
for path in paths where set.contains(path)
287-
&& !_buffer.contains(path) {
286+
for path in paths where set.contains(path) && !_buffer.contains(path) {
288287
_buffer.insert(path)
289288
_paths.append(path)
290289
}
@@ -304,8 +303,7 @@ extension Google_Protobuf_FieldMask {
304303
let set = mask.pathsSet
305304
var _paths: [String] = []
306305
var _buffer = Set<String>()
307-
for path in paths where !set.contains(path)
308-
&& !_buffer.contains(path) {
306+
for path in paths where !set.contains(path) && !_buffer.contains(path) {
309307
_buffer.insert(path)
310308
_paths.append(path)
311309
}
@@ -334,13 +332,6 @@ extension Google_Protobuf_FieldMask {
334332
private var pathsSet: Set<String> {
335333
.init(paths)
336334
}
337-
338-
private func levels(path: String) -> [String] {
339-
let comps = path.components(separatedBy: ".")
340-
return (0..<comps.count).map {
341-
comps[0...$0].joined(separator: ".")
342-
}
343-
}
344335
}
345336

346337
extension Google_Protobuf_FieldMask {

Sources/SwiftProtobuf/Message+FieldMask.swift

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,17 @@ extension Message {
3535
}
3636

3737
/// Defines available options for merging two messages.
38-
public enum MergeOption: Equatable {
38+
public struct MergeOption {
39+
40+
public init(replaceRepeatedFields: Bool = false) {
41+
self.replaceRepeatedFields = replaceRepeatedFields
42+
}
3943

4044
/// The default merging behavior will append entries from the source
4145
/// repeated field to the destination repeated field. If you only want
4246
/// to keep the entries from the source repeated field, set this flag
4347
/// to true.
44-
case replaceRepeatedFields
48+
public var replaceRepeatedFields = false
4549
}
4650

4751
extension Message {
@@ -54,29 +58,27 @@ extension Message {
5458
public mutating func merge(
5559
to source: Self,
5660
fieldMask: Google_Protobuf_FieldMask,
57-
mergeOptions: [MergeOption] = []
61+
mergeOption: MergeOption = .init()
5862
) throws {
5963
var source = source
60-
var copy = self
6164
var pathToValueMap: [String: Any?] = [:]
62-
let replaceRepeatedFields = mergeOptions
63-
.contains(.replaceRepeatedFields)
6465
for path in fieldMask.paths {
6566
pathToValueMap[path] = try source.get(path: path)
6667
}
6768
for (path, value) in pathToValueMap {
68-
try copy.set(
69+
try? set(
6970
path: path,
7071
value: value,
71-
replaceRepeatedFields: replaceRepeatedFields
72+
mergeOption: mergeOption
7273
)
7374
}
74-
self = copy
7575
}
7676
}
7777

7878
extension Message where Self: Equatable, Self: _ProtoNameProviding {
7979

80+
// TODO: Re-implement using clear fields instead of copying message
81+
8082
@discardableResult
8183
/// Removes from 'message' any field that is not represented in the given
8284
/// FieldMask. If the FieldMask is empty, does nothing.
@@ -92,7 +94,7 @@ extension Message where Self: Equatable, Self: _ProtoNameProviding {
9294
if fieldMask.paths.isEmpty {
9395
return false
9496
}
95-
var tmp = Self.init()
97+
var tmp = Self(removingAllFieldsOf: self)
9698
do {
9799
try tmp.merge(to: self, fieldMask: fieldMask)
98100
let changed = tmp != self
@@ -103,3 +105,22 @@ extension Message where Self: Equatable, Self: _ProtoNameProviding {
103105
}
104106
}
105107
}
108+
109+
private extension Message {
110+
init(removingAllFieldsOf message: Self) {
111+
if let type = Self.self as? ExtensibleMessage.Type,
112+
let extensible = message as? ExtensibleMessage {
113+
self = type.init(extensionsOf: extensible) as? Self ?? .init()
114+
} else {
115+
self = .init()
116+
}
117+
self.unknownFields = message.unknownFields
118+
}
119+
}
120+
121+
private extension Message where Self: ExtensibleMessage {
122+
init(extensionsOf message: ExtensibleMessage) {
123+
self.init()
124+
_protobuf_extensionFieldValues = message._protobuf_extensionFieldValues
125+
}
126+
}

Sources/SwiftProtobuf/SetPathDecoder.swift

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,24 +39,37 @@ extension Message {
3939
}
4040
}
4141

42+
// Decoder that set value of a message field by the given path
4243
struct SetPathDecoder<T: Message>: Decoder {
4344

45+
// The value should be set to the path
4446
private let value: Any?
47+
48+
// Field number should be overriden by decoder
4549
private var number: Int?
50+
51+
// The path only including sub-paths
4652
private let nextPath: [String]
47-
private let replaceRepeatedFields: Bool
53+
54+
// Merge options to be concidered while setting value
55+
private let mergeOption: MergeOption
56+
57+
private var replaceRepeatedFields: Bool {
58+
mergeOption.replaceRepeatedFields
59+
}
4860

4961
init(
5062
path: [String],
5163
value: Any?,
52-
replaceRepeatedFields: Bool
64+
mergeOption: MergeOption
5365
) {
54-
if let firstComponent = path.first {
55-
self.number = T.number(for: firstComponent)
66+
if let firstComponent = path.first,
67+
let number = T.number(for: firstComponent) {
68+
self.number = number
5669
}
5770
self.nextPath = .init(path.dropFirst())
5871
self.value = value
59-
self.replaceRepeatedFields = replaceRepeatedFields
72+
self.mergeOption = mergeOption
6073
}
6174

6275
private func setValue<V>(_ value: inout V) throws {
@@ -77,6 +90,21 @@ struct SetPathDecoder<T: Message>: Decoder {
7790
}
7891
}
7992

93+
private func setMapValue<K, V>(
94+
_ value: inout Dictionary<K, V>
95+
) throws {
96+
guard let __value = self.value as? Dictionary<K, V> else {
97+
throw PathDecodingError.typeMismatch
98+
}
99+
if replaceRepeatedFields {
100+
value = __value
101+
} else {
102+
value.merge(__value) { _, new in
103+
new
104+
}
105+
}
106+
}
107+
80108
mutating func handleConflictingOneOf() throws {}
81109

82110
mutating func nextFieldNumber() throws -> Int? {
@@ -292,7 +320,7 @@ struct SetPathDecoder<T: Message>: Decoder {
292320
var decoder = SetPathDecoder<M>(
293321
path: nextPath,
294322
value: self.value,
295-
replaceRepeatedFields: replaceRepeatedFields
323+
mergeOption: mergeOption
296324
)
297325
if value == nil {
298326
value = .init()
@@ -322,42 +350,46 @@ struct SetPathDecoder<T: Message>: Decoder {
322350
fieldType: _ProtobufMap<KeyType, ValueType>.Type,
323351
value: inout _ProtobufMap<KeyType, ValueType>.BaseType
324352
) throws where KeyType : MapKeyType, ValueType : MapValueType {
325-
try setValue(&value)
353+
try setMapValue(&value)
326354
}
327355

328356
mutating func decodeMapField<KeyType, ValueType>(
329357
fieldType: _ProtobufEnumMap<KeyType, ValueType>.Type,
330358
value: inout _ProtobufEnumMap<KeyType, ValueType>.BaseType
331359
) throws where KeyType : MapKeyType, ValueType : Enum, ValueType.RawValue == Int {
332-
try setValue(&value)
360+
try setMapValue(&value)
333361
}
334362

335363
mutating func decodeMapField<KeyType, ValueType>(
336364
fieldType: _ProtobufMessageMap<KeyType, ValueType>.Type,
337365
value: inout _ProtobufMessageMap<KeyType, ValueType>.BaseType
338366
) throws where KeyType : MapKeyType, ValueType : Hashable, ValueType : Message {
339-
try setValue(&value)
367+
try setMapValue(&value)
340368
}
341369

342370
mutating func decodeExtensionField(
343371
values: inout ExtensionFieldValueSet,
344372
messageType: Message.Type,
345373
fieldNumber: Int
346-
) throws {}
374+
) throws {
375+
preconditionFailure(
376+
"Path decoder should never decode an extension field"
377+
)
378+
}
347379

348380
}
349381

350382
extension Message {
351383
mutating func `set`(
352384
path: String,
353385
value: Any?,
354-
replaceRepeatedFields: Bool
386+
mergeOption: MergeOption
355387
) throws {
356388
let _path = path.components(separatedBy: ".")
357389
var decoder = SetPathDecoder<Self>(
358390
path: _path,
359391
value: value,
360-
replaceRepeatedFields: replaceRepeatedFields
392+
mergeOption: mergeOption
361393
)
362394
try decodeMessage(decoder: &decoder)
363395
}

Tests/SwiftProtobufTests/Test_FieldMask.swift

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,10 +151,31 @@ final class Test_FieldMask: XCTestCase, PBTestHelpers {
151151
XCTAssertEqual(message.repeatedInt32, [1, 2, 3, 4])
152152

153153
// Checks with replacing repeated fields
154-
try message.merge(to: secondMessage, fieldMask: fieldMask, mergeOptions: [.replaceRepeatedFields])
154+
try message.merge(to: secondMessage, fieldMask: fieldMask, mergeOption: .init(replaceRepeatedFields: true))
155155
XCTAssertEqual(message.repeatedInt32, [3, 4])
156156
}
157157

158+
// Checks merge functionality for map field masks.
159+
func testMergeMapFieldsOfMessage() throws {
160+
var message = SwiftProtoTesting_Fuzz_Message.with { model in
161+
model.mapInt32String = [1: "a", 2: "c"]
162+
}
163+
164+
let secondMessage = SwiftProtoTesting_Fuzz_Message.with { model in
165+
model.mapInt32String = [2: "b"]
166+
}
167+
168+
let fieldMask = Google_Protobuf_FieldMask(protoPaths: ["map_int32_string"])
169+
170+
// Checks without replacing repeated fields
171+
try message.merge(to: secondMessage, fieldMask: fieldMask)
172+
XCTAssertEqual(message.mapInt32String, [1: "a", 2: "b"])
173+
174+
// Checks with replacing repeated fields
175+
try message.merge(to: secondMessage, fieldMask: fieldMask, mergeOption: .init(replaceRepeatedFields: true))
176+
XCTAssertEqual(message.mapInt32String, [2: "b"])
177+
}
178+
158179
// Checks trim functionality for field masks.
159180
func testTrimFieldsOfMessage() throws {
160181
var message = SwiftProtoTesting_TestAllTypes.with { model in

0 commit comments

Comments
 (0)