Skip to content

Commit 0806a07

Browse files
author
Pouya Yarandi
committed
Add applying method and its generator
1 parent 4fc6b35 commit 0806a07

File tree

5 files changed

+55
-1
lines changed

5 files changed

+55
-1
lines changed

Sources/SwiftProtobuf/ProtobufMirror.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,12 @@ public extension ProtobufMirror {
132132
}
133133

134134
}
135+
136+
public enum MessageModificationError: Error {
137+
case typeMismatch
138+
case invalidFieldNumber
139+
}
140+
141+
public protocol MessageModifier: Message {
142+
func applying(_ value: Any, for fieldNumber: Int) throws -> Self
143+
}

Sources/protoc-gen-swift/FieldGenerator.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ protocol FieldGenerator {
5656
/// Generate any support needed to this field's value is initialized.
5757
/// The generated code should return false if it isn't set.
5858
func generateIsInitializedCheck(printer: inout CodePrinter)
59+
60+
func generateApplying(printer: inout CodePrinter)
5961
}
6062

6163
/// Simple base class for FieldGenerators that also provides fieldMapNames.

Sources/protoc-gen-swift/MessageFieldGenerator.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,4 +221,8 @@ class MessageFieldGenerator: FieldGeneratorBase, FieldGenerator {
221221
p.printIndented("try visitor.\(visitMethod)(\(traitsArg)value: \(varName), fieldNumber: \(number))")
222222
p.print("}\(suffix)")
223223
}
224+
225+
func generateApplying(printer p: inout CodePrinter) {
226+
p.print("case \(number): copy.\(swiftName) = try valueAs(\(swiftType).self)")
227+
}
224228
}

Sources/protoc-gen-swift/MessageGenerator.swift

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ class MessageGenerator {
196196
func generateRuntimeSupport(printer p: inout CodePrinter, file: FileGenerator, parent: MessageGenerator?) {
197197
p.print(
198198
"",
199-
"extension \(swiftFullName): \(namer.swiftProtobufModulePrefix)Message, \(namer.swiftProtobufModulePrefix)_MessageImplementationBase, \(namer.swiftProtobufModulePrefix)_ProtoNameProviding {")
199+
"extension \(swiftFullName): \(namer.swiftProtobufModulePrefix)Message, \(namer.swiftProtobufModulePrefix)_MessageImplementationBase, \(namer.swiftProtobufModulePrefix)_ProtoNameProviding, \(namer.swiftProtobufModulePrefix)MessageModifier {")
200200
p.withIndentation { p in
201201
if let parent = parent {
202202
p.print("\(visibility)static let protoMessageName: String = \(parent.swiftFullName).protoMessageName + \".\(descriptor.name)\"")
@@ -220,6 +220,8 @@ class MessageGenerator {
220220
generateTraverse(printer: &p)
221221
p.print()
222222
generateMessageEquality(printer: &p)
223+
p.print()
224+
generateMessageApplying(printer: &p)
223225
}
224226
p.print("}")
225227

@@ -402,6 +404,29 @@ class MessageGenerator {
402404
p.print("}")
403405
}
404406

407+
private func generateMessageApplying(printer p: inout CodePrinter) {
408+
p.print("\(visibility)func applying(_ value: Any, for fieldNumber: Int) throws -> \(swiftFullName) {")
409+
p.withIndentation { p in
410+
p.print("""
411+
func valueAs<T>(_ type: T.Type) throws -> T {
412+
guard let _value = value as? T else {
413+
throw \(namer.swiftProtobufModulePrefix)MessageModificationError.typeMismatch
414+
}
415+
return _value
416+
}
417+
""")
418+
p.print("var copy = self")
419+
p.print("switch fieldNumber {")
420+
for f in fields {
421+
f.generateApplying(printer: &p)
422+
}
423+
p.print("default: throw \(namer.swiftProtobufModulePrefix)MessageModificationError.invalidFieldNumber")
424+
p.print("}")
425+
p.print("return copy")
426+
}
427+
p.print("}")
428+
}
429+
405430
/// Generates the `isInitialized` property for the message, if needed.
406431
///
407432
/// This may generate nothing, if the `isInitialized` property is not

Sources/protoc-gen-swift/OneofGenerator.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ class OneofGenerator {
104104
func generateTraverse(printer p: inout CodePrinter) {
105105
oneof.generateTraverse(printer: &p, field: self)
106106
}
107+
108+
func generateApplying(printer p: inout CodePrinter) {
109+
oneof.generateApplying(printer: &p, field: self)
110+
}
107111
}
108112

109113
private let oneofDescriptor: OneofDescriptor
@@ -419,4 +423,14 @@ class OneofGenerator {
419423

420424
p.print("if let v = \(storedProperty), !v.isInitialized {return false}")
421425
}
426+
427+
func generateApplying(printer p: inout CodePrinter, field: MemberFieldGenerator) {
428+
// First field causes the output.
429+
let group = fieldSortedGrouped[field.group]
430+
guard field === fields.first else { return }
431+
432+
for f in group {
433+
p.print("case \(f.number): copy.\(f.swiftName) = try valueAs(\(f.swiftType).self)")
434+
}
435+
}
422436
}

0 commit comments

Comments
 (0)