Descriptor.swift 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  1. // Sources/SwiftProtobufPluginLibrary/Descriptor.swift - Descriptor wrappers
  2. //
  3. // Copyright (c) 2014 - 2017 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. /// This is like Descriptor.{h,cc} in the google/protobuf C++ code, it provides
  12. /// wrappers around the protos to make a more usable object graph for generation
  13. /// and also provides some SwiftProtobuf specific additions that would be useful
  14. /// to anyone generating something that uses SwiftProtobufs (like support the
  15. /// `service` messages). It is *not* the intent for these to eventually be used
  16. /// as part of some reflection or generate message api.
  17. ///
  18. // -----------------------------------------------------------------------------
  19. // NOTES:
  20. // 1. `lazy` and `weak` (or `unowned`) doesn't seem to work, so the impl here
  21. // can't simply keep the `Resolver` and look things up when first accessed
  22. // instead `bind()` is used to force those lookups to happen.
  23. // 2. Despite the Swift docs seeming to say `unowned` should work, there are
  24. // compile errors, `weak` ends up being used even though this code doesn't
  25. // need the zeroing behaviors. If it did, things will be a little faster
  26. // as the tracking for weak references wouldn't be needed.
  27. import Foundation
  28. import SwiftProtobuf
  29. public final class DescriptorSet {
  30. public let files: [FileDescriptor]
  31. private let registry = Registry()
  32. public convenience init(proto: Google_Protobuf_FileDescriptorSet) {
  33. self.init(protos: proto.file)
  34. }
  35. public init(protos: [Google_Protobuf_FileDescriptorProto]) {
  36. let registry = self.registry
  37. self.files = protos.map { return FileDescriptor(proto: $0, registry: registry) }
  38. }
  39. public func lookupFileDescriptor(protoName name: String) -> FileDescriptor {
  40. return registry.fileDescriptor(name: name)
  41. }
  42. public func lookupDescriptor(protoName name: String) -> Descriptor {
  43. return registry.descriptor(name: name)
  44. }
  45. public func lookupEnumDescriptor(protoName name: String) -> EnumDescriptor {
  46. return registry.enumDescriptor(name: name)
  47. }
  48. public func lookupServiceDescriptor(protoName name: String) -> ServiceDescriptor {
  49. return registry.serviceDescriptor(name: name)
  50. }
  51. /// Find a specific file. The names for files are what was captured in
  52. /// the `Google_Protobuf_FileDescriptorProto` when it was created, protoc
  53. /// uses the path name for how the file was found.
  54. public func fileDescriptor(named name: String) -> FileDescriptor? {
  55. return registry.fileDescriptor(named: name)
  56. }
  57. }
  58. public final class FileDescriptor {
  59. public enum Syntax: String {
  60. case proto2
  61. case proto3
  62. public init?(rawValue: String) {
  63. switch rawValue {
  64. case "proto2", "":
  65. self = .proto2
  66. case "proto3":
  67. self = .proto3
  68. default:
  69. return nil
  70. }
  71. }
  72. }
  73. public let proto: Google_Protobuf_FileDescriptorProto
  74. public var name: String { return proto.name }
  75. public var package: String { return proto.package }
  76. public let syntax: Syntax
  77. public let dependencies: [FileDescriptor]
  78. public var publicDependencies: [FileDescriptor] { return proto.publicDependency.map { dependencies[Int($0)] } }
  79. public var weakDependencies: [FileDescriptor] { return proto.weakDependency.map { dependencies[Int($0)] } }
  80. public let enums: [EnumDescriptor]
  81. public let messages: [Descriptor]
  82. public let extensions: [FieldDescriptor]
  83. public let services: [ServiceDescriptor]
  84. public var fileOptions: Google_Protobuf_FileOptions { return proto.options }
  85. public var isDeprecated: Bool { return proto.options.deprecated }
  86. fileprivate init(proto: Google_Protobuf_FileDescriptorProto, registry: Registry) {
  87. self.proto = proto
  88. self.syntax = Syntax(rawValue: proto.syntax)!
  89. let prefix: String
  90. let protoPackage = proto.package
  91. if protoPackage.isEmpty {
  92. prefix = ""
  93. } else {
  94. prefix = "." + protoPackage
  95. }
  96. self.enums = proto.enumType.enumeratedMap {
  97. return EnumDescriptor(proto: $1, index: $0, registry: registry, fullNamePrefix: prefix)
  98. }
  99. self.messages = proto.messageType.enumeratedMap {
  100. return Descriptor(proto: $1, index: $0, registry: registry, fullNamePrefix: prefix)
  101. }
  102. self.extensions = proto.extension.enumeratedMap {
  103. return FieldDescriptor(proto: $1, index: $0, registry: registry, isExtension: true)
  104. }
  105. self.services = proto.service.enumeratedMap {
  106. return ServiceDescriptor(proto: $1, index: $0, registry: registry, fullNamePrefix: prefix)
  107. }
  108. // The compiler ensures there aren't cycles between a file and dependencies, so
  109. // this doesn't run the risk of creating any retain cycles that would force these
  110. // to have to be weak.
  111. self.dependencies = proto.dependency.map { return registry.fileDescriptor(name: $0) }
  112. // Done initializing, register ourselves.
  113. registry.register(file: self)
  114. // descriptor.proto documents the files will be in deps order. That means we
  115. // any external reference will have been in the previous files in the set.
  116. self.enums.forEach { $0.bind(file: self, registry: registry, containingType: nil) }
  117. self.messages.forEach { $0.bind(file: self, registry: registry, containingType: nil) }
  118. self.extensions.forEach { $0.bind(file: self, registry: registry, containingType: nil) }
  119. self.services.forEach { $0.bind(file: self, registry: registry) }
  120. }
  121. public func sourceCodeInfoLocation(path: IndexPath) -> Google_Protobuf_SourceCodeInfo.Location? {
  122. guard let location = locationMap[path] else {
  123. return nil
  124. }
  125. return location
  126. }
  127. // Lazy so this can be computed on demand, as the imported files won't need
  128. // comments during generation.
  129. private lazy var locationMap: [IndexPath:Google_Protobuf_SourceCodeInfo.Location] = {
  130. var result: [IndexPath:Google_Protobuf_SourceCodeInfo.Location] = [:]
  131. for loc in self.proto.sourceCodeInfo.location {
  132. let intList = loc.path.map { return Int($0) }
  133. result[IndexPath(indexes: intList)] = loc
  134. }
  135. return result
  136. }()
  137. }
  138. public final class Descriptor {
  139. public let proto: Google_Protobuf_DescriptorProto
  140. let index: Int
  141. public let fullName: String
  142. public var name: String { return proto.name }
  143. public private(set) weak var file: FileDescriptor!
  144. public private(set) weak var containingType: Descriptor?
  145. public let enums: [EnumDescriptor]
  146. public let messages: [Descriptor]
  147. public let fields: [FieldDescriptor]
  148. public let oneofs: [OneofDescriptor]
  149. /// Non synthetic oneofs.
  150. ///
  151. /// These always come first (enforced by the C++ Descriptor code). So this is always a
  152. /// leading subset of `oneofs` (or the same if there are no synthetic entries).
  153. public private(set) lazy var realOneofs: [OneofDescriptor] = {
  154. // Lazy because `isSynthetic` can't be called until after `bind()`.
  155. return self.oneofs.filter { !$0.isSynthetic }
  156. }()
  157. public let extensions: [FieldDescriptor]
  158. public var extensionRanges: [Google_Protobuf_DescriptorProto.ExtensionRange] {
  159. return proto.extensionRange
  160. }
  161. /// The `extensionRanges` are in the order they appear in the original .proto
  162. /// file; this orders them and then merges any ranges that are actually
  163. /// contiguious (i.e. - [(21,30),(10,20)] -> [(10,30)])
  164. public private(set) lazy var normalizedExtensionRanges: [Google_Protobuf_DescriptorProto.ExtensionRange] = {
  165. var ordered = self.extensionRanges.sorted(by: { return $0.start < $1.start })
  166. if ordered.count > 1 {
  167. for i in (0..<(ordered.count - 1)).reversed() {
  168. if ordered[i].end == ordered[i+1].start {
  169. ordered[i].end = ordered[i+1].end
  170. ordered.remove(at: i + 1)
  171. }
  172. }
  173. }
  174. return ordered
  175. }()
  176. /// The `extensionRanges` from `normalizedExtensionRanges`, but takes a step
  177. /// further in that any ranges that do _not_ have any fields inbetween them
  178. /// are also merged together. These can then be used in context where it is
  179. /// ok to include field numbers that have to be extension or unknown fields.
  180. public private(set) lazy var ambitiousExtensionRanges: [Google_Protobuf_DescriptorProto.ExtensionRange] = {
  181. var merged = self.normalizedExtensionRanges
  182. var sortedFields = self.fields.sorted {$0.number < $1.number}
  183. if merged.count > 1 {
  184. var fieldNumbersReversedIterator =
  185. self.fields.map({ Int($0.number) }).sorted(by: { $0 > $1 }).makeIterator()
  186. var nextFieldNumber = fieldNumbersReversedIterator.next()
  187. while nextFieldNumber != nil && merged.last!.start < nextFieldNumber! {
  188. nextFieldNumber = fieldNumbersReversedIterator.next()
  189. }
  190. for i in (0..<(merged.count - 1)).reversed() {
  191. if nextFieldNumber == nil || merged[i].start > nextFieldNumber! {
  192. // No fields left or range starts after the next field, merge it with
  193. // the previous one.
  194. merged[i].end = merged[i+1].end
  195. merged.remove(at: i + 1)
  196. } else {
  197. // can't merge, find the next field number below this range.
  198. while nextFieldNumber != nil && merged[i].start < nextFieldNumber! {
  199. nextFieldNumber = fieldNumbersReversedIterator.next()
  200. }
  201. }
  202. }
  203. }
  204. return merged
  205. }()
  206. /// True/False if this Message is just for a `map<>` entry.
  207. public var isMapEntry: Bool { return proto.options.mapEntry }
  208. /// Returns the `FieldDescriptor`s for the "key" and "value" fields. If
  209. /// this isn't a map entry field, returns nil.
  210. public var mapKeyAndValue: (key: FieldDescriptor, value: FieldDescriptor)? {
  211. guard isMapEntry else { return nil }
  212. assert(fields.count == 2)
  213. return (key: fields[0], value: fields[1])
  214. }
  215. public var useMessageSetWireFormat: Bool { return proto.options.messageSetWireFormat }
  216. fileprivate init(proto: Google_Protobuf_DescriptorProto,
  217. index: Int,
  218. registry: Registry,
  219. fullNamePrefix prefix: String) {
  220. self.proto = proto
  221. self.index = index
  222. let fullName = "\(prefix).\(proto.name)"
  223. self.fullName = fullName
  224. self.enums = proto.enumType.enumeratedMap {
  225. return EnumDescriptor(proto: $1, index: $0, registry: registry, fullNamePrefix: fullName)
  226. }
  227. self.messages = proto.nestedType.enumeratedMap {
  228. return Descriptor(proto: $1, index: $0, registry: registry, fullNamePrefix: fullName)
  229. }
  230. self.fields = proto.field.enumeratedMap {
  231. return FieldDescriptor(proto: $1, index: $0, registry: registry)
  232. }
  233. self.oneofs = proto.oneofDecl.enumeratedMap {
  234. return OneofDescriptor(proto: $1, index: $0, registry: registry)
  235. }
  236. self.extensions = proto.extension.enumeratedMap {
  237. return FieldDescriptor(proto: $1, index: $0, registry: registry, isExtension: true)
  238. }
  239. // Done initializing, register ourselves.
  240. registry.register(message: self)
  241. }
  242. fileprivate func bind(file: FileDescriptor, registry: Registry, containingType: Descriptor?) {
  243. self.file = file
  244. self.containingType = containingType
  245. self.enums.forEach { $0.bind(file: file, registry: registry, containingType: self) }
  246. self.messages.forEach { $0.bind(file: file, registry: registry, containingType: self) }
  247. self.fields.forEach { $0.bind(file: file, registry: registry, containingType: self) }
  248. self.oneofs.forEach { $0.bind(registry: registry, containingType: self) }
  249. self.extensions.forEach { $0.bind(file: file, registry: registry, containingType: self) }
  250. // Synthetic oneofs come after normal oneofs. The C++ Descriptor enforces this, only
  251. // here as a secondary validation because other code can rely on it.
  252. var seenSynthetic = false
  253. for o in self.oneofs {
  254. if o.isSynthetic {
  255. seenSynthetic = true
  256. } else {
  257. assert(!seenSynthetic)
  258. }
  259. }
  260. }
  261. }
  262. public final class EnumDescriptor {
  263. public let proto: Google_Protobuf_EnumDescriptorProto
  264. let index: Int
  265. public let fullName: String
  266. public var name: String { return proto.name }
  267. public private(set) weak var file: FileDescriptor!
  268. public private(set) weak var containingType: Descriptor?
  269. // This is lazy so it is they are created only when needed, that way an
  270. // import doesn't have to do all this work unless the enum is used by
  271. // the importer.
  272. public private(set) lazy var values: [EnumValueDescriptor] = {
  273. var firstValues = [Int32:EnumValueDescriptor]()
  274. var result = [EnumValueDescriptor]()
  275. var i = 0
  276. for p in self.proto.value {
  277. let aliasing = firstValues[p.number]
  278. let d = EnumValueDescriptor(proto: p, index: i, enumType: self, aliasing: aliasing)
  279. result.append(d)
  280. i += 1
  281. if let aliasing = aliasing {
  282. aliasing.aliases.append(d)
  283. } else {
  284. firstValues[d.number] = d
  285. }
  286. }
  287. return result
  288. }()
  289. public var defaultValue: EnumValueDescriptor {
  290. // The compiler requires the be atleast one value, so force unwrap is safe.
  291. return values.first!
  292. }
  293. fileprivate init(proto: Google_Protobuf_EnumDescriptorProto,
  294. index: Int,
  295. registry: Registry,
  296. fullNamePrefix prefix: String) {
  297. self.proto = proto
  298. self.index = index
  299. self.fullName = "\(prefix).\(proto.name)"
  300. // Done initializing, register ourselves.
  301. registry.register(enum: self)
  302. }
  303. fileprivate func bind(file: FileDescriptor, registry: Registry, containingType: Descriptor?) {
  304. self.file = file
  305. self.containingType = containingType
  306. }
  307. }
  308. public final class EnumValueDescriptor {
  309. public let proto: Google_Protobuf_EnumValueDescriptorProto
  310. let index: Int
  311. public private(set) weak var enumType: EnumDescriptor!
  312. public weak var file: FileDescriptor! { return enumType.file }
  313. public var name: String { return proto.name }
  314. public var fullName: String
  315. public var number: Int32 { return proto.number }
  316. public private(set) weak var aliasOf: EnumValueDescriptor?
  317. public fileprivate(set) var aliases: [EnumValueDescriptor] = []
  318. fileprivate init(proto: Google_Protobuf_EnumValueDescriptorProto,
  319. index: Int,
  320. enumType: EnumDescriptor,
  321. aliasing: EnumValueDescriptor?) {
  322. self.proto = proto
  323. self.index = index
  324. self.enumType = enumType
  325. aliasOf = aliasing
  326. let fullName = "\(enumType.fullName).\(proto.name)"
  327. self.fullName = fullName
  328. }
  329. }
  330. public final class OneofDescriptor {
  331. public let proto: Google_Protobuf_OneofDescriptorProto
  332. let index: Int
  333. public private(set) weak var containingType: Descriptor!
  334. public weak var file: FileDescriptor! { return containingType.file }
  335. public var name: String { return proto.name }
  336. /// Returns whether this oneof was inserted by the compiler to wrap a proto3
  337. /// optional field. If this returns true, code generators should *not* emit it.
  338. public var isSynthetic: Bool {
  339. return fields.count == 1 && fields.first!.proto3Optional
  340. }
  341. public private(set) lazy var fields: [FieldDescriptor] = {
  342. let myIndex = Int32(self.index)
  343. return self.containingType.fields.filter { $0.oneofIndex == myIndex }
  344. }()
  345. fileprivate init(proto: Google_Protobuf_OneofDescriptorProto,
  346. index: Int,
  347. registry: Registry) {
  348. self.proto = proto
  349. self.index = index
  350. }
  351. fileprivate func bind(registry: Registry, containingType: Descriptor) {
  352. self.containingType = containingType
  353. }
  354. }
  355. public final class FieldDescriptor {
  356. public let proto: Google_Protobuf_FieldDescriptorProto
  357. let index: Int
  358. public private(set) weak var file: FileDescriptor!
  359. /// The Descriptor of the message which this is a field of. For extensions,
  360. /// this is the extended type.
  361. public private(set) weak var containingType: Descriptor!
  362. public var name: String { return proto.name }
  363. public var number: Int32 { return proto.number }
  364. public var label: Google_Protobuf_FieldDescriptorProto.Label { return proto.label }
  365. public var type: Google_Protobuf_FieldDescriptorProto.TypeEnum { return proto.type }
  366. var proto3Optional: Bool { return proto.proto3Optional }
  367. /// Returns true if this field was syntactically written with "optional" in the
  368. /// .proto file. Excludes singular proto3 fields that do not have a label.
  369. public var hasOptionalKeyword: Bool {
  370. return proto3Optional ||
  371. (file.syntax == .proto2 && label == .optional && oneofIndex == nil)
  372. }
  373. /// Returns true if this field tracks presence, ie. does the field
  374. /// distinguish between "unset" and "present with default value."
  375. /// This includes required, optional, and oneof fields. It excludes maps,
  376. /// repeated fields, and singular proto3 fields without "optional".
  377. public var hasPresence: Bool {
  378. guard label != .repeated else { return false }
  379. switch type {
  380. case .group, .message:
  381. // Groups/messages always get field presence.
  382. return true
  383. default:
  384. return file.syntax == .proto2 || oneofIndex != nil
  385. }
  386. }
  387. public var fullName: String {
  388. // Since the fullName isn't needed on Fields that often, compute it on demand.
  389. let prefix: String
  390. if isExtension {
  391. if let extensionScope = extensionScope {
  392. prefix = extensionScope.fullName
  393. } else {
  394. let package = file.package
  395. if package.isEmpty {
  396. prefix = ""
  397. } else {
  398. prefix = ".\(package)"
  399. }
  400. }
  401. } else {
  402. prefix = containingType.fullName
  403. }
  404. return "\(prefix).\(proto.name)"
  405. }
  406. public var jsonName: String? {
  407. guard proto.hasJsonName else { return nil }
  408. return proto.jsonName
  409. }
  410. /// The default value (string) set in the proto file.
  411. public var explicitDefaultValue: String? {
  412. if !proto.hasDefaultValue {
  413. return nil
  414. }
  415. return proto.defaultValue
  416. }
  417. /// True if this field is a map.
  418. public var isMap: Bool {
  419. // Maps are releated messages.
  420. if label != .repeated || type != .message {
  421. return false
  422. }
  423. return messageType.isMapEntry
  424. }
  425. /// If this is an extension field.
  426. public let isExtension: Bool
  427. /// Extensions can be declared within the scope of another message. If this
  428. /// is an extension field, then this will be the scope it was declared in
  429. /// nil if was declared at a global scope.
  430. public private(set) weak var extensionScope: Descriptor?
  431. /// The index in a oneof this field is in.
  432. public let oneofIndex: Int32?
  433. /// The oneof this field is a member of.
  434. public var oneof: OneofDescriptor? {
  435. guard let oneofIndex = oneofIndex else { return nil }
  436. assert(!isExtension)
  437. return containingType!.oneofs[Int(oneofIndex)]
  438. }
  439. /// The non synthetic oneof this field is a member of.
  440. public var realOneof: OneofDescriptor? {
  441. guard let oneof = oneof, !oneof.isSynthetic else { return nil }
  442. return oneof
  443. }
  444. /// When this is a message field, the message's desciptor.
  445. public private(set) weak var messageType: Descriptor!
  446. /// When this is a enum field, the enum's desciptor.
  447. public private(set) weak var enumType: EnumDescriptor!
  448. /// Should this field be packed format.
  449. public var isPacked: Bool {
  450. // NOTE: As of May 2017, the proto3 spec says:
  451. //
  452. // https://developers.google.com/protocol-buffers/docs/proto3#specifying-field-rules -
  453. // "In proto3, repeated fields of scalar numeric types use packed encoding by default."
  454. //
  455. // But this does not result in the field option for packed being set by protoc. Instead
  456. // there is some interesting logic in the C++ desciptor classes that causes the field
  457. // to be packed, but does leave the door open for it not to be backed. So the logic
  458. // here and in the helpers this cases duplicates that logic.
  459. // This logic comes from the C++ FieldDescriptor::is_packed() impl.
  460. guard isPackable else { return false }
  461. if file.syntax == .proto2 {
  462. return proto.hasOptions && proto.options.packed
  463. } else {
  464. return !proto.hasOptions || !proto.options.hasPacked || proto.options.packed
  465. }
  466. }
  467. public var options: Google_Protobuf_FieldOptions { return proto.options }
  468. fileprivate init(proto: Google_Protobuf_FieldDescriptorProto,
  469. index: Int,
  470. registry: Registry,
  471. isExtension: Bool = false) {
  472. self.proto = proto
  473. self.index = index
  474. self.isExtension = isExtension
  475. if proto.hasOneofIndex {
  476. assert(!isExtension)
  477. oneofIndex = proto.oneofIndex
  478. } else {
  479. oneofIndex = nil
  480. // FieldDescriptorProto is used for fields or extensions, generally
  481. // .proto3Optional only makes sense on fields if it is in a oneof. But
  482. // It is allowed on extensions. For information on that, see
  483. // https://github.com/protocolbuffers/protobuf/issues/8234#issuecomment-774224376
  484. // The C++ Descriptor code encorces the field/oneof part, but nothing
  485. // is checked on the oneof side.
  486. assert(!proto.proto3Optional || isExtension)
  487. }
  488. }
  489. fileprivate func bind(file: FileDescriptor, registry: Registry, containingType: Descriptor?) {
  490. self.file = file
  491. assert(isExtension == !proto.extendee.isEmpty)
  492. if isExtension {
  493. extensionScope = containingType
  494. self.containingType = registry.descriptor(name: proto.extendee)
  495. } else {
  496. self.containingType = containingType
  497. }
  498. switch type {
  499. case .group, .message:
  500. messageType = registry.descriptor(name: proto.typeName)
  501. case .enum:
  502. enumType = registry.enumDescriptor(name: proto.typeName)
  503. default:
  504. break
  505. }
  506. }
  507. }
  508. public final class ServiceDescriptor {
  509. public let proto: Google_Protobuf_ServiceDescriptorProto
  510. let index: Int
  511. public let fullName: String
  512. public var name: String { return proto.name }
  513. public private(set) weak var file: FileDescriptor!
  514. public let methods: [MethodDescriptor]
  515. fileprivate init(proto: Google_Protobuf_ServiceDescriptorProto,
  516. index: Int,
  517. registry: Registry,
  518. fullNamePrefix prefix: String) {
  519. self.proto = proto
  520. self.index = index
  521. let fullName = "\(prefix).\(proto.name)"
  522. self.fullName = fullName
  523. self.methods = proto.method.enumeratedMap {
  524. return MethodDescriptor(proto: $1, index: $0, registry: registry)
  525. }
  526. // Done initializing, register ourselves.
  527. registry.register(service: self)
  528. }
  529. fileprivate func bind(file: FileDescriptor, registry: Registry) {
  530. self.file = file
  531. methods.forEach { $0.bind(service: self, registry: registry) }
  532. }
  533. }
  534. public final class MethodDescriptor {
  535. public let proto: Google_Protobuf_MethodDescriptorProto
  536. let index: Int
  537. public private(set) weak var service: ServiceDescriptor!
  538. public weak var file: FileDescriptor! { return service.file }
  539. public var name: String { return proto.name }
  540. public private(set) var inputType: Descriptor!
  541. public private(set) var outputType: Descriptor!
  542. /// Whether the client streams multiple requests.
  543. public let clientStreaming: Bool
  544. // Whether the server streams multiple responses.
  545. public let serverStreaming: Bool
  546. fileprivate init(proto: Google_Protobuf_MethodDescriptorProto,
  547. index: Int,
  548. registry: Registry) {
  549. self.proto = proto
  550. self.index = index
  551. self.clientStreaming = proto.clientStreaming
  552. self.serverStreaming = proto.serverStreaming
  553. }
  554. fileprivate func bind(service: ServiceDescriptor, registry: Registry) {
  555. self.service = service
  556. inputType = registry.descriptor(name: proto.inputType)
  557. outputType = registry.descriptor(name: proto.outputType)
  558. }
  559. }
  560. /// Helper used under the hood to build the mapping tables and look things up.
  561. fileprivate final class Registry {
  562. private var fileMap = [String:FileDescriptor]()
  563. private var messageMap = [String:Descriptor]()
  564. private var enumMap = [String:EnumDescriptor]()
  565. private var serviceMap = [String:ServiceDescriptor]()
  566. init() {}
  567. func register(file: FileDescriptor) {
  568. fileMap[file.name] = file
  569. }
  570. func register(message: Descriptor) {
  571. messageMap[message.fullName] = message
  572. }
  573. func register(enum e: EnumDescriptor) {
  574. enumMap[e.fullName] = e
  575. }
  576. func register(service: ServiceDescriptor) {
  577. serviceMap[service.fullName] = service
  578. }
  579. // These are forced unwraps as the FileDescriptorSet should always be valid from protoc.
  580. func fileDescriptor(name: String) -> FileDescriptor {
  581. return fileMap[name]!
  582. }
  583. func descriptor(name: String) -> Descriptor {
  584. return messageMap[name]!
  585. }
  586. func enumDescriptor(name: String) -> EnumDescriptor {
  587. return enumMap[name]!
  588. }
  589. func serviceDescriptor(name: String) -> ServiceDescriptor {
  590. return serviceMap[name]!
  591. }
  592. func fileDescriptor(named name: String) -> FileDescriptor? {
  593. return fileMap[name]
  594. }
  595. }