CodeGenerationRequest.swift 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. /*
  2. * Copyright 2023, gRPC Authors All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /// Describes the services, dependencies and trivia from an IDL file,
  17. /// and the IDL itself through its specific serializer and deserializer.
  18. @available(gRPCSwift 2.0, *)
  19. public struct CodeGenerationRequest {
  20. /// The name of the source file containing the IDL, including the extension if applicable.
  21. public var fileName: String
  22. /// Any comments at the top of the file such as documentation and copyright headers.
  23. /// They will be placed at the top of the generated file. They are already formatted,
  24. /// meaning they contain "///" and new lines.
  25. public var leadingTrivia: String
  26. /// The Swift imports that the generated file depends on. The gRPC specific imports aren't required
  27. /// as they will be added by default in the generated file.
  28. ///
  29. /// - SeeAlso: ``Dependency``.
  30. public var dependencies: [Dependency]
  31. /// A description of each service to generate.
  32. ///
  33. /// - SeeAlso: ``ServiceDescriptor``.
  34. public var services: [ServiceDescriptor]
  35. /// Closure that receives a message type as a `String` and returns a code snippet to
  36. /// initialise a `MessageSerializer` for that type as a `String`.
  37. ///
  38. /// The result is inserted in the generated code, where clients serialize RPC inputs and
  39. /// servers serialize RPC outputs.
  40. ///
  41. /// For example, to serialize Protobuf messages you could specify a serializer as:
  42. /// ```swift
  43. /// request.makeSerializerCodeSnippet = { messageType in
  44. /// "ProtobufSerializer<\(messageType)>()"
  45. /// }
  46. /// ```
  47. public var makeSerializerCodeSnippet: (_ messageType: String) -> String
  48. /// Closure that receives a message type as a `String` and returns a code snippet to
  49. /// initialize a `MessageDeserializer` for that type as a `String`.
  50. ///
  51. /// The result is inserted in the generated code, where clients deserialize RPC outputs and
  52. /// servers deserialize RPC inputs.
  53. ///
  54. /// For example, to serialize Protobuf messages you could specify a serializer as:
  55. /// ```swift
  56. /// request.makeDeserializerCodeSnippet = { messageType in
  57. /// "ProtobufDeserializer<\(messageType)>()"
  58. /// }
  59. /// ```
  60. public var makeDeserializerCodeSnippet: (_ messageType: String) -> String
  61. public init(
  62. fileName: String,
  63. leadingTrivia: String,
  64. dependencies: [Dependency],
  65. services: [ServiceDescriptor],
  66. makeSerializerCodeSnippet: @escaping (_ messageType: String) -> String,
  67. makeDeserializerCodeSnippet: @escaping (_ messageType: String) -> String
  68. ) {
  69. self.fileName = fileName
  70. self.leadingTrivia = leadingTrivia
  71. self.dependencies = dependencies
  72. self.services = services
  73. self.makeSerializerCodeSnippet = makeSerializerCodeSnippet
  74. self.makeDeserializerCodeSnippet = makeDeserializerCodeSnippet
  75. }
  76. }
  77. @available(gRPCSwift 2.0, *)
  78. extension CodeGenerationRequest {
  79. @available(*, deprecated, renamed: "makeSerializerSnippet")
  80. public var lookupSerializer: (_ messageType: String) -> String {
  81. get { self.makeSerializerCodeSnippet }
  82. set { self.makeSerializerCodeSnippet = newValue }
  83. }
  84. @available(*, deprecated, renamed: "makeDeserializerSnippet")
  85. public var lookupDeserializer: (_ messageType: String) -> String {
  86. get { self.makeDeserializerCodeSnippet }
  87. set { self.makeDeserializerCodeSnippet = newValue }
  88. }
  89. @available(
  90. *,
  91. deprecated,
  92. renamed:
  93. "init(fileName:leadingTrivia:dependencies:services:lookupSerializer:lookupDeserializer:)"
  94. )
  95. public init(
  96. fileName: String,
  97. leadingTrivia: String,
  98. dependencies: [Dependency],
  99. services: [ServiceDescriptor],
  100. lookupSerializer: @escaping (String) -> String,
  101. lookupDeserializer: @escaping (String) -> String
  102. ) {
  103. self.init(
  104. fileName: fileName,
  105. leadingTrivia: leadingTrivia,
  106. dependencies: dependencies,
  107. services: services,
  108. makeSerializerCodeSnippet: lookupSerializer,
  109. makeDeserializerCodeSnippet: lookupDeserializer
  110. )
  111. }
  112. }
  113. /// Represents an import: a module or a specific item from a module.
  114. @available(gRPCSwift 2.0, *)
  115. public struct Dependency: Equatable {
  116. /// If the dependency is an item, the property's value is the item representation.
  117. /// If the dependency is a module, this property is nil.
  118. public var item: Item?
  119. /// The access level to be included in imports of this dependency.
  120. public var accessLevel: CodeGenerator.Config.AccessLevel
  121. /// The name of the imported module or of the module an item is imported from.
  122. public var module: String
  123. /// The name of the private interface for an `@_spi` import.
  124. ///
  125. /// For example, if `spi` was "Secret" and the module name was "Foo" then the import
  126. /// would be `@_spi(Secret) import Foo`.
  127. public var spi: String?
  128. /// Requirements for the `@preconcurrency` attribute.
  129. public var preconcurrency: PreconcurrencyRequirement
  130. public init(
  131. item: Item? = nil,
  132. module: String,
  133. spi: String? = nil,
  134. preconcurrency: PreconcurrencyRequirement = .notRequired,
  135. accessLevel: CodeGenerator.Config.AccessLevel
  136. ) {
  137. self.item = item
  138. self.module = module
  139. self.spi = spi
  140. self.preconcurrency = preconcurrency
  141. self.accessLevel = accessLevel
  142. }
  143. /// Represents an item imported from a module.
  144. public struct Item: Equatable {
  145. /// The keyword that specifies the item's kind (e.g. `func`, `struct`).
  146. public var kind: Kind
  147. /// The name of the imported item.
  148. public var name: String
  149. public init(kind: Kind, name: String) {
  150. self.kind = kind
  151. self.name = name
  152. }
  153. /// Represents the imported item's kind.
  154. public struct Kind: Equatable {
  155. /// Describes the keyword associated with the imported item.
  156. internal enum Value: String {
  157. case `typealias`
  158. case `struct`
  159. case `class`
  160. case `enum`
  161. case `protocol`
  162. case `let`
  163. case `var`
  164. case `func`
  165. }
  166. internal var value: Value
  167. internal init(_ value: Value) {
  168. self.value = value
  169. }
  170. /// The imported item is a typealias.
  171. public static var `typealias`: Self {
  172. Self(.`typealias`)
  173. }
  174. /// The imported item is a struct.
  175. public static var `struct`: Self {
  176. Self(.`struct`)
  177. }
  178. /// The imported item is a class.
  179. public static var `class`: Self {
  180. Self(.`class`)
  181. }
  182. /// The imported item is an enum.
  183. public static var `enum`: Self {
  184. Self(.`enum`)
  185. }
  186. /// The imported item is a protocol.
  187. public static var `protocol`: Self {
  188. Self(.`protocol`)
  189. }
  190. /// The imported item is a let.
  191. public static var `let`: Self {
  192. Self(.`let`)
  193. }
  194. /// The imported item is a var.
  195. public static var `var`: Self {
  196. Self(.`var`)
  197. }
  198. /// The imported item is a function.
  199. public static var `func`: Self {
  200. Self(.`func`)
  201. }
  202. }
  203. }
  204. /// Describes any requirement for the `@preconcurrency` attribute.
  205. public struct PreconcurrencyRequirement: Equatable {
  206. internal enum Value: Equatable {
  207. case required
  208. case notRequired
  209. case requiredOnOS([String])
  210. }
  211. internal var value: Value
  212. internal init(_ value: Value) {
  213. self.value = value
  214. }
  215. /// The attribute is always required.
  216. public static var required: Self {
  217. Self(.required)
  218. }
  219. /// The attribute is not required.
  220. public static var notRequired: Self {
  221. Self(.notRequired)
  222. }
  223. /// The attribute is required only on the named operating systems.
  224. public static func requiredOnOS(_ OSs: [String]) -> PreconcurrencyRequirement {
  225. return Self(.requiredOnOS(OSs))
  226. }
  227. }
  228. }
  229. /// Represents a service described in an IDL file.
  230. @available(gRPCSwift 2.0, *)
  231. public struct ServiceDescriptor: Hashable {
  232. /// Documentation from comments above the IDL service description.
  233. /// It is already formatted, meaning it contains "///" and new lines.
  234. public var documentation: String
  235. /// The name of the service.
  236. public var name: ServiceName
  237. /// A description of each method of a service.
  238. ///
  239. /// - SeeAlso: ``MethodDescriptor``.
  240. public var methods: [MethodDescriptor]
  241. public init(
  242. documentation: String,
  243. name: ServiceName,
  244. methods: [MethodDescriptor]
  245. ) {
  246. self.documentation = documentation
  247. self.name = name
  248. self.methods = methods
  249. }
  250. }
  251. @available(gRPCSwift 2.0, *)
  252. extension ServiceDescriptor {
  253. @available(*, deprecated, renamed: "init(documentation:name:methods:)")
  254. public init(
  255. documentation: String,
  256. name: Name,
  257. namespace: Name,
  258. methods: [MethodDescriptor]
  259. ) {
  260. self.documentation = documentation
  261. self.methods = methods
  262. let identifier = namespace.base.isEmpty ? name.base : namespace.base + "." + name.base
  263. let typeName =
  264. namespace.generatedUpperCase.isEmpty
  265. ? name.generatedUpperCase
  266. : namespace.generatedUpperCase + "_" + name.generatedUpperCase
  267. let propertyName =
  268. namespace.generatedLowerCase.isEmpty
  269. ? name.generatedUpperCase
  270. : namespace.generatedLowerCase + "_" + name.generatedUpperCase
  271. self.name = ServiceName(
  272. identifyingName: identifier,
  273. typeName: typeName,
  274. propertyName: propertyName
  275. )
  276. }
  277. }
  278. /// Represents a method described in an IDL file.
  279. @available(gRPCSwift 2.0, *)
  280. public struct MethodDescriptor: Hashable {
  281. /// Documentation from comments above the IDL method description.
  282. /// It is already formatted, meaning it contains "///" and new lines.
  283. public var documentation: String
  284. /// Method name in different formats.
  285. ///
  286. /// All properties of this object must be unique for each method
  287. /// from within a service.
  288. public var name: MethodName
  289. /// Identifies if the method is input streaming.
  290. public var isInputStreaming: Bool
  291. /// Identifies if the method is output streaming.
  292. public var isOutputStreaming: Bool
  293. /// The generated input type for the described method.
  294. public var inputType: String
  295. /// The generated output type for the described method.
  296. public var outputType: String
  297. public init(
  298. documentation: String,
  299. name: MethodName,
  300. isInputStreaming: Bool,
  301. isOutputStreaming: Bool,
  302. inputType: String,
  303. outputType: String
  304. ) {
  305. self.documentation = documentation
  306. self.name = name
  307. self.isInputStreaming = isInputStreaming
  308. self.isOutputStreaming = isOutputStreaming
  309. self.inputType = inputType
  310. self.outputType = outputType
  311. }
  312. }
  313. @available(gRPCSwift 2.0, *)
  314. extension MethodDescriptor {
  315. @available(*, deprecated, message: "Use MethodName instead of Name")
  316. public init(
  317. documentation: String,
  318. name: Name,
  319. isInputStreaming: Bool,
  320. isOutputStreaming: Bool,
  321. inputType: String,
  322. outputType: String
  323. ) {
  324. self.documentation = documentation
  325. self.name = MethodName(
  326. identifyingName: name.base,
  327. typeName: name.generatedUpperCase,
  328. functionName: name.generatedLowerCase
  329. )
  330. self.isInputStreaming = isInputStreaming
  331. self.isOutputStreaming = isOutputStreaming
  332. self.inputType = inputType
  333. self.outputType = outputType
  334. }
  335. }
  336. @available(gRPCSwift 2.0, *)
  337. public struct ServiceName: Hashable {
  338. /// The identifying name as used in the service/method descriptors including any namespace.
  339. ///
  340. /// This value is also used to identify the service to the remote peer, usually as part of the
  341. /// ":path" pseudoheader if doing gRPC over HTTP/2.
  342. ///
  343. /// If the service is declared in package "foo.bar" and the service is called "Baz" then this
  344. /// value should be "foo.bar.Baz".
  345. public var identifyingName: String
  346. /// The name as used on types including any namespace.
  347. ///
  348. /// This is used to generate a namespace for each service which contains a number of client and
  349. /// server protocols and concrete types.
  350. ///
  351. /// If the service is declared in package "foo.bar" and the service is called "Baz" then this
  352. /// value should be "Foo\_Bar\_Baz".
  353. public var typeName: String
  354. /// The name as used as a property.
  355. ///
  356. /// This is used to provide a convenience getter for a descriptor of the service.
  357. ///
  358. /// If the service is declared in package "foo.bar" and the service is called "Baz" then this
  359. /// value should be "foo\_bar\_Baz".
  360. public var propertyName: String
  361. public init(identifyingName: String, typeName: String, propertyName: String) {
  362. self.identifyingName = identifyingName
  363. self.typeName = typeName
  364. self.propertyName = propertyName
  365. }
  366. }
  367. @available(gRPCSwift 2.0, *)
  368. public struct MethodName: Hashable {
  369. /// The identifying name as used in the service/method descriptors.
  370. ///
  371. /// This value is also used to identify the method to the remote peer, usually as part of the
  372. /// ":path" pseudoheader if doing gRPC over HTTP/2.
  373. ///
  374. /// This value typically starts with an uppercase character, for example "Get".
  375. public var identifyingName: String
  376. /// The name as used on types including any namespace.
  377. ///
  378. /// This is used to generate a namespace for each method which contains information about
  379. /// the method.
  380. ///
  381. /// This value typically starts with an uppercase character, for example "Get".
  382. public var typeName: String
  383. /// The name as used as a property.
  384. ///
  385. /// This value typically starts with an lowercase character, for example "get".
  386. public var functionName: String
  387. public init(identifyingName: String, typeName: String, functionName: String) {
  388. self.identifyingName = identifyingName
  389. self.typeName = typeName
  390. self.functionName = functionName
  391. }
  392. }
  393. /// Represents the name associated with a namespace, service or a method, in three different formats.
  394. @available(*, deprecated, message: "Use ServiceName/MethodName instead.")
  395. @available(gRPCSwift 2.0, *)
  396. public struct Name: Hashable {
  397. /// The base name is the name used for the namespace/service/method in the IDL file, so it should follow
  398. /// the specific casing of the IDL.
  399. ///
  400. /// The base name is also used in the descriptors that identify a specific method or service :
  401. /// `<service_namespace_baseName>.<service_baseName>.<method_baseName>`.
  402. public var base: String
  403. /// The `generatedUpperCase` name is used in the generated code. It is expected
  404. /// to be the UpperCamelCase version of the base name
  405. ///
  406. /// For example, if `base` is "fooBar", then `generatedUpperCase` is "FooBar".
  407. public var generatedUpperCase: String
  408. /// The `generatedLowerCase` name is used in the generated code. It is expected
  409. /// to be the lowerCamelCase version of the base name
  410. ///
  411. /// For example, if `base` is "FooBar", then `generatedLowerCase` is "fooBar".
  412. public var generatedLowerCase: String
  413. public init(base: String, generatedUpperCase: String, generatedLowerCase: String) {
  414. self.base = base
  415. self.generatedUpperCase = generatedUpperCase
  416. self.generatedLowerCase = generatedLowerCase
  417. }
  418. }
  419. @available(*, deprecated, message: "Use ServiceName/MethodName instead.")
  420. @available(gRPCSwift 2.0, *)
  421. extension Name {
  422. /// The base name replacing occurrences of "." with "_".
  423. ///
  424. /// For example, if `base` is "Foo.Bar", then `normalizedBase` is "Foo_Bar".
  425. public var normalizedBase: String {
  426. return self.base.replacing(".", with: "_")
  427. }
  428. }