MessageStorageClassGenerator.swift 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. // Sources/protoc-gen-swift/MessageStorageClassGenerator.swift - Message storage class logic
  2. //
  3. // Copyright (c) 2014 - 2016 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. /// Code generation for the private storage class used inside copy-on-write
  12. /// messages.
  13. ///
  14. // -----------------------------------------------------------------------------
  15. import Foundation
  16. import SwiftProtobuf
  17. import SwiftProtobufPluginLibrary
  18. /// Generates the `_StorageClass` used for messages that employ copy-on-write
  19. /// logic for some of their fields.
  20. class MessageStorageClassGenerator {
  21. private let fields: [any FieldGenerator]
  22. /// Creates a new `MessageStorageClassGenerator`.
  23. init(fields: [any FieldGenerator]) {
  24. self.fields = fields
  25. }
  26. /// Visibility of the storage within the Message.
  27. var storageVisibility: String {
  28. "fileprivate"
  29. }
  30. /// If the storage wants to manually implement equality.
  31. var storageProvidesEqualTo: Bool { false }
  32. /// Generates the full code for the storage class.
  33. ///
  34. /// - Parameter p: The code printer.
  35. func generateTypeDeclaration(printer p: inout CodePrinter) {
  36. p.print("fileprivate class _StorageClass {")
  37. p.withIndentation { p in
  38. generateStoredProperties(printer: &p)
  39. // Generate a default instance to be used so the heap allocation is
  40. // delayed until mutation is needed. This is the largest savings when
  41. // the message is used as a field in another message as it causes
  42. // returning the default to not require that heap allocation, i.e. -
  43. // readonly usage never causes the allocation.
  44. p.print(
  45. """
  46. // This property is used as the initial default value for new instances of the type.
  47. // The type itself is protecting the reference to its storage via CoW semantics.
  48. // This will force a copy to be made of this reference when the first mutation occurs;
  49. // hence, it is safe to mark this as `nonisolated(unsafe)`.
  50. static nonisolated(unsafe) let defaultInstance = _StorageClass()
  51. private init() {}
  52. """
  53. )
  54. generateClone(printer: &p)
  55. }
  56. p.print("}")
  57. }
  58. /// Generated the uniqueStorage() implementation.
  59. func generateUniqueStorage(printer p: inout CodePrinter) {
  60. p.print("\(storageVisibility) mutating func _uniqueStorage() -> _StorageClass {")
  61. p.withIndentation { p in
  62. p.print("if !isKnownUniquelyReferenced(&_storage) {")
  63. p.printIndented("_storage = _StorageClass(copying: _storage)")
  64. p.print(
  65. "}",
  66. "return _storage"
  67. )
  68. }
  69. p.print("}")
  70. }
  71. func generatePreTraverse(printer p: inout CodePrinter) {
  72. // Nothing
  73. }
  74. /// Generates the stored properties for the storage class.
  75. ///
  76. /// - Parameter p: The code printer.
  77. private func generateStoredProperties(printer p: inout CodePrinter) {
  78. for f in fields {
  79. f.generateStorage(printer: &p)
  80. }
  81. }
  82. /// Generates the `init(copying:)` method of the storage class.
  83. ///
  84. /// - Parameter p: The code printer.
  85. private func generateClone(printer p: inout CodePrinter) {
  86. p.print("init(copying source: _StorageClass) {")
  87. p.withIndentation { p in
  88. for f in fields {
  89. f.generateStorageClassClone(printer: &p)
  90. }
  91. }
  92. p.print("}")
  93. }
  94. }
  95. /// Custom generator for storage of an google.protobuf.Any.
  96. class AnyMessageStorageClassGenerator: MessageStorageClassGenerator {
  97. override var storageVisibility: String { "internal" }
  98. override var storageProvidesEqualTo: Bool { true }
  99. override func generateTypeDeclaration(printer p: inout CodePrinter) {
  100. // Just need an alias to the hand coded Storage.
  101. p.print("typealias _StorageClass = AnyMessageStorage")
  102. }
  103. override func generatePreTraverse(printer p: inout CodePrinter) {
  104. p.print("try _storage.preTraverse()")
  105. }
  106. }