Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions Sources/GRPCCodeGen/Internal/Renderer/TextBasedRenderer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,8 @@ struct TextBasedRenderer: RendererProtocol {
renderCommentableDeclaration(comment: comment, declaration: nestedDeclaration)
case let .deprecated(deprecation, nestedDeclaration):
renderDeprecatedDeclaration(deprecation: deprecation, declaration: nestedDeclaration)
case let .guarded(availability, nestedDeclaration):
renderGuardedDeclaration(availability: availability, declaration: nestedDeclaration)
case .variable(let variableDescription): renderVariable(variableDescription)
case .extension(let extensionDescription): renderExtension(extensionDescription)
case .struct(let structDescription): renderStruct(structDescription)
Expand Down Expand Up @@ -1074,6 +1076,21 @@ struct TextBasedRenderer: RendererProtocol {
writer.writeLine(line)
}

/// Renders the specified declaration with an availability guard annotation.
func renderGuardedDeclaration(availability: AvailabilityDescription, declaration: Declaration) {
renderAvailability(availability)
renderDeclaration(declaration)
}
Comment on lines +1080 to +1083
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a test to the TextBasedRendererTests for this?


func renderAvailability(_ availability: AvailabilityDescription) {
var line = "@available("
for osVersion in availability.osVersions {
line.append("\(osVersion.os.name) \(osVersion.version), ")
}
line.append("*)")
writer.writeLine(line)
}

/// Renders the specified code block item.
func renderCodeBlockItem(_ description: CodeBlockItem) {
switch description {
Expand Down
43 changes: 43 additions & 0 deletions Sources/GRPCCodeGen/Internal/StructuredSwiftRepresentation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -764,6 +764,9 @@ indirect enum Declaration: Equatable, Codable {
/// A declaration that adds a comment on top of the provided declaration.
case deprecated(DeprecationDescription, Declaration)

/// A declaration that adds an availability guard on top of the provided declaration.
case guarded(AvailabilityDescription, Declaration)

/// A variable declaration.
case variable(VariableDescription)

Expand Down Expand Up @@ -801,6 +804,42 @@ struct DeprecationDescription: Equatable, Codable {
var renamed: String?
}

/// A description of an availability guard.
///
/// For example: `@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)`
struct AvailabilityDescription: Equatable, Codable {
/// The array of OSes and versions which are specified in the availability guard.
var osVersions: [OSVersion]
init(osVersions: [OSVersion]) {
self.osVersions = osVersions
}

/// An OS and its version.
struct OSVersion: Equatable, Codable {
var os: OS
var version: String
init(os: OS, version: String) {
self.os = os
self.version = version
}
}

/// One of the possible OSes.
// swift-format-ignore: DontRepeatTypeInStaticProperties
struct OS: Equatable, Codable {
var name: String

init(name: String) {
self.name = name
}

static let macOS = Self(name: "macOS")
static let iOS = Self(name: "iOS")
static let watchOS = Self(name: "watchOS")
static let tvOS = Self(name: "tvOS")
}
}

/// A description of an assignment expression.
///
/// For example: `foo = 42`.
Expand Down Expand Up @@ -1803,6 +1842,7 @@ extension Declaration {
switch self {
case .commentable(_, let declaration): return declaration.accessModifier
case .deprecated(_, let declaration): return declaration.accessModifier
case .guarded(_, let declaration): return declaration.accessModifier
case .variable(let variableDescription): return variableDescription.accessModifier
case .extension(let extensionDescription): return extensionDescription.accessModifier
case .struct(let structDescription): return structDescription.accessModifier
Expand All @@ -1821,6 +1861,9 @@ extension Declaration {
case .deprecated(let deprecationDescription, var declaration):
declaration.accessModifier = newValue
self = .deprecated(deprecationDescription, declaration)
case .guarded(let availability, var declaration):
declaration.accessModifier = newValue
self = .guarded(availability, declaration)
case .variable(var variableDescription):
variableDescription.accessModifier = newValue
self = .variable(variableDescription)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,12 +332,15 @@ extension ClientCodeTranslator {
)
}

return .struct(
StructDescription(
accessModifier: self.accessModifier,
name: "\(service.namespacedGeneratedName)Client",
conformances: ["\(service.namespacedTypealiasGeneratedName).ClientProtocol"],
members: [clientProperty, initializer] + methods
return .guarded(
self.availabilityGuard,
.struct(
StructDescription(
accessModifier: self.accessModifier,
name: "\(service.namespacedGeneratedName)Client",
conformances: ["\(service.namespacedTypealiasGeneratedName).ClientProtocol"],
members: [clientProperty, initializer] + methods
)
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,10 @@ extension ServerCodeTranslator {
)
)

return .commentable(.preFormatted(service.documentation), streamingProtocol)
return .commentable(
.preFormatted(service.documentation),
.guarded(self.availabilityGuard, streamingProtocol)
)
}

private func makeStreamingMethodSignature(
Expand Down Expand Up @@ -188,7 +191,10 @@ extension ServerCodeTranslator {
]
)
let registerRPCsBody = self.makeRegisterRPCsMethodBody(for: service, in: codeGenerationRequest)
return .function(signature: registerRPCsSignature, body: registerRPCsBody)
return .guarded(
self.availabilityGuard,
.function(signature: registerRPCsSignature, body: registerRPCsBody)
)
}

private func makeRegisterRPCsMethodBody(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,13 @@ extension SpecializedTranslator {
}
}
}

internal var availabilityGuard: AvailabilityDescription {
AvailabilityDescription(osVersions: [
.init(os: .macOS, version: "13.0"),
.init(os: .iOS, version: "16.0"),
.init(os: .watchOS, version: "9.0"),
.init(os: .tvOS, version: "16.0"),
])
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,21 @@ final class Test_TextBasedRenderer: XCTestCase {
)
}

func testAvailability() throws {
try _test(
.init(osVersions: [
.init(os: .macOS, version: "12.0"),
.init(os: .iOS, version: "13.1.2"),
.init(os: .watchOS, version: "8.1.2"),
.init(os: .tvOS, version: "15.0.2"),
]),
renderedBy: TextBasedRenderer.renderAvailability,
rendersAs: #"""
@available(macOS 12.0, iOS 13.1.2, watchOS 8.1.2, tvOS 15.0.2, *)
"""#
)
}

func testBindingKind() throws {
try _test(
.var,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase {
}
}
/// Documentation for ServiceA
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
public struct NamespaceA_ServiceAClient: NamespaceA.ServiceA.ClientProtocol {
private let client: GRPCCore.GRPCClient

Expand Down Expand Up @@ -139,6 +140,7 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase {
}
}
/// Documentation for ServiceA
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
public struct NamespaceA_ServiceAClient: NamespaceA.ServiceA.ClientProtocol {
private let client: GRPCCore.GRPCClient

Expand Down Expand Up @@ -212,6 +214,7 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase {
}
}
/// Documentation for ServiceA
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
public struct NamespaceA_ServiceAClient: NamespaceA.ServiceA.ClientProtocol {
private let client: GRPCCore.GRPCClient

Expand Down Expand Up @@ -285,6 +288,7 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase {
}
}
/// Documentation for ServiceA
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
public struct NamespaceA_ServiceAClient: NamespaceA.ServiceA.ClientProtocol {
private let client: GRPCCore.GRPCClient

Expand Down Expand Up @@ -386,6 +390,7 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase {
}
}
/// Documentation for ServiceA
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
package struct NamespaceA_ServiceAClient: NamespaceA.ServiceA.ClientProtocol {
private let client: GRPCCore.GRPCClient

Expand Down Expand Up @@ -475,6 +480,7 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase {
}
}
/// Documentation for ServiceA
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
internal struct ServiceAClient: ServiceA.ClientProtocol {
private let client: GRPCCore.GRPCClient

Expand Down Expand Up @@ -535,6 +541,7 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase {
extension NamespaceA.ServiceA.ClientProtocol {
}
/// Documentation for ServiceA
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
public struct NamespaceA_ServiceAClient: NamespaceA.ServiceA.ClientProtocol {
private let client: GRPCCore.GRPCClient

Expand All @@ -551,6 +558,7 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase {
/// Documentation for ServiceB
///
/// Line 2
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
public struct ServiceBClient: ServiceB.ClientProtocol {
private let client: GRPCCore.GRPCClient

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,10 +181,12 @@ final class IDLToStructuredSwiftTranslatorSnippetBasedTests: XCTestCase {
}

/// Documentation for AService
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
public protocol NamespaceA_ServiceAStreamingServiceProtocol: GRPCCore.RegistrableRPCService {}

/// Conformance to `GRPCCore.RegistrableRPCService`.
extension NamespaceA.ServiceA.StreamingServiceProtocol {
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
public func registerMethods(with router: inout GRPCCore.RPCRouter) {}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,14 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase {
let expectedSwift =
"""
/// Documentation for ServiceA
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
public protocol NamespaceA_ServiceAStreamingServiceProtocol: GRPCCore.RegistrableRPCService {
/// Documentation for unaryMethod
func unary(request: ServerRequest.Stream<NamespaceA.ServiceA.Method.Unary.Input>) async throws -> ServerResponse.Stream<NamespaceA.ServiceA.Method.Unary.Output>
}
/// Conformance to `GRPCCore.RegistrableRPCService`.
extension NamespaceA.ServiceA.StreamingServiceProtocol {
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
public func registerMethods(with router: inout GRPCCore.RPCRouter) {
router.registerHandler(
forMethod: NamespaceA.ServiceA.Method.Unary.descriptor,
Expand Down Expand Up @@ -115,12 +117,14 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase {
let expectedSwift =
"""
/// Documentation for ServiceA
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
package protocol NamespaceA_ServiceAStreamingServiceProtocol: GRPCCore.RegistrableRPCService {
/// Documentation for inputStreamingMethod
func inputStreaming(request: ServerRequest.Stream<NamespaceA.ServiceA.Method.InputStreaming.Input>) async throws -> ServerResponse.Stream<NamespaceA.ServiceA.Method.InputStreaming.Output>
}
/// Conformance to `GRPCCore.RegistrableRPCService`.
extension NamespaceA.ServiceA.StreamingServiceProtocol {
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
package func registerMethods(with router: inout GRPCCore.RPCRouter) {
router.registerHandler(
forMethod: NamespaceA.ServiceA.Method.InputStreaming.descriptor,
Expand Down Expand Up @@ -183,12 +187,14 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase {
let expectedSwift =
"""
/// Documentation for ServiceA
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
public protocol NamespaceA_ServiceAStreamingServiceProtocol: GRPCCore.RegistrableRPCService {
/// Documentation for outputStreamingMethod
func outputStreaming(request: ServerRequest.Stream<NamespaceA.ServiceA.Method.OutputStreaming.Input>) async throws -> ServerResponse.Stream<NamespaceA.ServiceA.Method.OutputStreaming.Output>
}
/// Conformance to `GRPCCore.RegistrableRPCService`.
extension NamespaceA.ServiceA.StreamingServiceProtocol {
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
public func registerMethods(with router: inout GRPCCore.RPCRouter) {
router.registerHandler(
forMethod: NamespaceA.ServiceA.Method.OutputStreaming.descriptor,
Expand Down Expand Up @@ -251,12 +257,14 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase {
let expectedSwift =
"""
/// Documentation for ServiceA
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
package protocol NamespaceA_ServiceAStreamingServiceProtocol: GRPCCore.RegistrableRPCService {
/// Documentation for bidirectionalStreamingMethod
func bidirectionalStreaming(request: ServerRequest.Stream<NamespaceA.ServiceA.Method.BidirectionalStreaming.Input>) async throws -> ServerResponse.Stream<NamespaceA.ServiceA.Method.BidirectionalStreaming.Output>
}
/// Conformance to `GRPCCore.RegistrableRPCService`.
extension NamespaceA.ServiceA.StreamingServiceProtocol {
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
package func registerMethods(with router: inout GRPCCore.RPCRouter) {
router.registerHandler(
forMethod: NamespaceA.ServiceA.Method.BidirectionalStreaming.descriptor,
Expand Down Expand Up @@ -327,6 +335,7 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase {
let expectedSwift =
"""
/// Documentation for ServiceA
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
internal protocol NamespaceA_ServiceAStreamingServiceProtocol: GRPCCore.RegistrableRPCService {
/// Documentation for inputStreamingMethod
func inputStreaming(request: ServerRequest.Stream<NamespaceA.ServiceA.Method.InputStreaming.Input>) async throws -> ServerResponse.Stream<NamespaceA.ServiceA.Method.InputStreaming.Output>
Expand All @@ -336,6 +345,7 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase {
}
/// Conformance to `GRPCCore.RegistrableRPCService`.
extension NamespaceA.ServiceA.StreamingServiceProtocol {
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
internal func registerMethods(with router: inout GRPCCore.RPCRouter) {
router.registerHandler(
forMethod: NamespaceA.ServiceA.Method.InputStreaming.descriptor,
Expand Down Expand Up @@ -406,12 +416,14 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase {
let expectedSwift =
"""
/// Documentation for ServiceA
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
internal protocol ServiceAStreamingServiceProtocol: GRPCCore.RegistrableRPCService {
/// Documentation for MethodA
func methodA(request: ServerRequest.Stream<ServiceA.Method.MethodA.Input>) async throws -> ServerResponse.Stream<ServiceA.Method.MethodA.Output>
}
/// Conformance to `GRPCCore.RegistrableRPCService`.
extension ServiceA.StreamingServiceProtocol {
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
internal func registerMethods(with router: inout GRPCCore.RPCRouter) {
router.registerHandler(
forMethod: ServiceA.Method.MethodA.descriptor,
Expand Down Expand Up @@ -468,9 +480,11 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase {
let expectedSwift =
"""
/// Documentation for ServiceA
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
public protocol NamespaceA_ServiceAStreamingServiceProtocol: GRPCCore.RegistrableRPCService {}
/// Conformance to `GRPCCore.RegistrableRPCService`.
extension NamespaceA.ServiceA.StreamingServiceProtocol {
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
public func registerMethods(with router: inout GRPCCore.RPCRouter) {}
}
/// Documentation for ServiceA
Expand All @@ -479,9 +493,11 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase {
extension NamespaceA.ServiceA.ServiceProtocol {
}
/// Documentation for ServiceB
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
public protocol NamespaceA_ServiceBStreamingServiceProtocol: GRPCCore.RegistrableRPCService {}
/// Conformance to `GRPCCore.RegistrableRPCService`.
extension NamespaceA.ServiceB.StreamingServiceProtocol {
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
public func registerMethods(with router: inout GRPCCore.RPCRouter) {}
}
/// Documentation for ServiceB
Expand Down
Loading