ProtobufExtensions.swift 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. // ProtobufRuntime/Sources/Protobuf/ProtobufExtensions.swift - Extension support
  2. //
  3. // This source file is part of the Swift.org open source project
  4. //
  5. // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
  6. // Licensed under Apache License v2.0 with Runtime Library Exception
  7. //
  8. // See http://swift.org/LICENSE.txt for license information
  9. // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
  10. //
  11. // -----------------------------------------------------------------------------
  12. ///
  13. /// A 'Message Extension' is an immutable class object that describes
  14. /// a particular extension field, including string and number
  15. /// identifiers, serialization details, and the identity of the
  16. /// message that is being extended.
  17. ///
  18. // -----------------------------------------------------------------------------
  19. import Swift
  20. /// Note that the base ProtobufMessageExtension class has no generic
  21. /// pieces, which allows us to construct dictionaries of
  22. /// ProtobufMessageExtension-typed objects.
  23. public class ProtobufMessageExtension {
  24. public let protoFieldNumber: Int
  25. public let protoFieldName: String
  26. public let jsonFieldName: String
  27. public let swiftFieldName: String
  28. public let messageType: ProtobufMessage.Type
  29. init(protoFieldNumber: Int, protoFieldName: String, jsonFieldName: String, swiftFieldName: String, messageType: ProtobufMessage.Type) {
  30. self.protoFieldNumber = protoFieldNumber
  31. self.protoFieldName = protoFieldName
  32. self.jsonFieldName = jsonFieldName
  33. self.swiftFieldName = swiftFieldName
  34. self.messageType = messageType
  35. }
  36. public func newField() -> ProtobufExtensionField {
  37. fatalError("newField() -> ProtobufExtensionField must always be overridden.")
  38. }
  39. }
  40. public func ==(lhs: ProtobufMessageExtension, rhs: ProtobufMessageExtension) -> Bool {
  41. return lhs.protoFieldNumber == rhs.protoFieldNumber
  42. }
  43. /// A "Generic Message Extension" augments the base Extension type
  44. /// with generic information about the type of the message being
  45. /// extended. These generic constrints enable compile-time checks on
  46. /// compatibility.
  47. public class ProtobufGenericMessageExtension<FieldType: ProtobufTypedExtensionField, MessageType: ProtobufMessage>: ProtobufMessageExtension {
  48. public init(protoFieldNumber: Int, protoFieldName: String, jsonFieldName: String, swiftFieldName: String, defaultValue: FieldType.ValueType) {
  49. self.defaultValue = defaultValue
  50. super.init(protoFieldNumber: protoFieldNumber, protoFieldName: protoFieldName, jsonFieldName: jsonFieldName, swiftFieldName: swiftFieldName, messageType: MessageType.self)
  51. }
  52. public let defaultValue: FieldType.ValueType
  53. public func set(value: FieldType.ValueType) -> ProtobufExtensionField {
  54. var f = FieldType(protobufExtension: self)
  55. f.value = value
  56. return f
  57. }
  58. override public func newField() -> ProtobufExtensionField {
  59. return FieldType(protobufExtension: self)
  60. }
  61. }
  62. // Messages that support extensions implement this protocol
  63. public protocol ProtobufExtensibleMessage: ProtobufMessage {
  64. mutating func setExtensionValue<F: ProtobufExtensionField>(ext: ProtobufGenericMessageExtension<F, Self>, value: F.ValueType)
  65. mutating func getExtensionValue<F: ProtobufExtensionField>(ext: ProtobufGenericMessageExtension<F, Self>) -> F.ValueType
  66. }
  67. // Backwards compatibility shim: Remove in August 2016
  68. public typealias ProtobufExtensibleMessageType = ProtobufExtensibleMessage
  69. // Common support for storage classes to handle extension fields
  70. public protocol ProtobufExtensibleMessageStorage: class {
  71. associatedtype ProtobufExtendedMessage: ProtobufMessage
  72. var extensionFieldValues: ProtobufExtensionFieldValueSet {get set}
  73. func setExtensionValue<F: ProtobufExtensionField>(ext: ProtobufGenericMessageExtension<F, ProtobufExtendedMessage>, value: F.ValueType)
  74. func getExtensionValue<F: ProtobufExtensionField>(ext: ProtobufGenericMessageExtension<F, ProtobufExtendedMessage>) -> F.ValueType
  75. }
  76. // Backwards compatibility shim: Remove in August 2016
  77. public typealias ProtobufExtensibleMessageStorageType = ProtobufExtensibleMessageStorage
  78. public extension ProtobufExtensibleMessageStorage {
  79. public func setExtensionValue<F: ProtobufExtensionField>(ext: ProtobufGenericMessageExtension<F, ProtobufExtendedMessage>, value: F.ValueType) {
  80. extensionFieldValues[ext.protoFieldNumber] = ext.set(value: value)
  81. }
  82. public func getExtensionValue<F: ProtobufExtensionField>(ext: ProtobufGenericMessageExtension<F, ProtobufExtendedMessage>) -> F.ValueType {
  83. if let fieldValue = extensionFieldValues[ext.protoFieldNumber] as? F {
  84. return fieldValue.value
  85. }
  86. return ext.defaultValue
  87. }
  88. }
  89. ///
  90. /// A set of extensions that can be passed into deserializers
  91. /// to provide details of the particular extensions that should
  92. /// be recognized.
  93. ///
  94. // TODO: Make this more Set-like
  95. // Note: The generated code only relies on ExpressibleByArrayLiteral
  96. public struct ProtobufExtensionSet: CustomDebugStringConvertible, ExpressibleByArrayLiteral {
  97. public typealias Element = ProtobufMessageExtension
  98. // Since type objects aren't Hashable, we can't do much better than this...
  99. private var fields = [Int: Array<(ProtobufMessage.Type, ProtobufMessageExtension)>]()
  100. public init() {}
  101. public init(arrayLiteral: Element...) {
  102. insert(contentsOf: arrayLiteral)
  103. }
  104. public subscript(messageType: ProtobufMessage.Type, protoFieldNumber: Int) -> ProtobufMessageExtension? {
  105. get {
  106. if let l = fields[protoFieldNumber] {
  107. for (t, e) in l {
  108. if t == messageType {
  109. return e
  110. }
  111. }
  112. }
  113. return nil
  114. }
  115. set(newValue) {
  116. if let l = fields[protoFieldNumber] {
  117. var newL = l.flatMap {
  118. pair -> (ProtobufMessage.Type, ProtobufMessageExtension)? in
  119. if pair.0 == messageType { return nil }
  120. else { return pair }
  121. }
  122. if let newValue = newValue {
  123. newL.append((messageType, newValue))
  124. fields[protoFieldNumber] = newL
  125. }
  126. fields[protoFieldNumber] = newL
  127. } else if let newValue = newValue {
  128. fields[protoFieldNumber] = [(messageType, newValue)]
  129. }
  130. }
  131. }
  132. public func fieldNumberForJson(messageType: ProtobufJSONMessageBase.Type, jsonFieldName: String) -> Int? {
  133. // TODO: Make this faster...
  134. for (_, list) in fields {
  135. for (_, e) in list {
  136. if e.jsonFieldName == jsonFieldName {
  137. return e.protoFieldNumber
  138. }
  139. }
  140. }
  141. return nil
  142. }
  143. public mutating func insert(_ e: Element) {
  144. self[e.messageType, e.protoFieldNumber] = e
  145. }
  146. public var debugDescription: String {
  147. var names = [String]()
  148. for (_, list) in fields {
  149. for (_, e) in list {
  150. names.append("\(e.protoFieldName)(\(e.protoFieldNumber))")
  151. }
  152. }
  153. let d = names.joined(separator: ",")
  154. return "ProtobufExtensionSet(\(d))"
  155. }
  156. public mutating func unionInPlace(_ contentsOf: ProtobufExtensionSet) {
  157. for (_, list) in contentsOf.fields {
  158. for (_, e) in list {
  159. insert(e)
  160. }
  161. }
  162. }
  163. public mutating func insert(contentsOf: [Element]) {
  164. for e in contentsOf {
  165. insert(e)
  166. }
  167. }
  168. }
  169. /// A collection of extension field values on a particular object.
  170. /// This is only used within messages to manage the values of extension fields;
  171. /// it does not need to be very sophisticated.
  172. public struct ProtobufExtensionFieldValueSet: Equatable, Sequence {
  173. public typealias Iterator = Dictionary<Int, ProtobufExtensionField>.Iterator
  174. fileprivate var values = [Int : ProtobufExtensionField]()
  175. public init() {}
  176. public func makeIterator() -> Iterator {
  177. return values.makeIterator()
  178. }
  179. public var isEmpty: Bool {
  180. for (_, value) in values {
  181. if !value.isEmpty {
  182. return false
  183. }
  184. }
  185. return true
  186. }
  187. public var hashValue: Int {
  188. var hash: Int = 0
  189. for i in values.keys.sorted() {
  190. hash = (hash &* 16777619) ^ values[i]!.hashValue
  191. }
  192. return hash
  193. }
  194. public func traverse(visitor: inout ProtobufVisitor, start: Int, end: Int) throws {
  195. let validIndexes = values.keys.filter {$0 >= start && $0 < end}
  196. for i in validIndexes.sorted() {
  197. let value = values[i]!
  198. try value.traverse(visitor: &visitor)
  199. }
  200. }
  201. public subscript(index: Int) -> ProtobufExtensionField? {
  202. get {return values[index]}
  203. set(newValue) {values[index] = newValue}
  204. }
  205. }
  206. public func ==(lhs: ProtobufExtensionFieldValueSet, rhs: ProtobufExtensionFieldValueSet) -> Bool {
  207. for (index, l) in lhs.values {
  208. if let r = rhs.values[index] {
  209. if type(of: l) != type(of: r) {
  210. return false
  211. }
  212. if !l.isEqual(other: r) {
  213. return false
  214. }
  215. } else {
  216. return false
  217. }
  218. }
  219. for (index, r) in rhs.values {
  220. if let _ = lhs.values[index] {
  221. // already checked above
  222. } else if !r.isEmpty {
  223. // in r but not l: okay if r is empty
  224. return false
  225. }
  226. }
  227. return true
  228. }