| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483 |
- /*
- * Copyright 2023, gRPC Authors All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- /// Describes the services, dependencies and trivia from an IDL file,
- /// and the IDL itself through its specific serializer and deserializer.
- public struct CodeGenerationRequest {
- /// The name of the source file containing the IDL, including the extension if applicable.
- public var fileName: String
- /// Any comments at the top of the file such as documentation and copyright headers.
- /// They will be placed at the top of the generated file. They are already formatted,
- /// meaning they contain "///" and new lines.
- public var leadingTrivia: String
- /// The Swift imports that the generated file depends on. The gRPC specific imports aren't required
- /// as they will be added by default in the generated file.
- ///
- /// - SeeAlso: ``Dependency``.
- public var dependencies: [Dependency]
- /// A description of each service to generate.
- ///
- /// - SeeAlso: ``ServiceDescriptor``.
- public var services: [ServiceDescriptor]
- /// Closure that receives a message type as a `String` and returns a code snippet to
- /// initialise a `MessageSerializer` for that type as a `String`.
- ///
- /// The result is inserted in the generated code, where clients serialize RPC inputs and
- /// servers serialize RPC outputs.
- ///
- /// For example, to serialize Protobuf messages you could specify a serializer as:
- /// ```swift
- /// request.makeSerializerCodeSnippet = { messageType in
- /// "ProtobufSerializer<\(messageType)>()"
- /// }
- /// ```
- public var makeSerializerCodeSnippet: (_ messageType: String) -> String
- /// Closure that receives a message type as a `String` and returns a code snippet to
- /// initialize a `MessageDeserializer` for that type as a `String`.
- ///
- /// The result is inserted in the generated code, where clients deserialize RPC outputs and
- /// servers deserialize RPC inputs.
- ///
- /// For example, to serialize Protobuf messages you could specify a serializer as:
- /// ```swift
- /// request.makeDeserializerCodeSnippet = { messageType in
- /// "ProtobufDeserializer<\(messageType)>()"
- /// }
- /// ```
- public var makeDeserializerCodeSnippet: (_ messageType: String) -> String
- public init(
- fileName: String,
- leadingTrivia: String,
- dependencies: [Dependency],
- services: [ServiceDescriptor],
- makeSerializerCodeSnippet: @escaping (_ messageType: String) -> String,
- makeDeserializerCodeSnippet: @escaping (_ messageType: String) -> String
- ) {
- self.fileName = fileName
- self.leadingTrivia = leadingTrivia
- self.dependencies = dependencies
- self.services = services
- self.makeSerializerCodeSnippet = makeSerializerCodeSnippet
- self.makeDeserializerCodeSnippet = makeDeserializerCodeSnippet
- }
- }
- extension CodeGenerationRequest {
- @available(*, deprecated, renamed: "makeSerializerSnippet")
- public var lookupSerializer: (_ messageType: String) -> String {
- get { self.makeSerializerCodeSnippet }
- set { self.makeSerializerCodeSnippet = newValue }
- }
- @available(*, deprecated, renamed: "makeDeserializerSnippet")
- public var lookupDeserializer: (_ messageType: String) -> String {
- get { self.makeDeserializerCodeSnippet }
- set { self.makeDeserializerCodeSnippet = newValue }
- }
- @available(
- *,
- deprecated,
- renamed:
- "init(fileName:leadingTrivia:dependencies:services:lookupSerializer:lookupDeserializer:)"
- )
- public init(
- fileName: String,
- leadingTrivia: String,
- dependencies: [Dependency],
- services: [ServiceDescriptor],
- lookupSerializer: @escaping (String) -> String,
- lookupDeserializer: @escaping (String) -> String
- ) {
- self.init(
- fileName: fileName,
- leadingTrivia: leadingTrivia,
- dependencies: dependencies,
- services: services,
- makeSerializerCodeSnippet: lookupSerializer,
- makeDeserializerCodeSnippet: lookupDeserializer
- )
- }
- }
- /// Represents an import: a module or a specific item from a module.
- public struct Dependency: Equatable {
- /// If the dependency is an item, the property's value is the item representation.
- /// If the dependency is a module, this property is nil.
- public var item: Item?
- /// The access level to be included in imports of this dependency.
- public var accessLevel: CodeGenerator.Config.AccessLevel
- /// The name of the imported module or of the module an item is imported from.
- public var module: String
- /// The name of the private interface for an `@_spi` import.
- ///
- /// For example, if `spi` was "Secret" and the module name was "Foo" then the import
- /// would be `@_spi(Secret) import Foo`.
- public var spi: String?
- /// Requirements for the `@preconcurrency` attribute.
- public var preconcurrency: PreconcurrencyRequirement
- public init(
- item: Item? = nil,
- module: String,
- spi: String? = nil,
- preconcurrency: PreconcurrencyRequirement = .notRequired,
- accessLevel: CodeGenerator.Config.AccessLevel
- ) {
- self.item = item
- self.module = module
- self.spi = spi
- self.preconcurrency = preconcurrency
- self.accessLevel = accessLevel
- }
- /// Represents an item imported from a module.
- public struct Item: Equatable {
- /// The keyword that specifies the item's kind (e.g. `func`, `struct`).
- public var kind: Kind
- /// The name of the imported item.
- public var name: String
- public init(kind: Kind, name: String) {
- self.kind = kind
- self.name = name
- }
- /// Represents the imported item's kind.
- public struct Kind: Equatable {
- /// Describes the keyword associated with the imported item.
- internal enum Value: String {
- case `typealias`
- case `struct`
- case `class`
- case `enum`
- case `protocol`
- case `let`
- case `var`
- case `func`
- }
- internal var value: Value
- internal init(_ value: Value) {
- self.value = value
- }
- /// The imported item is a typealias.
- public static var `typealias`: Self {
- Self(.`typealias`)
- }
- /// The imported item is a struct.
- public static var `struct`: Self {
- Self(.`struct`)
- }
- /// The imported item is a class.
- public static var `class`: Self {
- Self(.`class`)
- }
- /// The imported item is an enum.
- public static var `enum`: Self {
- Self(.`enum`)
- }
- /// The imported item is a protocol.
- public static var `protocol`: Self {
- Self(.`protocol`)
- }
- /// The imported item is a let.
- public static var `let`: Self {
- Self(.`let`)
- }
- /// The imported item is a var.
- public static var `var`: Self {
- Self(.`var`)
- }
- /// The imported item is a function.
- public static var `func`: Self {
- Self(.`func`)
- }
- }
- }
- /// Describes any requirement for the `@preconcurrency` attribute.
- public struct PreconcurrencyRequirement: Equatable {
- internal enum Value: Equatable {
- case required
- case notRequired
- case requiredOnOS([String])
- }
- internal var value: Value
- internal init(_ value: Value) {
- self.value = value
- }
- /// The attribute is always required.
- public static var required: Self {
- Self(.required)
- }
- /// The attribute is not required.
- public static var notRequired: Self {
- Self(.notRequired)
- }
- /// The attribute is required only on the named operating systems.
- public static func requiredOnOS(_ OSs: [String]) -> PreconcurrencyRequirement {
- return Self(.requiredOnOS(OSs))
- }
- }
- }
- /// Represents a service described in an IDL file.
- public struct ServiceDescriptor: Hashable {
- /// Documentation from comments above the IDL service description.
- /// It is already formatted, meaning it contains "///" and new lines.
- public var documentation: String
- /// The name of the service.
- public var name: ServiceName
- /// A description of each method of a service.
- ///
- /// - SeeAlso: ``MethodDescriptor``.
- public var methods: [MethodDescriptor]
- public init(
- documentation: String,
- name: ServiceName,
- methods: [MethodDescriptor]
- ) {
- self.documentation = documentation
- self.name = name
- self.methods = methods
- }
- }
- extension ServiceDescriptor {
- @available(*, deprecated, renamed: "init(documentation:name:methods:)")
- public init(
- documentation: String,
- name: Name,
- namespace: Name,
- methods: [MethodDescriptor]
- ) {
- self.documentation = documentation
- self.methods = methods
- let identifier = namespace.base.isEmpty ? name.base : namespace.base + "." + name.base
- let typeName =
- namespace.generatedUpperCase.isEmpty
- ? name.generatedUpperCase
- : namespace.generatedUpperCase + "_" + name.generatedUpperCase
- let propertyName =
- namespace.generatedLowerCase.isEmpty
- ? name.generatedUpperCase
- : namespace.generatedLowerCase + "_" + name.generatedUpperCase
- self.name = ServiceName(
- identifyingName: identifier,
- typeName: typeName,
- propertyName: propertyName
- )
- }
- }
- /// Represents a method described in an IDL file.
- public struct MethodDescriptor: Hashable {
- /// Documentation from comments above the IDL method description.
- /// It is already formatted, meaning it contains "///" and new lines.
- public var documentation: String
- /// Method name in different formats.
- ///
- /// All properties of this object must be unique for each method
- /// from within a service.
- public var name: MethodName
- /// Identifies if the method is input streaming.
- public var isInputStreaming: Bool
- /// Identifies if the method is output streaming.
- public var isOutputStreaming: Bool
- /// The generated input type for the described method.
- public var inputType: String
- /// The generated output type for the described method.
- public var outputType: String
- public init(
- documentation: String,
- name: MethodName,
- isInputStreaming: Bool,
- isOutputStreaming: Bool,
- inputType: String,
- outputType: String
- ) {
- self.documentation = documentation
- self.name = name
- self.isInputStreaming = isInputStreaming
- self.isOutputStreaming = isOutputStreaming
- self.inputType = inputType
- self.outputType = outputType
- }
- }
- extension MethodDescriptor {
- @available(*, deprecated, message: "Use MethodName instead of Name")
- public init(
- documentation: String,
- name: Name,
- isInputStreaming: Bool,
- isOutputStreaming: Bool,
- inputType: String,
- outputType: String
- ) {
- self.documentation = documentation
- self.name = MethodName(
- identifyingName: name.base,
- typeName: name.generatedUpperCase,
- functionName: name.generatedLowerCase
- )
- self.isInputStreaming = isInputStreaming
- self.isOutputStreaming = isOutputStreaming
- self.inputType = inputType
- self.outputType = outputType
- }
- }
- public struct ServiceName: Hashable {
- /// The identifying name as used in the service/method descriptors including any namespace.
- ///
- /// This value is also used to identify the service to the remote peer, usually as part of the
- /// ":path" pseudoheader if doing gRPC over HTTP/2.
- ///
- /// If the service is declared in package "foo.bar" and the service is called "Baz" then this
- /// value should be "foo.bar.Baz".
- public var identifyingName: String
- /// The name as used on types including any namespace.
- ///
- /// This is used to generate a namespace for each service which contains a number of client and
- /// server protocols and concrete types.
- ///
- /// If the service is declared in package "foo.bar" and the service is called "Baz" then this
- /// value should be "Foo\_Bar\_Baz".
- public var typeName: String
- /// The name as used as a property.
- ///
- /// This is used to provide a convenience getter for a descriptor of the service.
- ///
- /// If the service is declared in package "foo.bar" and the service is called "Baz" then this
- /// value should be "foo\_bar\_Baz".
- public var propertyName: String
- public init(identifyingName: String, typeName: String, propertyName: String) {
- self.identifyingName = identifyingName
- self.typeName = typeName
- self.propertyName = propertyName
- }
- }
- public struct MethodName: Hashable {
- /// The identifying name as used in the service/method descriptors.
- ///
- /// This value is also used to identify the method to the remote peer, usually as part of the
- /// ":path" pseudoheader if doing gRPC over HTTP/2.
- ///
- /// This value typically starts with an uppercase character, for example "Get".
- public var identifyingName: String
- /// The name as used on types including any namespace.
- ///
- /// This is used to generate a namespace for each method which contains information about
- /// the method.
- ///
- /// This value typically starts with an uppercase character, for example "Get".
- public var typeName: String
- /// The name as used as a property.
- ///
- /// This value typically starts with an lowercase character, for example "get".
- public var functionName: String
- public init(identifyingName: String, typeName: String, functionName: String) {
- self.identifyingName = identifyingName
- self.typeName = typeName
- self.functionName = functionName
- }
- }
- /// Represents the name associated with a namespace, service or a method, in three different formats.
- @available(*, deprecated, message: "Use ServiceName/MethodName instead.")
- public struct Name: Hashable {
- /// The base name is the name used for the namespace/service/method in the IDL file, so it should follow
- /// the specific casing of the IDL.
- ///
- /// The base name is also used in the descriptors that identify a specific method or service :
- /// `<service_namespace_baseName>.<service_baseName>.<method_baseName>`.
- public var base: String
- /// The `generatedUpperCase` name is used in the generated code. It is expected
- /// to be the UpperCamelCase version of the base name
- ///
- /// For example, if `base` is "fooBar", then `generatedUpperCase` is "FooBar".
- public var generatedUpperCase: String
- /// The `generatedLowerCase` name is used in the generated code. It is expected
- /// to be the lowerCamelCase version of the base name
- ///
- /// For example, if `base` is "FooBar", then `generatedLowerCase` is "fooBar".
- public var generatedLowerCase: String
- public init(base: String, generatedUpperCase: String, generatedLowerCase: String) {
- self.base = base
- self.generatedUpperCase = generatedUpperCase
- self.generatedLowerCase = generatedLowerCase
- }
- }
- @available(*, deprecated, message: "Use ServiceName/MethodName instead.")
- extension Name {
- /// The base name replacing occurrences of "." with "_".
- ///
- /// For example, if `base` is "Foo.Bar", then `normalizedBase` is "Foo_Bar".
- public var normalizedBase: String {
- return self.base.replacing(".", with: "_")
- }
- }
|