Coverage Report

Created: 2026-02-14 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/swift-protobuf/Sources/SwiftProtobuf/PathDecoder.swift
Line
Count
Source
1
// Sources/SwiftProtobuf/PathDecoder.swift - Path decoder
2
//
3
// Copyright (c) 2014 - 2023 Apple Inc. and the project authors
4
// Licensed under Apache License v2.0 with Runtime Library Exception
5
//
6
// See LICENSE.txt for license information:
7
// https://github.com/apple/swift-protobuf/blob/main/LICENSE.txt
8
//
9
// -----------------------------------------------------------------------------
10
///
11
/// Decoder which sets value of a field by its path.
12
///
13
// -----------------------------------------------------------------------------
14
15
import Foundation
16
17
/// Describes errors can occure during decoding a proto by path.
18
public enum PathDecodingError: Error {
19
20
    /// Describes a mismatch in type of the fields.
21
    ///
22
    /// If a value of type A is applied to a path with type B.
23
    /// this error will be thrown.
24
    case typeMismatch
25
26
    /// Describes path is not found in message type.
27
    ///
28
    /// If a message has no field with the given path this
29
    /// error will be thrown.
30
    case pathNotFound
31
}
32
33
extension Message {
34
0
    static func number(for field: String) -> Int? {
35
0
        guard let type = Self.self as? any _ProtoNameProviding.Type else {
36
0
            return nil
37
0
        }
38
0
        guard
39
0
            let number = Array(field.utf8).withUnsafeBytes({ bytes in
40
0
                type._protobuf_nameMap.number(forProtoName: bytes)
41
0
            })
42
0
        else {
43
0
            return nil
44
0
        }
45
0
        if type._protobuf_nameMap.names(for: number)?.proto.description != field {
46
0
            return nil
47
0
        }
48
0
        return number
49
0
    }
50
51
0
    static func name(for field: Int) -> String? {
52
0
        guard let type = Self.self as? any _ProtoNameProviding.Type else {
53
0
            return nil
54
0
        }
55
0
        return type._protobuf_nameMap.names(for: field)?.proto.description
56
0
    }
57
}
58
59
// Decoder that set value of a message field by the given path
60
struct PathDecoder<T: Message>: Decoder {
61
62
    // The value should be set to the path
63
    private let value: Any?
64
65
    // Field number should be overriden by decoder
66
    private var number: Int?
67
68
    // The path only including sub-paths
69
    private let nextPath: [String]
70
71
    // Merge options to be concidered while setting value
72
    private let mergeOption: Google_Protobuf_FieldMask.MergeOptions
73
74
0
    private var replaceRepeatedFields: Bool {
75
0
        mergeOption.replaceRepeatedFields
76
0
    }
77
78
    init(
79
        path: [String],
80
        value: Any?,
81
        mergeOption: Google_Protobuf_FieldMask.MergeOptions
82
0
    ) throws {
83
0
        if let firstComponent = path.first,
84
0
            let number = T.number(for: firstComponent)
85
0
        {
86
0
            self.number = number
87
0
            self.nextPath = .init(path.dropFirst())
88
0
        } else {
89
0
            throw PathDecodingError.pathNotFound
90
0
        }
91
0
        self.value = value
92
0
        self.mergeOption = mergeOption
93
0
    }
94
95
0
    private func setValue<V>(_ value: inout V, defaultValue: V) throws {
96
0
        if !nextPath.isEmpty {
97
0
            throw PathDecodingError.pathNotFound
98
0
        }
99
0
        if self.value == nil {
100
0
            value = defaultValue
101
0
            return
102
0
        }
103
0
        guard let castedValue = self.value as? V else {
104
0
            throw PathDecodingError.typeMismatch
105
0
        }
106
0
        value = castedValue
107
0
    }
108
109
0
    private func setRepeatedValue<V>(_ value: inout [V]) throws {
110
0
        if !nextPath.isEmpty {
111
0
            throw PathDecodingError.pathNotFound
112
0
        }
113
0
        var castedValue: [V] = []
114
0
        if self.value != nil {
115
0
            guard let v = self.value as? [V] else {
116
0
                throw PathDecodingError.typeMismatch
117
0
            }
118
0
            castedValue = v
119
0
        }
120
0
        if replaceRepeatedFields {
121
0
            value = castedValue
122
0
        } else {
123
0
            value.append(contentsOf: castedValue)
124
0
        }
125
0
    }
126
127
    private func setMapValue<K, V>(
128
        _ value: inout [K: V]
129
0
    ) throws {
130
0
        if !nextPath.isEmpty {
131
0
            throw PathDecodingError.pathNotFound
132
0
        }
133
0
        var castedValue: [K: V] = [:]
134
0
        if self.value != nil {
135
0
            guard let v = self.value as? [K: V] else {
136
0
                throw PathDecodingError.typeMismatch
137
0
            }
138
0
            castedValue = v
139
0
        }
140
0
        if replaceRepeatedFields {
141
0
            value = castedValue
142
0
        } else {
143
0
            value.merge(castedValue) { _, new in
144
0
                new
145
0
            }
146
0
        }
147
0
    }
148
149
    private func setMessageValue<M: Message>(
150
        _ value: inout M?
151
0
    ) throws {
152
0
        if nextPath.isEmpty {
153
0
            try setValue(&value, defaultValue: nil)
154
0
            return
155
0
        }
156
0
        var decoder = try PathDecoder<M>(
157
0
            path: nextPath,
158
0
            value: self.value,
159
0
            mergeOption: mergeOption
160
0
        )
161
0
        if value == nil {
162
0
            value = .init()
163
0
        }
164
0
        try value?.decodeMessage(decoder: &decoder)
165
0
    }
166
167
0
    mutating func handleConflictingOneOf() throws {}
168
169
0
    mutating func nextFieldNumber() throws -> Int? {
170
0
        defer { number = nil }
171
0
        return number
172
0
    }
173
174
0
    mutating func decodeSingularFloatField(value: inout Float) throws {
175
0
        try setValue(&value, defaultValue: .init())
176
0
    }
177
178
0
    mutating func decodeSingularFloatField(value: inout Float?) throws {
179
0
        try setValue(&value, defaultValue: nil)
180
0
    }
181
182
0
    mutating func decodeRepeatedFloatField(value: inout [Float]) throws {
183
0
        try setRepeatedValue(&value)
184
0
    }
185
186
0
    mutating func decodeSingularDoubleField(value: inout Double) throws {
187
0
        try setValue(&value, defaultValue: .init())
188
0
    }
189
190
0
    mutating func decodeSingularDoubleField(value: inout Double?) throws {
191
0
        try setValue(&value, defaultValue: nil)
192
0
    }
193
194
0
    mutating func decodeRepeatedDoubleField(value: inout [Double]) throws {
195
0
        try setRepeatedValue(&value)
196
0
    }
197
198
0
    mutating func decodeSingularInt32Field(value: inout Int32) throws {
199
0
        try setValue(&value, defaultValue: .init())
200
0
    }
201
202
0
    mutating func decodeSingularInt32Field(value: inout Int32?) throws {
203
0
        try setValue(&value, defaultValue: nil)
204
0
    }
205
206
0
    mutating func decodeRepeatedInt32Field(value: inout [Int32]) throws {
207
0
        try setRepeatedValue(&value)
208
0
    }
209
210
0
    mutating func decodeSingularInt64Field(value: inout Int64) throws {
211
0
        try setValue(&value, defaultValue: .init())
212
0
    }
213
214
0
    mutating func decodeSingularInt64Field(value: inout Int64?) throws {
215
0
        try setValue(&value, defaultValue: nil)
216
0
    }
217
218
0
    mutating func decodeRepeatedInt64Field(value: inout [Int64]) throws {
219
0
        try setRepeatedValue(&value)
220
0
    }
221
222
0
    mutating func decodeSingularUInt32Field(value: inout UInt32) throws {
223
0
        try setValue(&value, defaultValue: .init())
224
0
    }
225
226
0
    mutating func decodeSingularUInt32Field(value: inout UInt32?) throws {
227
0
        try setValue(&value, defaultValue: nil)
228
0
    }
229
230
0
    mutating func decodeRepeatedUInt32Field(value: inout [UInt32]) throws {
231
0
        try setRepeatedValue(&value)
232
0
    }
233
234
0
    mutating func decodeSingularUInt64Field(value: inout UInt64) throws {
235
0
        try setValue(&value, defaultValue: .init())
236
0
    }
237
238
0
    mutating func decodeSingularUInt64Field(value: inout UInt64?) throws {
239
0
        try setValue(&value, defaultValue: nil)
240
0
    }
241
242
0
    mutating func decodeRepeatedUInt64Field(value: inout [UInt64]) throws {
243
0
        try setRepeatedValue(&value)
244
0
    }
245
246
0
    mutating func decodeSingularSInt32Field(value: inout Int32) throws {
247
0
        try setValue(&value, defaultValue: .init())
248
0
    }
249
250
0
    mutating func decodeSingularSInt32Field(value: inout Int32?) throws {
251
0
        try setValue(&value, defaultValue: nil)
252
0
    }
253
254
0
    mutating func decodeRepeatedSInt32Field(value: inout [Int32]) throws {
255
0
        try setRepeatedValue(&value)
256
0
    }
257
258
0
    mutating func decodeSingularSInt64Field(value: inout Int64) throws {
259
0
        try setValue(&value, defaultValue: .init())
260
0
    }
261
262
0
    mutating func decodeSingularSInt64Field(value: inout Int64?) throws {
263
0
        try setValue(&value, defaultValue: nil)
264
0
    }
265
266
0
    mutating func decodeRepeatedSInt64Field(value: inout [Int64]) throws {
267
0
        try setRepeatedValue(&value)
268
0
    }
269
270
0
    mutating func decodeSingularFixed32Field(value: inout UInt32) throws {
271
0
        try setValue(&value, defaultValue: .init())
272
0
    }
273
274
0
    mutating func decodeSingularFixed32Field(value: inout UInt32?) throws {
275
0
        try setValue(&value, defaultValue: nil)
276
0
    }
277
278
0
    mutating func decodeRepeatedFixed32Field(value: inout [UInt32]) throws {
279
0
        try setRepeatedValue(&value)
280
0
    }
281
282
0
    mutating func decodeSingularFixed64Field(value: inout UInt64) throws {
283
0
        try setValue(&value, defaultValue: .init())
284
0
    }
285
286
0
    mutating func decodeSingularFixed64Field(value: inout UInt64?) throws {
287
0
        try setValue(&value, defaultValue: nil)
288
0
    }
289
290
0
    mutating func decodeRepeatedFixed64Field(value: inout [UInt64]) throws {
291
0
        try setRepeatedValue(&value)
292
0
    }
293
294
0
    mutating func decodeSingularSFixed32Field(value: inout Int32) throws {
295
0
        try setValue(&value, defaultValue: .init())
296
0
    }
297
298
0
    mutating func decodeSingularSFixed32Field(value: inout Int32?) throws {
299
0
        try setValue(&value, defaultValue: nil)
300
0
    }
301
302
0
    mutating func decodeRepeatedSFixed32Field(value: inout [Int32]) throws {
303
0
        try setRepeatedValue(&value)
304
0
    }
305
306
0
    mutating func decodeSingularSFixed64Field(value: inout Int64) throws {
307
0
        try setValue(&value, defaultValue: .init())
308
0
    }
309
310
0
    mutating func decodeSingularSFixed64Field(value: inout Int64?) throws {
311
0
        try setValue(&value, defaultValue: nil)
312
0
    }
313
314
0
    mutating func decodeRepeatedSFixed64Field(value: inout [Int64]) throws {
315
0
        try setRepeatedValue(&value)
316
0
    }
317
318
0
    mutating func decodeSingularBoolField(value: inout Bool) throws {
319
0
        try setValue(&value, defaultValue: .init())
320
0
    }
321
322
0
    mutating func decodeSingularBoolField(value: inout Bool?) throws {
323
0
        try setValue(&value, defaultValue: nil)
324
0
    }
325
326
0
    mutating func decodeRepeatedBoolField(value: inout [Bool]) throws {
327
0
        try setRepeatedValue(&value)
328
0
    }
329
330
0
    mutating func decodeSingularStringField(value: inout String) throws {
331
0
        try setValue(&value, defaultValue: .init())
332
0
    }
333
334
0
    mutating func decodeSingularStringField(value: inout String?) throws {
335
0
        try setValue(&value, defaultValue: nil)
336
0
    }
337
338
0
    mutating func decodeRepeatedStringField(value: inout [String]) throws {
339
0
        try setRepeatedValue(&value)
340
0
    }
341
342
0
    mutating func decodeSingularBytesField(value: inout Data) throws {
343
0
        try setValue(&value, defaultValue: .init())
344
0
    }
345
346
0
    mutating func decodeSingularBytesField(value: inout Data?) throws {
347
0
        try setValue(&value, defaultValue: nil)
348
0
    }
349
350
0
    mutating func decodeRepeatedBytesField(value: inout [Data]) throws {
351
0
        try setRepeatedValue(&value)
352
0
    }
353
354
    mutating func decodeSingularEnumField<E>(
355
        value: inout E
356
0
    ) throws where E: Enum, E.RawValue == Int {
357
0
        try setValue(&value, defaultValue: .init())
358
0
    }
359
360
    mutating func decodeSingularEnumField<E>(
361
        value: inout E?
362
0
    ) throws where E: Enum, E.RawValue == Int {
363
0
        try setValue(&value, defaultValue: nil)
364
0
    }
365
366
    mutating func decodeRepeatedEnumField<E>(
367
        value: inout [E]
368
0
    ) throws where E: Enum, E.RawValue == Int {
369
0
        try setRepeatedValue(&value)
370
0
    }
371
372
    mutating func decodeSingularMessageField<M>(
373
        value: inout M?
374
0
    ) throws where M: Message {
375
0
        try setMessageValue(&value)
376
0
    }
377
378
    mutating func decodeRepeatedMessageField<M>(
379
        value: inout [M]
380
0
    ) throws where M: Message {
381
0
        try setRepeatedValue(&value)
382
0
    }
383
384
    mutating func decodeSingularGroupField<G>(
385
        value: inout G?
386
0
    ) throws where G: Message {
387
0
        try setMessageValue(&value)
388
0
    }
389
390
    mutating func decodeRepeatedGroupField<G>(
391
        value: inout [G]
392
0
    ) throws where G: Message {
393
0
        try setRepeatedValue(&value)
394
0
    }
395
396
    mutating func decodeMapField<KeyType, ValueType>(
397
        fieldType: _ProtobufMap<KeyType, ValueType>.Type,
398
        value: inout _ProtobufMap<KeyType, ValueType>.BaseType
399
0
    ) throws where KeyType: MapKeyType, ValueType: MapValueType {
400
0
        try setMapValue(&value)
401
0
    }
402
403
    mutating func decodeMapField<KeyType, ValueType>(
404
        fieldType: _ProtobufEnumMap<KeyType, ValueType>.Type,
405
        value: inout _ProtobufEnumMap<KeyType, ValueType>.BaseType
406
0
    ) throws where KeyType: MapKeyType, ValueType: Enum, ValueType.RawValue == Int {
407
0
        try setMapValue(&value)
408
0
    }
409
410
    mutating func decodeMapField<KeyType, ValueType>(
411
        fieldType: _ProtobufMessageMap<KeyType, ValueType>.Type,
412
        value: inout _ProtobufMessageMap<KeyType, ValueType>.BaseType
413
0
    ) throws where KeyType: MapKeyType, ValueType: Hashable, ValueType: Message {
414
0
        try setMapValue(&value)
415
0
    }
416
417
    mutating func decodeExtensionField(
418
        values: inout ExtensionFieldValueSet,
419
        messageType: any Message.Type,
420
        fieldNumber: Int
421
0
    ) throws {
422
0
        preconditionFailure(
423
0
            "Internal Error: Path decoder should never decode an extension field"
424
0
        )
425
0
    }
426
427
}
428
429
extension Message {
430
    mutating func `set`(
431
        path: String,
432
        value: Any?,
433
        mergeOption: Google_Protobuf_FieldMask.MergeOptions
434
0
    ) throws {
435
0
        let _path = path.components(separatedBy: ".")
436
0
        var decoder = try PathDecoder<Self>(
437
0
            path: _path,
438
0
            value: value,
439
0
            mergeOption: mergeOption
440
0
        )
441
0
        try decodeMessage(decoder: &decoder)
442
0
    }
443
}