diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7bbb50f13..b00e62a07 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,8 +13,8 @@ jobs: with: linux_5_9_enabled: false linux_5_10_enabled: false - linux_6_0_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable -Xswiftc -warnings-as-errors" - linux_6_1_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable -Xswiftc -warnings-as-errors" + linux_6_0_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable -Xswiftc -warnings-as-errors -Xswiftc -require-explicit-availability" + linux_6_1_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable -Xswiftc -warnings-as-errors -Xswiftc -require-explicit-availability" linux_nightly_next_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" linux_nightly_main_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index a7aa1ae96..cada4efcc 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -22,8 +22,8 @@ jobs: with: linux_5_9_enabled: false linux_5_10_enabled: false - linux_6_0_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable -Xswiftc -warnings-as-errors" - linux_6_1_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable -Xswiftc -warnings-as-errors" + linux_6_0_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable -Xswiftc -warnings-as-errors -Xswiftc -require-explicit-availability" + linux_6_1_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable -Xswiftc -warnings-as-errors -Xswiftc -require-explicit-availability" linux_nightly_next_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" linux_nightly_main_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" diff --git a/Package.swift b/Package.swift index 24f8cc8df..0b1839e24 100644 --- a/Package.swift +++ b/Package.swift @@ -15,6 +15,7 @@ * limitations under the License. */ +import CompilerPluginSupport import PackageDescription let products: [Product] = [ @@ -45,12 +46,28 @@ let dependencies: [Package.Dependency] = [ ), ] -let defaultSwiftSettings: [SwiftSetting] = [ - .swiftLanguageMode(.v6), - .enableUpcomingFeature("ExistentialAny"), - .enableUpcomingFeature("InternalImportsByDefault"), - .enableUpcomingFeature("MemberImportVisibility"), -] +// ------------------------------------------------------------------------------------------------- + +// This adds some build settings which allow us to map "@available(gRPCSwift 2.x, *)" to +// the appropriate OS platforms. +let nextMinorVersion = 2 +let availabilitySettings: [SwiftSetting] = (0 ... nextMinorVersion).map { minor in + let name = "gRPCSwift" + let version = "2.\(minor)" + let platforms = "macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0" + let setting = "AvailabilityMacro=\(name) \(version):\(platforms)" + return .enableExperimentalFeature(setting) +} + +let defaultSwiftSettings: [SwiftSetting] = + availabilitySettings + [ + .swiftLanguageMode(.v6), + .enableUpcomingFeature("ExistentialAny"), + .enableUpcomingFeature("InternalImportsByDefault"), + .enableUpcomingFeature("MemberImportVisibility"), + ] + +// ------------------------------------------------------------------------------------------------- let targets: [Target] = [ // Runtime serialization components @@ -107,13 +124,6 @@ let targets: [Target] = [ let package = Package( name: "grpc-swift", - platforms: [ - .macOS(.v15), - .iOS(.v18), - .tvOS(.v18), - .watchOS(.v11), - .visionOS(.v2), - ], products: products, dependencies: dependencies, targets: targets diff --git a/Sources/GRPCCodeGen/CodeGenError.swift b/Sources/GRPCCodeGen/CodeGenError.swift index 6cfffa32c..e5a0508a9 100644 --- a/Sources/GRPCCodeGen/CodeGenError.swift +++ b/Sources/GRPCCodeGen/CodeGenError.swift @@ -15,6 +15,7 @@ */ /// A error thrown by the ``SourceGenerator`` to signal errors in the ``CodeGenerationRequest`` object. +@available(gRPCSwift 2.0, *) public struct CodeGenError: Error, Hashable, Sendable { /// The code indicating the domain of the error. public var code: Code @@ -33,6 +34,7 @@ public struct CodeGenError: Error, Hashable, Sendable { } } +@available(gRPCSwift 2.0, *) extension CodeGenError { public struct Code: Hashable, Sendable { private enum Value { @@ -63,6 +65,7 @@ extension CodeGenError { } } +@available(gRPCSwift 2.0, *) extension CodeGenError: CustomStringConvertible { public var description: String { return "\(self.code): \"\(self.message)\"" diff --git a/Sources/GRPCCodeGen/CodeGenerationRequest.swift b/Sources/GRPCCodeGen/CodeGenerationRequest.swift index fc69c1bcf..55cdb679a 100644 --- a/Sources/GRPCCodeGen/CodeGenerationRequest.swift +++ b/Sources/GRPCCodeGen/CodeGenerationRequest.swift @@ -16,6 +16,7 @@ /// Describes the services, dependencies and trivia from an IDL file, /// and the IDL itself through its specific serializer and deserializer. +@available(gRPCSwift 2.0, *) public struct CodeGenerationRequest { /// The name of the source file containing the IDL, including the extension if applicable. public var fileName: String @@ -81,6 +82,7 @@ public struct CodeGenerationRequest { } } +@available(gRPCSwift 2.0, *) extension CodeGenerationRequest { @available(*, deprecated, renamed: "makeSerializerSnippet") public var lookupSerializer: (_ messageType: String) -> String { @@ -120,6 +122,7 @@ extension CodeGenerationRequest { } /// Represents an import: a module or a specific item from a module. +@available(gRPCSwift 2.0, *) 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. @@ -261,6 +264,7 @@ public struct Dependency: Equatable { } /// Represents a service described in an IDL file. +@available(gRPCSwift 2.0, *) public struct ServiceDescriptor: Hashable { /// Documentation from comments above the IDL service description. /// It is already formatted, meaning it contains "///" and new lines. @@ -285,6 +289,7 @@ public struct ServiceDescriptor: Hashable { } } +@available(gRPCSwift 2.0, *) extension ServiceDescriptor { @available(*, deprecated, renamed: "init(documentation:name:methods:)") public init( @@ -317,6 +322,7 @@ extension ServiceDescriptor { } /// Represents a method described in an IDL file. +@available(gRPCSwift 2.0, *) public struct MethodDescriptor: Hashable { /// Documentation from comments above the IDL method description. /// It is already formatted, meaning it contains "///" and new lines. @@ -357,6 +363,7 @@ public struct MethodDescriptor: Hashable { } } +@available(gRPCSwift 2.0, *) extension MethodDescriptor { @available(*, deprecated, message: "Use MethodName instead of Name") public init( @@ -380,6 +387,7 @@ extension MethodDescriptor { } } +@available(gRPCSwift 2.0, *) public struct ServiceName: Hashable { /// The identifying name as used in the service/method descriptors including any namespace. /// @@ -414,6 +422,7 @@ public struct ServiceName: Hashable { } } +@available(gRPCSwift 2.0, *) public struct MethodName: Hashable { /// The identifying name as used in the service/method descriptors. /// @@ -445,6 +454,7 @@ public struct MethodName: Hashable { /// Represents the name associated with a namespace, service or a method, in three different formats. @available(*, deprecated, message: "Use ServiceName/MethodName instead.") +@available(gRPCSwift 2.0, *) 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. @@ -473,6 +483,7 @@ public struct Name: Hashable { } @available(*, deprecated, message: "Use ServiceName/MethodName instead.") +@available(gRPCSwift 2.0, *) extension Name { /// The base name replacing occurrences of "." with "_". /// diff --git a/Sources/GRPCCodeGen/CodeGenerator.swift b/Sources/GRPCCodeGen/CodeGenerator.swift index 07ffd9848..56de6efc6 100644 --- a/Sources/GRPCCodeGen/CodeGenerator.swift +++ b/Sources/GRPCCodeGen/CodeGenerator.swift @@ -15,10 +15,12 @@ */ @available(*, deprecated, renamed: "CodeGenerator") +@available(gRPCSwift 2.0, *) public typealias SourceGenerator = CodeGenerator /// Generates ``SourceFile`` objects containing generated code for the RPCs represented /// in a ``CodeGenerationRequest`` object. +@available(gRPCSwift 2.0, *) public struct CodeGenerator: Sendable { /// The options regarding the access level, indentation for the generated code /// and whether to generate server and client code. @@ -41,8 +43,10 @@ public struct CodeGenerator: Sendable { /// Whether or not server code should be generated. public var server: Bool /// The name of the core gRPC module. + @available(gRPCSwift 2.1, *) public var grpcCoreModuleName: String /// The availability annotations to use on the generated code. + @available(gRPCSwift 2.2, *) public var availability: AvailabilityAnnotations = .default /// Creates a new configuration. @@ -88,6 +92,7 @@ public struct CodeGenerator: Sendable { } // The availability that generated code is annotated with. + @available(gRPCSwift 2.2, *) public struct AvailabilityAnnotations: Sendable, Hashable { public struct Platform: Sendable, Hashable { /// The name of the OS, e.g. 'macOS'. @@ -156,6 +161,7 @@ public struct CodeGenerator: Sendable { } } +@available(gRPCSwift 2.0, *) extension AvailabilityDescription { init(_ availability: CodeGenerator.Config.AvailabilityAnnotations) throws { switch availability.wrapped { diff --git a/Sources/GRPCCodeGen/Internal/Renderer/RendererProtocol.swift b/Sources/GRPCCodeGen/Internal/Renderer/RendererProtocol.swift index a08700e65..8495a1884 100644 --- a/Sources/GRPCCodeGen/Internal/Renderer/RendererProtocol.swift +++ b/Sources/GRPCCodeGen/Internal/Renderer/RendererProtocol.swift @@ -31,6 +31,7 @@ /// into Swift files. /// /// Rendering is the last phase of the generator pipeline. +@available(gRPCSwift 2.0, *) protocol RendererProtocol { /// Renders the specified structured code into a raw Swift file. diff --git a/Sources/GRPCCodeGen/Internal/Renderer/TextBasedRenderer.swift b/Sources/GRPCCodeGen/Internal/Renderer/TextBasedRenderer.swift index e4cb173af..3cfb4a2dd 100644 --- a/Sources/GRPCCodeGen/Internal/Renderer/TextBasedRenderer.swift +++ b/Sources/GRPCCodeGen/Internal/Renderer/TextBasedRenderer.swift @@ -111,6 +111,7 @@ extension TextBasedRenderer: Sendable {} /// A renderer that uses string interpolation and concatenation /// to convert the provided structure code into raw string form. +@available(gRPCSwift 2.0, *) struct TextBasedRenderer: RendererProtocol { func render( @@ -1207,6 +1208,7 @@ extension String { } } +@available(gRPCSwift 2.0, *) extension TextBasedRenderer { /// Returns the provided expression rendered as a string. diff --git a/Sources/GRPCCodeGen/Internal/StructuredSwift+Client.swift b/Sources/GRPCCodeGen/Internal/StructuredSwift+Client.swift index 99fddbede..c9c7d9545 100644 --- a/Sources/GRPCCodeGen/Internal/StructuredSwift+Client.swift +++ b/Sources/GRPCCodeGen/Internal/StructuredSwift+Client.swift @@ -194,6 +194,7 @@ extension FunctionDescription { } } +@available(gRPCSwift 2.0, *) extension ProtocolDescription { /// ``` /// protocol : Sendable { @@ -233,6 +234,7 @@ extension ProtocolDescription { } } +@available(gRPCSwift 2.0, *) extension ExtensionDescription { /// ``` /// extension { @@ -503,6 +505,7 @@ extension FunctionDescription { } } +@available(gRPCSwift 2.0, *) extension ExtensionDescription { /// ``` /// extension { @@ -662,6 +665,7 @@ extension FunctionDescription { } } +@available(gRPCSwift 2.0, *) extension StructDescription { /// ``` /// struct : where Transport: GRPCCore.ClientTransport { @@ -752,6 +756,7 @@ extension StructDescription { } } +@available(gRPCSwift 2.0, *) private func docs( for method: MethodDescriptor, serializers includeSerializers: Bool = true @@ -793,6 +798,7 @@ private func docs( return Docs.interposeDocs(method.documentation, between: summary, and: allParameters) } +@available(gRPCSwift 2.0, *) private func explodedDocs(for method: MethodDescriptor) -> String { let summary = "/// Call the \"\(method.name.identifyingName)\" method." var parameters = """ diff --git a/Sources/GRPCCodeGen/Internal/StructuredSwift+Server.swift b/Sources/GRPCCodeGen/Internal/StructuredSwift+Server.swift index a012f0b67..5cd883caa 100644 --- a/Sources/GRPCCodeGen/Internal/StructuredSwift+Server.swift +++ b/Sources/GRPCCodeGen/Internal/StructuredSwift+Server.swift @@ -48,6 +48,7 @@ extension FunctionSignatureDescription { } } +@available(gRPCSwift 2.0, *) extension ProtocolDescription { /// ``` /// protocol : GRPCCore.RegistrableRPCService { @@ -101,6 +102,7 @@ extension ProtocolDescription { } } +@available(gRPCSwift 2.0, *) extension ExtensionDescription { /// ``` /// extension { @@ -136,6 +138,7 @@ extension ExtensionDescription { } } +@available(gRPCSwift 2.0, *) extension ProtocolDescription { /// ``` /// protocol : { @@ -304,6 +307,7 @@ extension FunctionCallDescription { } } +@available(gRPCSwift 2.0, *) extension FunctionDescription { /// ``` /// func registerMethods(with router: inout GRPCCore.RPCRouter) { @@ -451,6 +455,7 @@ extension FunctionDescription { } } +@available(gRPCSwift 2.0, *) extension ExtensionDescription { /// ``` /// extension { @@ -548,6 +553,7 @@ extension FunctionSignatureDescription { } } +@available(gRPCSwift 2.0, *) extension ProtocolDescription { /// ``` /// protocol SimpleServiceProtocol: { @@ -763,6 +769,7 @@ extension FunctionDescription { } } +@available(gRPCSwift 2.0, *) extension ExtensionDescription { /// ``` /// extension ServiceProtocol { diff --git a/Sources/GRPCCodeGen/Internal/StructuredSwift+ServiceMetadata.swift b/Sources/GRPCCodeGen/Internal/StructuredSwift+ServiceMetadata.swift index 7e06ec07a..8ed3cc885 100644 --- a/Sources/GRPCCodeGen/Internal/StructuredSwift+ServiceMetadata.swift +++ b/Sources/GRPCCodeGen/Internal/StructuredSwift+ServiceMetadata.swift @@ -185,6 +185,7 @@ extension VariableDescription { } } +@available(gRPCSwift 2.0, *) extension EnumDescription { /// ``` /// enum { @@ -340,6 +341,7 @@ extension EnumDescription { } } +@available(gRPCSwift 2.0, *) extension [CodeBlock] { /// ``` /// enum { diff --git a/Sources/GRPCCodeGen/Internal/Translator/ClientCodeTranslator.swift b/Sources/GRPCCodeGen/Internal/Translator/ClientCodeTranslator.swift index 443bf9c17..1f38bea37 100644 --- a/Sources/GRPCCodeGen/Internal/Translator/ClientCodeTranslator.swift +++ b/Sources/GRPCCodeGen/Internal/Translator/ClientCodeTranslator.swift @@ -75,6 +75,7 @@ /// } /// } ///``` +@available(gRPCSwift 2.0, *) struct ClientCodeTranslator { init() {} diff --git a/Sources/GRPCCodeGen/Internal/Translator/Docs.swift b/Sources/GRPCCodeGen/Internal/Translator/Docs.swift index f8c6def00..2e6505406 100644 --- a/Sources/GRPCCodeGen/Internal/Translator/Docs.swift +++ b/Sources/GRPCCodeGen/Internal/Translator/Docs.swift @@ -14,6 +14,7 @@ * limitations under the License. */ +@available(gRPCSwift 2.0, *) package enum Docs { package static func suffix(_ header: String, withDocs footer: String) -> String { if footer.isEmpty { diff --git a/Sources/GRPCCodeGen/Internal/Translator/IDLToStructuredSwiftTranslator.swift b/Sources/GRPCCodeGen/Internal/Translator/IDLToStructuredSwiftTranslator.swift index c496980b7..038254cf3 100644 --- a/Sources/GRPCCodeGen/Internal/Translator/IDLToStructuredSwiftTranslator.swift +++ b/Sources/GRPCCodeGen/Internal/Translator/IDLToStructuredSwiftTranslator.swift @@ -17,6 +17,7 @@ /// Creates a representation for the server and client code, as well as for the enums containing useful type aliases and properties. /// The representation is generated based on the ``CodeGenerationRequest`` object and user specifications, /// using types from ``StructuredSwiftRepresentation``. +@available(gRPCSwift 2.0, *) package struct IDLToStructuredSwiftTranslator { package init() {} @@ -136,6 +137,7 @@ package struct IDLToStructuredSwiftTranslator { } } +@available(gRPCSwift 2.0, *) extension AccessModifier { init(_ accessLevel: CodeGenerator.Config.AccessLevel) { switch accessLevel.level { @@ -146,6 +148,7 @@ extension AccessModifier { } } +@available(gRPCSwift 2.0, *) extension IDLToStructuredSwiftTranslator { private func translateImport( dependency: Dependency, diff --git a/Sources/GRPCCodeGen/Internal/Translator/MetadataTranslator.swift b/Sources/GRPCCodeGen/Internal/Translator/MetadataTranslator.swift index 2fc64821c..6015a1057 100644 --- a/Sources/GRPCCodeGen/Internal/Translator/MetadataTranslator.swift +++ b/Sources/GRPCCodeGen/Internal/Translator/MetadataTranslator.swift @@ -14,6 +14,7 @@ * limitations under the License. */ +@available(gRPCSwift 2.0, *) struct MetadataTranslator { init() {} diff --git a/Sources/GRPCCodeGen/Internal/Translator/ServerCodeTranslator.swift b/Sources/GRPCCodeGen/Internal/Translator/ServerCodeTranslator.swift index caf981742..3de95fdc1 100644 --- a/Sources/GRPCCodeGen/Internal/Translator/ServerCodeTranslator.swift +++ b/Sources/GRPCCodeGen/Internal/Translator/ServerCodeTranslator.swift @@ -57,6 +57,7 @@ /// } /// } ///``` +@available(gRPCSwift 2.0, *) struct ServerCodeTranslator { init() {} diff --git a/Sources/GRPCCodeGen/SourceFile.swift b/Sources/GRPCCodeGen/SourceFile.swift index c435fb100..ac511536f 100644 --- a/Sources/GRPCCodeGen/SourceFile.swift +++ b/Sources/GRPCCodeGen/SourceFile.swift @@ -16,6 +16,7 @@ /// Representation of the file to be created by the code generator, that contains the /// generated Swift source code. +@available(gRPCSwift 2.0, *) public struct SourceFile: Sendable, Hashable { /// The base name of the file. public var name: String diff --git a/Sources/GRPCCore/Call/Client/CallOptions.swift b/Sources/GRPCCore/Call/Client/CallOptions.swift index 2e6f8d939..68a36a9e6 100644 --- a/Sources/GRPCCore/Call/Client/CallOptions.swift +++ b/Sources/GRPCCore/Call/Client/CallOptions.swift @@ -21,6 +21,7 @@ /// /// You can create the default set of options, which defers all possible /// configuration to the transport, by using ``CallOptions/defaults``. +@available(gRPCSwift 2.0, *) public struct CallOptions: Sendable { /// The default timeout for the RPC. /// @@ -107,6 +108,7 @@ public struct CallOptions: Sendable { } } +@available(gRPCSwift 2.0, *) extension CallOptions { /// Default call options. /// @@ -123,6 +125,7 @@ extension CallOptions { } } +@available(gRPCSwift 2.0, *) extension CallOptions { package mutating func formUnion(with methodConfig: MethodConfig?) { guard let methodConfig = methodConfig else { return } diff --git a/Sources/GRPCCore/Call/Client/ClientContext.swift b/Sources/GRPCCore/Call/Client/ClientContext.swift index 679496ed4..b53983795 100644 --- a/Sources/GRPCCore/Call/Client/ClientContext.swift +++ b/Sources/GRPCCore/Call/Client/ClientContext.swift @@ -15,6 +15,7 @@ */ /// A context passed to the client containing additional information about the RPC. +@available(gRPCSwift 2.0, *) public struct ClientContext: Sendable { /// A description of the method being called. public var descriptor: MethodDescriptor diff --git a/Sources/GRPCCore/Call/Client/ClientInterceptor.swift b/Sources/GRPCCore/Call/Client/ClientInterceptor.swift index d09d654b5..a2e22ba87 100644 --- a/Sources/GRPCCore/Call/Client/ClientInterceptor.swift +++ b/Sources/GRPCCore/Call/Client/ClientInterceptor.swift @@ -89,6 +89,7 @@ /// ``` /// /// For server-side interceptors see ``ServerInterceptor``. +@available(gRPCSwift 2.0, *) public protocol ClientInterceptor: Sendable { /// Intercept a request object. /// diff --git a/Sources/GRPCCore/Call/Client/ClientRequest.swift b/Sources/GRPCCore/Call/Client/ClientRequest.swift index c36df63db..3e52a741c 100644 --- a/Sources/GRPCCore/Call/Client/ClientRequest.swift +++ b/Sources/GRPCCore/Call/Client/ClientRequest.swift @@ -28,6 +28,7 @@ /// print(request.metadata) // prints '[:]' /// print(request.message) // prints 'Hello, gRPC!' /// ``` +@available(gRPCSwift 2.0, *) public struct ClientRequest: Sendable { /// Caller-specified metadata to send to the server at the start of the RPC. /// @@ -61,6 +62,7 @@ public struct ClientRequest: Sendable { /// /// See ``ClientRequest`` for single-message requests and ``StreamingServerRequest`` for the /// servers representation of a streaming-message request. +@available(gRPCSwift 2.0, *) public struct StreamingClientRequest: Sendable { /// Caller-specified metadata sent to the server at the start of the RPC. /// diff --git a/Sources/GRPCCore/Call/Client/ClientResponse.swift b/Sources/GRPCCore/Call/Client/ClientResponse.swift index 73fcde0d5..23ec38546 100644 --- a/Sources/GRPCCore/Call/Client/ClientResponse.swift +++ b/Sources/GRPCCore/Call/Client/ClientResponse.swift @@ -67,6 +67,7 @@ /// print("RPC failed with code '\(error.code)'") /// } /// ``` +@available(gRPCSwift 2.0, *) public struct ClientResponse: Sendable { /// The contents of an accepted response with a single message. public struct Contents: Sendable { @@ -198,6 +199,7 @@ public struct ClientResponse: Sendable { /// print("RPC failed with code '\(error.code)'") /// } /// ``` +@available(gRPCSwift 2.0, *) public struct StreamingClientResponse: Sendable { public struct Contents: Sendable { /// Metadata received from the server at the beginning of the response. @@ -254,6 +256,7 @@ public struct StreamingClientResponse: Sendable { // MARK: - Convenience API +@available(gRPCSwift 2.0, *) extension ClientResponse { /// Creates a new accepted response. /// @@ -324,6 +327,7 @@ extension ClientResponse { } } +@available(gRPCSwift 2.0, *) extension StreamingClientResponse { /// Creates a new accepted response. /// @@ -386,6 +390,7 @@ extension StreamingClientResponse { /// Returns the body parts (i.e. `messages` and `trailingMetadata`) returned from the server. /// /// For rejected RPCs (in other words, where ``accepted`` is `failure`), the `RPCAsyncSequence` throws a ``RPCError``. + @available(gRPCSwift 2.1, *) public var bodyParts: RPCAsyncSequence { switch self.accepted { case let .success(contents): @@ -397,4 +402,5 @@ extension StreamingClientResponse { } } +@available(gRPCSwift 2.0, *) extension StreamingClientResponse.Contents.BodyPart: Equatable where Message: Equatable {} diff --git a/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor+HedgingExecutor.swift b/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor+HedgingExecutor.swift index e0743bee3..08bdb62d7 100644 --- a/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor+HedgingExecutor.swift +++ b/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor+HedgingExecutor.swift @@ -16,6 +16,7 @@ public import Synchronization // would be internal but for usableFromInline +@available(gRPCSwift 2.0, *) extension ClientRPCExecutor { @usableFromInline struct HedgingExecutor< @@ -61,6 +62,7 @@ extension ClientRPCExecutor { } } +@available(gRPCSwift 2.0, *) extension ClientRPCExecutor.HedgingExecutor { @inlinable func execute( @@ -543,6 +545,7 @@ extension ClientRPCExecutor.HedgingExecutor { } } +@available(gRPCSwift 2.0, *) @usableFromInline enum _HedgingTaskResult: Sendable { case rpcHandled(Result) @@ -550,6 +553,7 @@ enum _HedgingTaskResult: Sendable { case timedOut(Result) } +@available(gRPCSwift 2.0, *) @usableFromInline enum _HedgingAttemptTaskResult: Sendable { case attemptPicked(Bool) diff --git a/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor+OneShotExecutor.swift b/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor+OneShotExecutor.swift index a4de402af..97be8b77a 100644 --- a/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor+OneShotExecutor.swift +++ b/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor+OneShotExecutor.swift @@ -14,6 +14,7 @@ * limitations under the License. */ +@available(gRPCSwift 2.0, *) extension ClientRPCExecutor { /// An executor for requests which doesn't apply retries or hedging. The request has just one /// attempt at execution. @@ -53,6 +54,7 @@ extension ClientRPCExecutor { } } +@available(gRPCSwift 2.0, *) extension ClientRPCExecutor.OneShotExecutor { @inlinable func execute( @@ -88,6 +90,7 @@ extension ClientRPCExecutor.OneShotExecutor { } } +@available(gRPCSwift 2.0, *) extension ClientRPCExecutor.OneShotExecutor { @inlinable func _execute( @@ -129,6 +132,7 @@ extension ClientRPCExecutor.OneShotExecutor { } } +@available(gRPCSwift 2.0, *) @inlinable func withDeadline( _ deadline: ContinuousClock.Instant, @@ -169,6 +173,7 @@ func withDeadline( } } +@available(gRPCSwift 2.0, *) @usableFromInline enum _DeadlineChildTaskResult: Sendable { case deadlinePassed diff --git a/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor+RetryExecutor.swift b/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor+RetryExecutor.swift index e5964baee..bb4eb4bc7 100644 --- a/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor+RetryExecutor.swift +++ b/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor+RetryExecutor.swift @@ -14,6 +14,7 @@ * limitations under the License. */ +@available(gRPCSwift 2.0, *) extension ClientRPCExecutor { @usableFromInline struct RetryExecutor< @@ -59,6 +60,7 @@ extension ClientRPCExecutor { } } +@available(gRPCSwift 2.0, *) extension ClientRPCExecutor.RetryExecutor { @inlinable func execute( @@ -310,6 +312,7 @@ extension ClientRPCExecutor.RetryExecutor { } } +@available(gRPCSwift 2.0, *) @usableFromInline enum _RetryExecutorTask: Sendable { case timedOut(Result) diff --git a/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor.swift b/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor.swift index 0cbe1490a..f7e41fad9 100644 --- a/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor.swift +++ b/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor.swift @@ -14,6 +14,7 @@ * limitations under the License. */ +@available(gRPCSwift 2.0, *) @usableFromInline enum ClientRPCExecutor { /// Execute the request and handle its response. @@ -99,6 +100,7 @@ enum ClientRPCExecutor { } } +@available(gRPCSwift 2.0, *) extension ClientRPCExecutor { /// Executes a request on a given stream processor. /// diff --git a/Sources/GRPCCore/Call/Client/Internal/ClientRequest+Convenience.swift b/Sources/GRPCCore/Call/Client/Internal/ClientRequest+Convenience.swift index 477378599..3a6b15969 100644 --- a/Sources/GRPCCore/Call/Client/Internal/ClientRequest+Convenience.swift +++ b/Sources/GRPCCore/Call/Client/Internal/ClientRequest+Convenience.swift @@ -14,6 +14,7 @@ * limitations under the License. */ +@available(gRPCSwift 2.0, *) extension StreamingClientRequest { internal init(single request: ClientRequest) { self.init(metadata: request.metadata) { diff --git a/Sources/GRPCCore/Call/Client/Internal/ClientResponse+Convenience.swift b/Sources/GRPCCore/Call/Client/Internal/ClientResponse+Convenience.swift index 30b381e72..41c3d0244 100644 --- a/Sources/GRPCCore/Call/Client/Internal/ClientResponse+Convenience.swift +++ b/Sources/GRPCCore/Call/Client/Internal/ClientResponse+Convenience.swift @@ -14,6 +14,7 @@ * limitations under the License. */ +@available(gRPCSwift 2.0, *) extension ClientResponse { /// Converts a streaming response into a single response. /// @@ -81,6 +82,7 @@ extension ClientResponse { } } +@available(gRPCSwift 2.0, *) extension StreamingClientResponse { /// Creates a streaming response from the given status and metadata. /// @@ -101,6 +103,7 @@ extension StreamingClientResponse { } } +@available(gRPCSwift 2.0, *) extension StreamingClientResponse { /// Returns a new response which maps the messages of this response. /// diff --git a/Sources/GRPCCore/Call/Client/Internal/ClientStreamExecutor.swift b/Sources/GRPCCore/Call/Client/Internal/ClientStreamExecutor.swift index 1b2cac862..74aac103f 100644 --- a/Sources/GRPCCore/Call/Client/Internal/ClientStreamExecutor.swift +++ b/Sources/GRPCCore/Call/Client/Internal/ClientStreamExecutor.swift @@ -14,6 +14,7 @@ * limitations under the License. */ +@available(gRPCSwift 2.0, *) @usableFromInline internal enum ClientStreamExecutor { /// Execute a request on the stream executor. diff --git a/Sources/GRPCCore/Call/Client/Internal/RetryDelaySequence.swift b/Sources/GRPCCore/Call/Client/Internal/RetryDelaySequence.swift index 4f87682b2..b9f54a916 100644 --- a/Sources/GRPCCore/Call/Client/Internal/RetryDelaySequence.swift +++ b/Sources/GRPCCore/Call/Client/Internal/RetryDelaySequence.swift @@ -25,6 +25,7 @@ public import Musl // should be @usableFromInline #error("Unsupported OS") #endif +@available(gRPCSwift 2.0, *) @usableFromInline struct RetryDelaySequence: Sequence { @usableFromInline diff --git a/Sources/GRPCCore/Call/ConditionalInterceptor.swift b/Sources/GRPCCore/Call/ConditionalInterceptor.swift index 1a61755ac..c5302260c 100644 --- a/Sources/GRPCCore/Call/ConditionalInterceptor.swift +++ b/Sources/GRPCCore/Call/ConditionalInterceptor.swift @@ -23,6 +23,7 @@ /// /// - SeeAlso: ``ClientInterceptor`` and ``ServerInterceptor`` for more information on client and /// server interceptors, respectively. +@available(gRPCSwift 2.0, *) public struct ConditionalInterceptor: Sendable { public struct Subject: Sendable { internal enum Wrapped: Sendable { @@ -85,6 +86,7 @@ public struct ConditionalInterceptor: Sendable { } } +@available(gRPCSwift 2.0, *) extension ConditionalInterceptor where Interceptor == any ClientInterceptor { /// Create an operation, specifying which ``ClientInterceptor`` to apply and to which ``Subject``. /// - Parameters: @@ -98,6 +100,7 @@ extension ConditionalInterceptor where Interceptor == any ClientInterceptor { } } +@available(gRPCSwift 2.0, *) extension ConditionalInterceptor where Interceptor == any ServerInterceptor { /// Create an operation, specifying which ``ServerInterceptor`` to apply and to which ``Subject``. /// - Parameters: diff --git a/Sources/GRPCCore/Call/Server/Internal/ServerCancellationManager.swift b/Sources/GRPCCore/Call/Server/Internal/ServerCancellationManager.swift index 471f9d007..d4b8021fc 100644 --- a/Sources/GRPCCore/Call/Server/Internal/ServerCancellationManager.swift +++ b/Sources/GRPCCore/Call/Server/Internal/ServerCancellationManager.swift @@ -17,6 +17,7 @@ private import Synchronization /// Stores cancellation state for an RPC on the server . +@available(gRPCSwift 2.0, *) package final class ServerCancellationManager: Sendable { private let state: Mutex @@ -104,6 +105,7 @@ package final class ServerCancellationManager: Sendable { } } +@available(gRPCSwift 2.0, *) extension ServerCancellationManager { enum CancellationSource { case rpc diff --git a/Sources/GRPCCore/Call/Server/Internal/ServerRPCExecutor.swift b/Sources/GRPCCore/Call/Server/Internal/ServerRPCExecutor.swift index 416a2c4c7..8df70f86d 100644 --- a/Sources/GRPCCore/Call/Server/Internal/ServerRPCExecutor.swift +++ b/Sources/GRPCCore/Call/Server/Internal/ServerRPCExecutor.swift @@ -14,6 +14,7 @@ * limitations under the License. */ +@available(gRPCSwift 2.0, *) @usableFromInline struct ServerRPCExecutor { /// Executes an RPC using the provided handler. @@ -290,6 +291,7 @@ struct ServerRPCExecutor { } } +@available(gRPCSwift 2.0, *) extension ServerRPCExecutor { @inlinable static func _intercept( diff --git a/Sources/GRPCCore/Call/Server/RPCRouter.swift b/Sources/GRPCCore/Call/Server/RPCRouter.swift index 5f43639f7..88c89c635 100644 --- a/Sources/GRPCCore/Call/Server/RPCRouter.swift +++ b/Sources/GRPCCore/Call/Server/RPCRouter.swift @@ -34,6 +34,7 @@ /// 1. Remove individual methods by calling ``removeHandler(forMethod:)``, or /// 2. Implement ``RegistrableRPCService/registerMethods(with:)`` to register only the methods you /// want to be served. +@available(gRPCSwift 2.0, *) public struct RPCRouter: Sendable { @usableFromInline struct RPCHandler: Sendable { @@ -168,6 +169,7 @@ public struct RPCRouter: Sendable { } } +@available(gRPCSwift 2.0, *) extension RPCRouter { internal func handle( stream: RPCStream< @@ -187,6 +189,7 @@ extension RPCRouter { } } +@available(gRPCSwift 2.0, *) extension Status { fileprivate static let rpcNotImplemented = Status( code: .unimplemented, diff --git a/Sources/GRPCCore/Call/Server/RegistrableRPCService.swift b/Sources/GRPCCore/Call/Server/RegistrableRPCService.swift index b7f3e241b..7bd5819be 100644 --- a/Sources/GRPCCore/Call/Server/RegistrableRPCService.swift +++ b/Sources/GRPCCore/Call/Server/RegistrableRPCService.swift @@ -22,6 +22,7 @@ /// generated conformance by implementing ``registerMethods(with:)`` manually by calling /// ``RPCRouter/registerHandler(forMethod:deserializer:serializer:handler:)`` for each method /// you want to register with the router. +@available(gRPCSwift 2.0, *) public protocol RegistrableRPCService: Sendable { /// Registers methods to server with the provided ``RPCRouter``. /// diff --git a/Sources/GRPCCore/Call/Server/ServerContext+RPCCancellationHandle.swift b/Sources/GRPCCore/Call/Server/ServerContext+RPCCancellationHandle.swift index f958978b8..607c478c6 100644 --- a/Sources/GRPCCore/Call/Server/ServerContext+RPCCancellationHandle.swift +++ b/Sources/GRPCCore/Call/Server/ServerContext+RPCCancellationHandle.swift @@ -16,6 +16,7 @@ private import Synchronization +@available(gRPCSwift 2.0, *) extension ServerContext { @TaskLocal internal static var rpcCancellation: RPCCancellationHandle? @@ -73,6 +74,7 @@ extension ServerContext { /// - handler: The handler which is invoked when the RPC is cancelled. /// - Throws: Any error thrown by the `operation` closure. /// - Returns: The result of the `operation` closure. +@available(gRPCSwift 2.0, *) public func withRPCCancellationHandler( operation: () async throws(Failure) -> Result, onCancelRPC handler: @Sendable @escaping () -> Void @@ -102,6 +104,7 @@ public func withRPCCancellationHandler( /// use ``withRPCCancellationHandler(operation:onCancelRPC:)``. /// /// - Parameter operation: The operation to execute with the handle. +@available(gRPCSwift 2.0, *) public func withServerContextRPCCancellationHandle( _ operation: (ServerContext.RPCCancellationHandle) async throws(Failure) -> Success ) async throws(Failure) -> Success { diff --git a/Sources/GRPCCore/Call/Server/ServerContext.swift b/Sources/GRPCCore/Call/Server/ServerContext.swift index f027ad058..6df188f1c 100644 --- a/Sources/GRPCCore/Call/Server/ServerContext.swift +++ b/Sources/GRPCCore/Call/Server/ServerContext.swift @@ -15,9 +15,11 @@ */ /// Additional information about an RPC handled by a server. +@available(gRPCSwift 2.0, *) public struct ServerContext: Sendable { /// Protocol used to help identify transport specific context fields + @available(gRPCSwift 2.2, *) public protocol TransportSpecific: Sendable {} /// A description of the method being called. @@ -56,6 +58,7 @@ public struct ServerContext: Sendable { /// /// An example of what this field can be used for, would be to store /// things like a peer certificate from a mTLS connection + @available(gRPCSwift 2.2, *) public var transportSpecific: (any TransportSpecific)? /// A handle for checking the cancellation status of an RPC. diff --git a/Sources/GRPCCore/Call/Server/ServerInterceptor.swift b/Sources/GRPCCore/Call/Server/ServerInterceptor.swift index c6310edc3..8192fc21e 100644 --- a/Sources/GRPCCore/Call/Server/ServerInterceptor.swift +++ b/Sources/GRPCCore/Call/Server/ServerInterceptor.swift @@ -60,6 +60,7 @@ /// ``` /// /// For client-side interceptors see ``ClientInterceptor``. +@available(gRPCSwift 2.0, *) public protocol ServerInterceptor: Sendable { /// Intercept a request object. /// diff --git a/Sources/GRPCCore/Call/Server/ServerRequest.swift b/Sources/GRPCCore/Call/Server/ServerRequest.swift index 40ec6b568..6dd23063b 100644 --- a/Sources/GRPCCore/Call/Server/ServerRequest.swift +++ b/Sources/GRPCCore/Call/Server/ServerRequest.swift @@ -15,6 +15,7 @@ */ /// A request received at the server containing a single message. +@available(gRPCSwift 2.0, *) public struct ServerRequest: Sendable { /// Metadata received from the client at the start of the RPC. /// @@ -37,6 +38,7 @@ public struct ServerRequest: Sendable { } /// A request received at the server containing a stream of messages. +@available(gRPCSwift 2.0, *) public struct StreamingServerRequest: Sendable { /// Metadata received from the client at the start of the RPC. /// @@ -62,12 +64,14 @@ public struct StreamingServerRequest: Sendable { // MARK: - Conversion +@available(gRPCSwift 2.0, *) extension StreamingServerRequest { public init(single request: ServerRequest) { self.init(metadata: request.metadata, messages: .one(request.message)) } } +@available(gRPCSwift 2.0, *) extension ServerRequest { public init(stream request: StreamingServerRequest) async throws { var iterator = request.messages.makeAsyncIterator() diff --git a/Sources/GRPCCore/Call/Server/ServerResponse.swift b/Sources/GRPCCore/Call/Server/ServerResponse.swift index f71fe4204..0b439355d 100644 --- a/Sources/GRPCCore/Call/Server/ServerResponse.swift +++ b/Sources/GRPCCore/Call/Server/ServerResponse.swift @@ -66,6 +66,7 @@ /// print("RPC failed with code '\(error.code)'") /// } /// ``` +@available(gRPCSwift 2.0, *) public struct ServerResponse: Sendable { /// An accepted RPC with a successful outcome. public struct Contents: Sendable { @@ -168,6 +169,7 @@ public struct ServerResponse: Sendable { /// return ["goodbye": "trailing metadata"] /// } /// ``` +@available(gRPCSwift 2.0, *) public struct StreamingServerResponse: Sendable { /// The contents of a response to a request which has been accepted for processing. public struct Contents: Sendable { @@ -219,6 +221,7 @@ public struct StreamingServerResponse: Sendable { } } +@available(gRPCSwift 2.0, *) extension ServerResponse { /// Creates a new accepted response. /// @@ -288,6 +291,7 @@ extension ServerResponse { } } +@available(gRPCSwift 2.0, *) extension StreamingServerResponse { /// Creates a new accepted response. /// @@ -336,6 +340,7 @@ extension StreamingServerResponse { } } +@available(gRPCSwift 2.0, *) extension StreamingServerResponse { public init(single response: ServerResponse) { switch response.accepted { diff --git a/Sources/GRPCCore/Coding/Coding.swift b/Sources/GRPCCore/Coding/Coding.swift index 97e236db3..156fd6638 100644 --- a/Sources/GRPCCore/Coding/Coding.swift +++ b/Sources/GRPCCore/Coding/Coding.swift @@ -22,6 +22,7 @@ /// /// Serializers are used frequently and implementations should take care to ensure that /// serialization is as cheap as possible. +@available(gRPCSwift 2.0, *) public protocol MessageSerializer: Sendable { /// The type of message this serializer can serialize. associatedtype Message @@ -41,6 +42,7 @@ public protocol MessageSerializer: Sendable { /// /// Deserializers are used frequently and implementations should take care to ensure that /// deserialization is as cheap as possible. +@available(gRPCSwift 2.0, *) public protocol MessageDeserializer: Sendable { /// The type of message this deserializer can deserialize. associatedtype Message diff --git a/Sources/GRPCCore/Coding/CompressionAlgorithm.swift b/Sources/GRPCCore/Coding/CompressionAlgorithm.swift index 7b54e6636..9c162f6a2 100644 --- a/Sources/GRPCCore/Coding/CompressionAlgorithm.swift +++ b/Sources/GRPCCore/Coding/CompressionAlgorithm.swift @@ -15,6 +15,7 @@ */ /// Message compression algorithms. +@available(gRPCSwift 2.0, *) public struct CompressionAlgorithm: Hashable, Sendable { package enum Value: UInt8, Hashable, Sendable, CaseIterable { case none = 0 @@ -45,6 +46,7 @@ public struct CompressionAlgorithm: Hashable, Sendable { } /// A set of compression algorithms. +@available(gRPCSwift 2.0, *) public struct CompressionAlgorithmSet: OptionSet, Hashable, Sendable { public var rawValue: UInt32 @@ -84,6 +86,7 @@ public struct CompressionAlgorithmSet: OptionSet, Hashable, Sendable { } } +@available(gRPCSwift 2.0, *) extension CompressionAlgorithmSet { /// A sequence of ``CompressionAlgorithm`` values present in the set. public var elements: Elements { diff --git a/Sources/GRPCCore/Coding/GRPCContiguousBytes.swift b/Sources/GRPCCore/Coding/GRPCContiguousBytes.swift index 93adb45fb..79930ab01 100644 --- a/Sources/GRPCCore/Coding/GRPCContiguousBytes.swift +++ b/Sources/GRPCCore/Coding/GRPCContiguousBytes.swift @@ -19,6 +19,7 @@ /// This protocol is used by the transport protocols (``ClientTransport`` and ``ServerTransport``) /// with the serialization protocols (``MessageSerializer`` and ``MessageDeserializer``) so that /// messages don't have to be copied to a fixed intermediate bag-of-bytes types. +@available(gRPCSwift 2.0, *) public protocol GRPCContiguousBytes { /// Initialize the bytes to a repeated value. /// @@ -55,4 +56,5 @@ public protocol GRPCContiguousBytes { ) rethrows -> R } +@available(gRPCSwift 2.0, *) extension [UInt8]: GRPCContiguousBytes {} diff --git a/Sources/GRPCCore/Configuration/MethodConfig.swift b/Sources/GRPCCore/Configuration/MethodConfig.swift index 2de35e5a4..3decbfe58 100644 --- a/Sources/GRPCCore/Configuration/MethodConfig.swift +++ b/Sources/GRPCCore/Configuration/MethodConfig.swift @@ -17,6 +17,7 @@ /// Configuration values for executing an RPC. /// /// See also: https://github.com/grpc/grpc-proto/blob/0b30c8c05277ab78ec72e77c9cbf66a26684673d/grpc/service_config/service_config.proto +@available(gRPCSwift 2.0, *) public struct MethodConfig: Hashable, Sendable { /// The name of a method to which the method config applies. public struct Name: Sendable, Hashable { @@ -145,6 +146,7 @@ public struct MethodConfig: Hashable, Sendable { } /// Whether an RPC should be retried or hedged. +@available(gRPCSwift 2.0, *) public struct RPCExecutionPolicy: Hashable, Sendable { @usableFromInline enum Wrapped: Hashable, Sendable { @@ -214,6 +216,7 @@ public struct RPCExecutionPolicy: Hashable, Sendable { /// /// For more information see [gRFC A6 Client /// Retries](https://github.com/grpc/proposal/blob/0e1807a6e30a1a915c0dcadc873bca92b9fa9720/A6-client-retries.md). +@available(gRPCSwift 2.0, *) public struct RetryPolicy: Hashable, Sendable { /// The maximum number of RPC attempts, including the original attempt. /// @@ -331,6 +334,7 @@ public struct RetryPolicy: Hashable, Sendable { /// /// For more information see [gRFC A6 Client /// Retries](https://github.com/grpc/proposal/blob/0e1807a6e30a1a915c0dcadc873bca92b9fa9720/A6-client-retries.md). +@available(gRPCSwift 2.0, *) public struct HedgingPolicy: Hashable, Sendable { /// The maximum number of RPC attempts, including the original attempt. /// @@ -384,6 +388,7 @@ public struct HedgingPolicy: Hashable, Sendable { } } +@available(gRPCSwift 2.0, *) private func validateMaxAttempts(_ value: Int) throws -> Int { guard value > 1 else { throw RuntimeError( @@ -395,6 +400,7 @@ private func validateMaxAttempts(_ value: Int) throws -> Int { return min(value, 5) } +@available(gRPCSwift 2.0, *) extension MethodConfig: Codable { private enum CodingKeys: String, CodingKey { case name @@ -453,6 +459,7 @@ extension MethodConfig: Codable { } } +@available(gRPCSwift 2.0, *) extension MethodConfig.Name: Codable { private enum CodingKeys: String, CodingKey { case service @@ -478,6 +485,7 @@ extension MethodConfig.Name: Codable { } } +@available(gRPCSwift 2.0, *) extension RetryPolicy: Codable { private enum CodingKeys: String, CodingKey { case maxAttempts @@ -525,6 +533,7 @@ extension RetryPolicy: Codable { } } +@available(gRPCSwift 2.0, *) extension HedgingPolicy: Codable { private enum CodingKeys: String, CodingKey { case maxAttempts @@ -556,6 +565,7 @@ extension HedgingPolicy: Codable { } } +@available(gRPCSwift 2.0, *) struct GoogleProtobufDuration: Codable { var duration: Duration @@ -593,6 +603,7 @@ struct GoogleProtobufDuration: Codable { } } +@available(gRPCSwift 2.0, *) struct GoogleRPCCode: Codable { var code: Status.Code @@ -625,6 +636,7 @@ struct GoogleRPCCode: Codable { } } +@available(gRPCSwift 2.0, *) extension Status.Code { fileprivate init?(googleRPCCode code: String) { switch code { diff --git a/Sources/GRPCCore/Configuration/ServiceConfig.swift b/Sources/GRPCCore/Configuration/ServiceConfig.swift index 805e5ea59..a96119f1e 100644 --- a/Sources/GRPCCore/Configuration/ServiceConfig.swift +++ b/Sources/GRPCCore/Configuration/ServiceConfig.swift @@ -22,6 +22,7 @@ /// The schema is described by [`grpc/service_config/service_config.proto`](https://github.com/grpc/grpc-proto/blob/0b30c8c05277ab78ec72e77c9cbf66a26684673d/grpc/service_config/service_config.proto) /// in the `grpc/grpc-proto` GitHub repository although gRPC uses it in its JSON form rather than /// the Protobuf form. +@available(gRPCSwift 2.0, *) public struct ServiceConfig: Hashable, Sendable { /// Per-method configuration. public var methodConfig: [MethodConfig] @@ -67,6 +68,7 @@ public struct ServiceConfig: Hashable, Sendable { } } +@available(gRPCSwift 2.0, *) extension ServiceConfig: Codable { private enum CodingKeys: String, CodingKey { case methodConfig @@ -103,6 +105,7 @@ extension ServiceConfig: Codable { } } +@available(gRPCSwift 2.0, *) extension ServiceConfig { /// Configuration used by clients for load-balancing. public struct LoadBalancingConfig: Hashable, Sendable { @@ -168,6 +171,7 @@ extension ServiceConfig { } } +@available(gRPCSwift 2.0, *) extension ServiceConfig.LoadBalancingConfig { /// Configuration for the pick-first load balancing policy. public struct PickFirst: Hashable, Sendable, Codable { @@ -195,6 +199,7 @@ extension ServiceConfig.LoadBalancingConfig { } } +@available(gRPCSwift 2.0, *) extension ServiceConfig.LoadBalancingConfig: Codable { private enum CodingKeys: String, CodingKey { case roundRobin = "round_robin" @@ -225,6 +230,7 @@ extension ServiceConfig.LoadBalancingConfig: Codable { } } +@available(gRPCSwift 2.0, *) extension ServiceConfig { public struct RetryThrottling: Hashable, Sendable, Codable { /// The initial, and maximum number of tokens. diff --git a/Sources/GRPCCore/GRPCClient.swift b/Sources/GRPCCore/GRPCClient.swift index ffb6911ae..a41c8b261 100644 --- a/Sources/GRPCCore/GRPCClient.swift +++ b/Sources/GRPCCore/GRPCClient.swift @@ -54,6 +54,7 @@ private import Synchronization /// more abruptly you can cancel the task running your client. If your application requires /// additional resources that need their lifecycles managed you should consider using [Swift Service /// Lifecycle](https://github.com/swift-server/swift-service-lifecycle). +@available(gRPCSwift 2.0, *) public final class GRPCClient: Sendable { /// The transport which provides a bidirectional communication channel with the server. private let transport: Transport @@ -397,6 +398,7 @@ public final class GRPCClient: Sendable { /// code is nonisolated. /// - handleClient: A closure which is called with the client. When the closure returns, the /// client is shutdown gracefully. +@available(gRPCSwift 2.0, *) public func withGRPCClient( transport: Transport, interceptors: [any ClientInterceptor] = [], @@ -425,6 +427,7 @@ public func withGRPCClient( /// - handleClient: A closure which is called with the client. When the closure returns, the /// client is shutdown gracefully. /// - Returns: The result of the `handleClient` closure. +@available(gRPCSwift 2.0, *) public func withGRPCClient( transport: Transport, interceptorPipeline: [ConditionalInterceptor], diff --git a/Sources/GRPCCore/GRPCServer.swift b/Sources/GRPCCore/GRPCServer.swift index 832e3cdec..d2ca1ed77 100644 --- a/Sources/GRPCCore/GRPCServer.swift +++ b/Sources/GRPCCore/GRPCServer.swift @@ -75,6 +75,7 @@ private import Synchronization /// that need their lifecycles managed you should consider using [Swift Service /// Lifecycle](https://github.com/swift-server/swift-service-lifecycle) and the /// `GRPCServiceLifecycle` module provided by [gRPC Swift Extras](https://github.com/grpc/grpc-swift-extras). +@available(gRPCSwift 2.0, *) public final class GRPCServer: Sendable { typealias Stream = RPCStream @@ -257,6 +258,7 @@ public final class GRPCServer: Sendable { /// - handleServer: A closure which is called with the server. When the closure returns, the /// server is shutdown gracefully. /// - Returns: The result of the `handleServer` closure. +@available(gRPCSwift 2.0, *) public func withGRPCServer( transport: Transport, services: [any RegistrableRPCService], @@ -288,6 +290,7 @@ public func withGRPCServer( /// - handleServer: A closure which is called with the server. When the closure returns, the /// server is shutdown gracefully. /// - Returns: The result of the `handleServer` closure. +@available(gRPCSwift 2.0, *) public func withGRPCServer( transport: Transport, services: [any RegistrableRPCService], diff --git a/Sources/GRPCCore/Internal/Concurrency Primitives/UnsafeTransfer.swift b/Sources/GRPCCore/Internal/Concurrency Primitives/UnsafeTransfer.swift index bc82d0255..a9b4ea090 100644 --- a/Sources/GRPCCore/Internal/Concurrency Primitives/UnsafeTransfer.swift +++ b/Sources/GRPCCore/Internal/Concurrency Primitives/UnsafeTransfer.swift @@ -14,6 +14,7 @@ * limitations under the License. */ +@available(gRPCSwift 2.0, *) @usableFromInline struct UnsafeTransfer { @usableFromInline @@ -25,4 +26,5 @@ struct UnsafeTransfer { } } +@available(gRPCSwift 2.0, *) extension UnsafeTransfer: @unchecked Sendable {} diff --git a/Sources/GRPCCore/Internal/Metadata+GRPC.swift b/Sources/GRPCCore/Internal/Metadata+GRPC.swift index bb1c74a0d..76c7e459d 100644 --- a/Sources/GRPCCore/Internal/Metadata+GRPC.swift +++ b/Sources/GRPCCore/Internal/Metadata+GRPC.swift @@ -14,6 +14,7 @@ * limitations under the License. */ +@available(gRPCSwift 2.0, *) extension Metadata { @inlinable var previousRPCAttempts: Int? { @@ -51,6 +52,7 @@ extension Metadata { } } +@available(gRPCSwift 2.0, *) extension Metadata { @usableFromInline enum GRPCKey: String, Sendable, Hashable { @@ -75,6 +77,7 @@ extension Metadata { } } +@available(gRPCSwift 2.0, *) extension Metadata { @usableFromInline enum RetryPushback: Hashable, Sendable { diff --git a/Sources/GRPCCore/Internal/MethodConfigs.swift b/Sources/GRPCCore/Internal/MethodConfigs.swift index 6aab8858d..326237def 100644 --- a/Sources/GRPCCore/Internal/MethodConfigs.swift +++ b/Sources/GRPCCore/Internal/MethodConfigs.swift @@ -22,6 +22,7 @@ /// service, or set a default configuration for all methods by calling ``setDefaultConfig(_:)``. /// /// Use the subscript to get and set configurations for specific methods. +@available(gRPCSwift 2.0, *) package struct MethodConfigs: Sendable, Hashable { private var elements: [MethodConfig.Name: MethodConfig] diff --git a/Sources/GRPCCore/Internal/Result+Catching.swift b/Sources/GRPCCore/Internal/Result+Catching.swift index 8f9cbe59c..07258ca58 100644 --- a/Sources/GRPCCore/Internal/Result+Catching.swift +++ b/Sources/GRPCCore/Internal/Result+Catching.swift @@ -19,6 +19,7 @@ extension Result { /// /// - Parameter body: An `async` closure to catch the result of. @inlinable + @available(gRPCSwift 2.0, *) init(catching body: () async throws(Failure) -> Success) async { do { self = .success(try await body()) @@ -35,6 +36,7 @@ extension Result { /// - errorType: The type of error to cast to. /// - buildError: A closure which constructs the desired error if the cast fails. @inlinable + @available(gRPCSwift 2.0, *) func castError( to errorType: NewError.Type = NewError.self, or buildError: (any Error) -> NewError diff --git a/Sources/GRPCCore/Internal/String+Extensions.swift b/Sources/GRPCCore/Internal/String+Extensions.swift index f230c1ffe..dd4d68397 100644 --- a/Sources/GRPCCore/Internal/String+Extensions.swift +++ b/Sources/GRPCCore/Internal/String+Extensions.swift @@ -29,6 +29,7 @@ extension UInt8 { @inlinable + @available(gRPCSwift 2.0, *) var isASCII: Bool { return self <= 127 } @@ -40,6 +41,7 @@ extension String.UTF8View { /// - Parameter bytes: The string constant in the form of a collection of `UInt8` /// - Returns: Whether the collection contains **EXACTLY** this array or no, but by ignoring case. @inlinable + @available(gRPCSwift 2.0, *) func compareCaseInsensitiveASCIIBytes(to other: String.UTF8View) -> Bool { // fast path: we can get the underlying bytes of both let maybeMaybeResult = self.withContiguousStorageIfAvailable { lhsBuffer -> Bool? in @@ -67,6 +69,7 @@ extension String.UTF8View { @inlinable @inline(never) + @available(gRPCSwift 2.0, *) func _compareCaseInsensitiveASCIIBytesSlowPath(to other: String.UTF8View) -> Bool { return self.elementsEqual(other, by: { return (($0 & 0xdf) == ($1 & 0xdf) && $0.isASCII) }) } @@ -74,6 +77,7 @@ extension String.UTF8View { extension String { @inlinable + @available(gRPCSwift 2.0, *) func isEqualCaseInsensitiveASCIIBytes(to: String) -> Bool { return self.utf8.compareCaseInsensitiveASCIIBytes(to: to.utf8) } diff --git a/Sources/GRPCCore/Internal/TaskGroup+CancellableTask.swift b/Sources/GRPCCore/Internal/TaskGroup+CancellableTask.swift index d0f38d6d3..4b6fd5ca8 100644 --- a/Sources/GRPCCore/Internal/TaskGroup+CancellableTask.swift +++ b/Sources/GRPCCore/Internal/TaskGroup+CancellableTask.swift @@ -14,6 +14,7 @@ * limitations under the License. */ +@available(gRPCSwift 2.0, *) extension TaskGroup { /// Adds a child task to the group which is individually cancellable. /// @@ -63,6 +64,7 @@ extension TaskGroup { } } +@available(gRPCSwift 2.0, *) @usableFromInline struct CancellableTaskHandle: Sendable { @usableFromInline diff --git a/Sources/GRPCCore/Metadata.swift b/Sources/GRPCCore/Metadata.swift index 23218b4a1..c9e736eae 100644 --- a/Sources/GRPCCore/Metadata.swift +++ b/Sources/GRPCCore/Metadata.swift @@ -79,6 +79,7 @@ /// - Note: Binary values are encoded as base64 strings when they are sent over the wire, so keys with /// the "-bin" suffix may have string values (rather than binary). These are deserialized automatically when /// using ``subscript(binaryValues:)``. +@available(gRPCSwift 2.0, *) public struct Metadata: Sendable, Hashable { /// A metadata value. It can either be a simple string, or binary data. @@ -262,6 +263,7 @@ public struct Metadata: Sendable, Hashable { } } +@available(gRPCSwift 2.0, *) extension Metadata: RandomAccessCollection { public typealias Element = (key: String, value: Value) @@ -302,6 +304,7 @@ extension Metadata: RandomAccessCollection { } } +@available(gRPCSwift 2.0, *) extension Metadata { /// A sequence of metadata values for a given key. public struct Values: Sequence, Sendable { @@ -349,8 +352,8 @@ extension Metadata { } } +@available(gRPCSwift 2.0, *) extension Metadata { - /// A sequence of metadata string values for a given key. public struct StringValues: Sequence, Sendable { /// An iterator for all string values associated with a given key. @@ -399,6 +402,7 @@ extension Metadata { } } +@available(gRPCSwift 2.0, *) extension Metadata { /// A sequence of metadata binary values for a given key. public struct BinaryValues: Sequence, Sendable { @@ -460,30 +464,35 @@ extension Metadata { } } +@available(gRPCSwift 2.0, *) extension Metadata: ExpressibleByDictionaryLiteral { public init(dictionaryLiteral elements: (String, Value)...) { self.elements = elements.map { KeyValuePair(key: $0, value: $1) } } } +@available(gRPCSwift 2.0, *) extension Metadata: ExpressibleByArrayLiteral { public init(arrayLiteral elements: (String, Value)...) { self.elements = elements.map { KeyValuePair(key: $0, value: $1) } } } +@available(gRPCSwift 2.0, *) extension Metadata.Value: ExpressibleByStringLiteral { public init(stringLiteral value: StringLiteralType) { self = .string(value) } } +@available(gRPCSwift 2.0, *) extension Metadata.Value: ExpressibleByStringInterpolation { public init(stringInterpolation: DefaultStringInterpolation) { self = .string(String(stringInterpolation: stringInterpolation)) } } +@available(gRPCSwift 2.0, *) extension Metadata.Value: ExpressibleByArrayLiteral { public typealias ArrayLiteralElement = UInt8 @@ -492,6 +501,7 @@ extension Metadata.Value: ExpressibleByArrayLiteral { } } +@available(gRPCSwift 2.0, *) extension Metadata: CustomStringConvertible { public var description: String { if self.isEmpty { @@ -504,6 +514,7 @@ extension Metadata: CustomStringConvertible { } } +@available(gRPCSwift 2.0, *) extension Metadata.Value: CustomStringConvertible { public var description: String { switch self { @@ -515,6 +526,7 @@ extension Metadata.Value: CustomStringConvertible { } } +@available(gRPCSwift 2.0, *) extension Metadata.Value: CustomDebugStringConvertible { public var debugDescription: String { switch self { diff --git a/Sources/GRPCCore/MethodDescriptor.swift b/Sources/GRPCCore/MethodDescriptor.swift index 20a1f3f50..a677ff982 100644 --- a/Sources/GRPCCore/MethodDescriptor.swift +++ b/Sources/GRPCCore/MethodDescriptor.swift @@ -15,6 +15,7 @@ */ /// A description of a method on a service. +@available(gRPCSwift 2.0, *) public struct MethodDescriptor: Sendable, Hashable { /// A description of the service, including its package name. public var service: ServiceDescriptor @@ -53,6 +54,7 @@ public struct MethodDescriptor: Sendable, Hashable { } } +@available(gRPCSwift 2.0, *) extension MethodDescriptor: CustomStringConvertible { public var description: String { self.fullyQualifiedMethod diff --git a/Sources/GRPCCore/RPCError.swift b/Sources/GRPCCore/RPCError.swift index 80157034c..e6baf1d2b 100644 --- a/Sources/GRPCCore/RPCError.swift +++ b/Sources/GRPCCore/RPCError.swift @@ -17,6 +17,7 @@ /// An error representing the outcome of an RPC. /// /// See also ``Status``. +@available(gRPCSwift 2.0, *) public struct RPCError: Sendable, Hashable, Error { /// A code representing the high-level domain of the error. public var code: Code @@ -116,6 +117,7 @@ public struct RPCError: Sendable, Hashable, Error { } } +@available(gRPCSwift 2.0, *) extension RPCError: CustomStringConvertible { public var description: String { if let cause = self.cause { @@ -126,6 +128,7 @@ extension RPCError: CustomStringConvertible { } } +@available(gRPCSwift 2.0, *) extension RPCError { public struct Code: Hashable, Sendable, CustomStringConvertible { /// The numeric value of the error code. @@ -173,6 +176,7 @@ extension RPCError { } } +@available(gRPCSwift 2.0, *) extension RPCError.Code { /// The operation was cancelled (typically by the caller). public static let cancelled = Self(code: .cancelled) @@ -282,6 +286,7 @@ extension RPCError.Code { /// /// You can conform types to this protocol to have more control over the status codes and /// error information provided to clients when a service throws an error. +@available(gRPCSwift 2.0, *) public protocol RPCErrorConvertible { /// The error code to terminate the RPC with. var rpcErrorCode: RPCError.Code { get } @@ -301,6 +306,7 @@ public protocol RPCErrorConvertible { var rpcErrorCause: (any Error)? { get } } +@available(gRPCSwift 2.0, *) extension RPCErrorConvertible { /// Metadata associated with the error. /// @@ -318,6 +324,7 @@ extension RPCErrorConvertible { } } +@available(gRPCSwift 2.0, *) extension RPCErrorConvertible where Self: Error { /// The original error which led to this error being thrown. public var rpcErrorCause: (any Error)? { @@ -325,6 +332,7 @@ extension RPCErrorConvertible where Self: Error { } } +@available(gRPCSwift 2.0, *) extension RPCError { /// Create a new error by converting the given value. public init(_ convertible: some RPCErrorConvertible) { diff --git a/Sources/GRPCCore/RuntimeError.swift b/Sources/GRPCCore/RuntimeError.swift index 357aa59f7..62d82f8ed 100644 --- a/Sources/GRPCCore/RuntimeError.swift +++ b/Sources/GRPCCore/RuntimeError.swift @@ -18,6 +18,7 @@ /// /// In contrast to ``RPCError``, the ``RuntimeError`` represents errors which happen at a scope /// wider than an individual RPC. For example, passing invalid configuration values. +@available(gRPCSwift 2.0, *) public struct RuntimeError: Error, Hashable, Sendable { /// The code indicating the domain of the error. public var code: Code @@ -51,6 +52,7 @@ public struct RuntimeError: Error, Hashable, Sendable { } } +@available(gRPCSwift 2.0, *) extension RuntimeError: CustomStringConvertible { public var description: String { if let cause = self.cause { @@ -61,6 +63,7 @@ extension RuntimeError: CustomStringConvertible { } } +@available(gRPCSwift 2.0, *) extension RuntimeError { public struct Code: Hashable, Sendable { private enum Value { @@ -109,6 +112,7 @@ extension RuntimeError { } } +@available(gRPCSwift 2.0, *) extension RuntimeError.Code: CustomStringConvertible { public var description: String { String(describing: self.value) diff --git a/Sources/GRPCCore/ServiceDescriptor.swift b/Sources/GRPCCore/ServiceDescriptor.swift index 3a9709d83..a8b7d3abd 100644 --- a/Sources/GRPCCore/ServiceDescriptor.swift +++ b/Sources/GRPCCore/ServiceDescriptor.swift @@ -15,6 +15,7 @@ */ /// A description of a service. +@available(gRPCSwift 2.0, *) public struct ServiceDescriptor: Sendable, Hashable { /// The name of the package the service belongs to. For example, "helloworld". /// An empty string means that the service does not belong to any package. @@ -60,6 +61,7 @@ public struct ServiceDescriptor: Sendable, Hashable { } } +@available(gRPCSwift 2.0, *) extension ServiceDescriptor: CustomStringConvertible { public var description: String { self.fullyQualifiedService diff --git a/Sources/GRPCCore/Status.swift b/Sources/GRPCCore/Status.swift index eba8d54f0..2b85d038f 100644 --- a/Sources/GRPCCore/Status.swift +++ b/Sources/GRPCCore/Status.swift @@ -24,6 +24,7 @@ /// ``Status`` represents the raw outcome of an RPC whether it was successful or not; ``RPCError`` /// is similar to ``Status`` but only represents error cases, in other words represents all status /// codes apart from ``Code-swift.struct/ok``. +@available(gRPCSwift 2.0, *) public struct Status: @unchecked Sendable, Hashable { // @unchecked because it relies on heap allocated storage and 'isKnownUniquelyReferenced' @@ -75,12 +76,14 @@ public struct Status: @unchecked Sendable, Hashable { internal static let ok = Status(storage: Storage(code: .ok, message: "")) } +@available(gRPCSwift 2.0, *) extension Status: CustomStringConvertible { public var description: String { "\(self.code): \"\(self.message)\"" } } +@available(gRPCSwift 2.0, *) extension Status { private final class Storage: Hashable { var code: Status.Code @@ -106,6 +109,7 @@ extension Status { } } +@available(gRPCSwift 2.0, *) extension Status { /// Status codes for gRPC operations. /// @@ -189,6 +193,7 @@ extension Status { } } +@available(gRPCSwift 2.0, *) extension Status.Code { /// The operation completed successfully. public static let ok = Self(code: .ok) @@ -297,6 +302,7 @@ extension Status.Code { public static let unauthenticated = Self(code: .unauthenticated) } +@available(gRPCSwift 2.0, *) extension Status { /// Create a status from an HTTP status code for a response which didn't include a gRPC status. /// diff --git a/Sources/GRPCCore/Streaming/Internal/AsyncSequenceOfOne.swift b/Sources/GRPCCore/Streaming/Internal/AsyncSequenceOfOne.swift index 40ea25e71..f0a078c1e 100644 --- a/Sources/GRPCCore/Streaming/Internal/AsyncSequenceOfOne.swift +++ b/Sources/GRPCCore/Streaming/Internal/AsyncSequenceOfOne.swift @@ -14,6 +14,7 @@ * limitations under the License. */ +@available(gRPCSwift 2.0, *) extension RPCAsyncSequence { /// Returns an ``RPCAsyncSequence`` containing just the given element. @inlinable @@ -32,6 +33,7 @@ extension RPCAsyncSequence { /// An `AsyncSequence` of a single value. @usableFromInline +@available(gRPCSwift 2.0, *) struct AsyncSequenceOfOne: AsyncSequence, Sendable { @usableFromInline let result: Result diff --git a/Sources/GRPCCore/Streaming/Internal/BroadcastAsyncSequence+RPCWriter.swift b/Sources/GRPCCore/Streaming/Internal/BroadcastAsyncSequence+RPCWriter.swift index f7e4f72ff..afd8e6661 100644 --- a/Sources/GRPCCore/Streaming/Internal/BroadcastAsyncSequence+RPCWriter.swift +++ b/Sources/GRPCCore/Streaming/Internal/BroadcastAsyncSequence+RPCWriter.swift @@ -14,6 +14,7 @@ * limitations under the License. */ +@available(gRPCSwift 2.0, *) extension BroadcastAsyncSequence.Source: ClosableRPCWriterProtocol { @inlinable func write(contentsOf elements: some Sequence) async throws { diff --git a/Sources/GRPCCore/Streaming/Internal/BroadcastAsyncSequence.swift b/Sources/GRPCCore/Streaming/Internal/BroadcastAsyncSequence.swift index 4e4860508..c40e01585 100644 --- a/Sources/GRPCCore/Streaming/Internal/BroadcastAsyncSequence.swift +++ b/Sources/GRPCCore/Streaming/Internal/BroadcastAsyncSequence.swift @@ -32,6 +32,7 @@ public import Synchronization // should be @usableFromInline /// The expectation is that the number of subscribers will be low; for retries there will be at most /// one subscriber at a time, for hedging there may be at most five subscribers at a time. @usableFromInline +@available(gRPCSwift 2.0, *) struct BroadcastAsyncSequence: Sendable, AsyncSequence { @usableFromInline let _storage: _BroadcastSequenceStorage @@ -85,6 +86,7 @@ struct BroadcastAsyncSequence: Sendable, AsyncSequence { // MARK: - AsyncIterator +@available(gRPCSwift 2.0, *) extension BroadcastAsyncSequence { @usableFromInline struct AsyncIterator: AsyncIteratorProtocol { @@ -111,6 +113,7 @@ extension BroadcastAsyncSequence { // MARK: - Continuation +@available(gRPCSwift 2.0, *) extension BroadcastAsyncSequence { @usableFromInline struct Source: Sendable { @@ -145,6 +148,7 @@ extension BroadcastAsyncSequence { } @usableFromInline +@available(gRPCSwift 2.0, *) enum BroadcastAsyncSequenceError: Error { /// The consumer was too slow. case consumingTooSlow @@ -155,6 +159,7 @@ enum BroadcastAsyncSequenceError: Error { // MARK: - Storage @usableFromInline +@available(gRPCSwift 2.0, *) final class _BroadcastSequenceStorage: Sendable { @usableFromInline let _state: Mutex<_BroadcastSequenceStateMachine> @@ -326,6 +331,7 @@ final class _BroadcastSequenceStorage: Sendable { // MARK: - State machine @usableFromInline +@available(gRPCSwift 2.0, *) struct _BroadcastSequenceStateMachine: Sendable { @usableFromInline typealias ConsumerContinuation = CheckedContinuation @@ -1376,6 +1382,7 @@ struct _BroadcastSequenceStateMachine: Sendable { } } +@available(gRPCSwift 2.0, *) extension _BroadcastSequenceStateMachine { /// A collection of elements tagged with an identifier. /// @@ -1530,6 +1537,7 @@ extension _BroadcastSequenceStateMachine { } } +@available(gRPCSwift 2.0, *) extension _BroadcastSequenceStateMachine { /// A collection of subscriptions. @usableFromInline @@ -1793,6 +1801,7 @@ extension _BroadcastSequenceStateMachine { } } +@available(gRPCSwift 2.0, *) extension _BroadcastSequenceStateMachine { // TODO: tiny array @usableFromInline diff --git a/Sources/GRPCCore/Streaming/Internal/GRPCAsyncThrowingStream.swift b/Sources/GRPCCore/Streaming/Internal/GRPCAsyncThrowingStream.swift index 3eadd1d85..f0ff95878 100644 --- a/Sources/GRPCCore/Streaming/Internal/GRPCAsyncThrowingStream.swift +++ b/Sources/GRPCCore/Streaming/Internal/GRPCAsyncThrowingStream.swift @@ -19,6 +19,7 @@ // 'RPCWriterProtocol'. (Adding a constrained conformance to 'RPCWriterProtocol' on // 'AsyncThrowingStream.Continuation' isn't possible because 'Sendable' is a marker protocol.) +@available(gRPCSwift 2.0, *) package struct GRPCAsyncThrowingStream: AsyncSequence, Sendable { package typealias Element = Element package typealias Failure = any Error @@ -77,6 +78,7 @@ package struct GRPCAsyncThrowingStream: AsyncSequence, Sendab } } +@available(gRPCSwift 2.0, *) extension GRPCAsyncThrowingStream.Continuation: RPCWriterProtocol { package func write(_ element: Element) async throws { self.yield(element) @@ -89,6 +91,7 @@ extension GRPCAsyncThrowingStream.Continuation: RPCWriterProtocol { } } +@available(gRPCSwift 2.0, *) extension GRPCAsyncThrowingStream.Continuation: ClosableRPCWriterProtocol { package func finish() async { self.finish(throwing: nil) diff --git a/Sources/GRPCCore/Streaming/Internal/RPCWriter+Map.swift b/Sources/GRPCCore/Streaming/Internal/RPCWriter+Map.swift index 41332f1f2..d5349d2bf 100644 --- a/Sources/GRPCCore/Streaming/Internal/RPCWriter+Map.swift +++ b/Sources/GRPCCore/Streaming/Internal/RPCWriter+Map.swift @@ -15,6 +15,7 @@ */ @usableFromInline +@available(gRPCSwift 2.0, *) struct MapRPCWriter< Value: Sendable, Mapped: Sendable, @@ -46,6 +47,7 @@ struct MapRPCWriter< } } +@available(gRPCSwift 2.0, *) extension RPCWriter { @inlinable static func map( diff --git a/Sources/GRPCCore/Streaming/Internal/RPCWriter+MessageToRPCResponsePart.swift b/Sources/GRPCCore/Streaming/Internal/RPCWriter+MessageToRPCResponsePart.swift index 84b2f70f3..c1a0a9b51 100644 --- a/Sources/GRPCCore/Streaming/Internal/RPCWriter+MessageToRPCResponsePart.swift +++ b/Sources/GRPCCore/Streaming/Internal/RPCWriter+MessageToRPCResponsePart.swift @@ -15,6 +15,7 @@ */ @usableFromInline +@available(gRPCSwift 2.0, *) struct MessageToRPCResponsePartWriter< Serializer: MessageSerializer, Bytes: GRPCContiguousBytes & Sendable @@ -48,6 +49,7 @@ struct MessageToRPCResponsePartWriter< } } +@available(gRPCSwift 2.0, *) extension RPCWriter { @inlinable static func serializingToRPCResponsePart( diff --git a/Sources/GRPCCore/Streaming/Internal/RPCWriter+Serialize.swift b/Sources/GRPCCore/Streaming/Internal/RPCWriter+Serialize.swift index 1eff0c09a..b2c714fee 100644 --- a/Sources/GRPCCore/Streaming/Internal/RPCWriter+Serialize.swift +++ b/Sources/GRPCCore/Streaming/Internal/RPCWriter+Serialize.swift @@ -15,6 +15,7 @@ */ @usableFromInline +@available(gRPCSwift 2.0, *) struct SerializingRPCWriter< Base: RPCWriterProtocol, Bytes: GRPCContiguousBytes, @@ -49,6 +50,7 @@ struct SerializingRPCWriter< } } +@available(gRPCSwift 2.0, *) extension RPCWriter { @inlinable static func serializing( diff --git a/Sources/GRPCCore/Streaming/Internal/UncheckedAsyncIteratorSequence.swift b/Sources/GRPCCore/Streaming/Internal/UncheckedAsyncIteratorSequence.swift index 5b963e3bd..4beae5841 100644 --- a/Sources/GRPCCore/Streaming/Internal/UncheckedAsyncIteratorSequence.swift +++ b/Sources/GRPCCore/Streaming/Internal/UncheckedAsyncIteratorSequence.swift @@ -16,8 +16,9 @@ public import Synchronization // should be @usableFromInline -@usableFromInline /// An `AsyncSequence` which wraps an existing async iterator. +@available(gRPCSwift 2.0, *) +@usableFromInline final class UncheckedAsyncIteratorSequence< Base: AsyncIteratorProtocol >: AsyncSequence, @unchecked Sendable { diff --git a/Sources/GRPCCore/Streaming/RPCAsyncSequence.swift b/Sources/GRPCCore/Streaming/RPCAsyncSequence.swift index edf451179..de44eb5aa 100644 --- a/Sources/GRPCCore/Streaming/RPCAsyncSequence.swift +++ b/Sources/GRPCCore/Streaming/RPCAsyncSequence.swift @@ -15,6 +15,7 @@ */ /// A type-erasing `AsyncSequence`. +@available(gRPCSwift 2.0, *) public struct RPCAsyncSequence< Element: Sendable, Failure: Error diff --git a/Sources/GRPCCore/Streaming/RPCWriter+Closable.swift b/Sources/GRPCCore/Streaming/RPCWriter+Closable.swift index 075c05ad8..51d2824d1 100644 --- a/Sources/GRPCCore/Streaming/RPCWriter+Closable.swift +++ b/Sources/GRPCCore/Streaming/RPCWriter+Closable.swift @@ -14,6 +14,7 @@ * limitations under the License. */ +@available(gRPCSwift 2.0, *) extension RPCWriter { public struct Closable: ClosableRPCWriterProtocol { @usableFromInline diff --git a/Sources/GRPCCore/Streaming/RPCWriter.swift b/Sources/GRPCCore/Streaming/RPCWriter.swift index cc680b01d..866aa974e 100644 --- a/Sources/GRPCCore/Streaming/RPCWriter.swift +++ b/Sources/GRPCCore/Streaming/RPCWriter.swift @@ -15,6 +15,7 @@ */ /// A type-erasing ``RPCWriterProtocol``. +@available(gRPCSwift 2.0, *) public struct RPCWriter: Sendable, RPCWriterProtocol { private let writer: any RPCWriterProtocol diff --git a/Sources/GRPCCore/Streaming/RPCWriterProtocol.swift b/Sources/GRPCCore/Streaming/RPCWriterProtocol.swift index 2f1c706d5..bde8369ec 100644 --- a/Sources/GRPCCore/Streaming/RPCWriterProtocol.swift +++ b/Sources/GRPCCore/Streaming/RPCWriterProtocol.swift @@ -15,6 +15,7 @@ */ /// A type into which values can be written indefinitely. +@available(gRPCSwift 2.0, *) public protocol RPCWriterProtocol: Sendable { /// The type of value written. associatedtype Element: Sendable @@ -36,6 +37,7 @@ public protocol RPCWriterProtocol: Sendable { func write(contentsOf elements: some Sequence) async throws } +@available(gRPCSwift 2.0, *) extension RPCWriterProtocol { /// Writes an `AsyncSequence` of values into the sink. /// @@ -50,6 +52,7 @@ extension RPCWriterProtocol { } /// A type into which values can be written until it is finished. +@available(gRPCSwift 2.0, *) public protocol ClosableRPCWriterProtocol: RPCWriterProtocol { /// Indicate to the writer that no more writes are to be accepted. /// diff --git a/Sources/GRPCCore/Timeout.swift b/Sources/GRPCCore/Timeout.swift index 68fa49779..c7150b99c 100644 --- a/Sources/GRPCCore/Timeout.swift +++ b/Sources/GRPCCore/Timeout.swift @@ -23,6 +23,7 @@ internal import Dispatch /// /// Timeouts must be positive and at most 8-digits long. @usableFromInline +@available(gRPCSwift 2.0, *) struct Timeout: CustomStringConvertible, Hashable, Sendable { /// Possible units for a ``Timeout``. internal enum Unit: Character { @@ -181,6 +182,7 @@ extension Int64 { } } +@available(gRPCSwift 2.0, *) extension Duration { /// Construct a `Duration` given a number of minutes represented as an `Int64`. /// diff --git a/Sources/GRPCCore/Transport/ClientTransport.swift b/Sources/GRPCCore/Transport/ClientTransport.swift index 8c2e8a07e..4b3cf6545 100644 --- a/Sources/GRPCCore/Transport/ClientTransport.swift +++ b/Sources/GRPCCore/Transport/ClientTransport.swift @@ -25,6 +25,7 @@ /// gRPC provides an in-process transport in the `GRPCInProcessTransport` module and HTTP/2 /// transport built on top of SwiftNIO in the https://github.com/grpc/grpc-swift-nio-transport /// package. +@available(gRPCSwift 2.0, *) public protocol ClientTransport: Sendable { /// The bag-of-bytes type used by the transport. associatedtype Bytes: GRPCContiguousBytes & Sendable diff --git a/Sources/GRPCCore/Transport/RPCParts.swift b/Sources/GRPCCore/Transport/RPCParts.swift index ba19d58b4..8ebf12787 100644 --- a/Sources/GRPCCore/Transport/RPCParts.swift +++ b/Sources/GRPCCore/Transport/RPCParts.swift @@ -15,6 +15,7 @@ */ /// Part of a request sent from a client to a server in a stream. +@available(gRPCSwift 2.0, *) public enum RPCRequestPart { /// Key-value pairs sent at the start of a request stream. Only one ``metadata(_:)`` value may /// be sent to the server. @@ -26,11 +27,15 @@ public enum RPCRequestPart { case message(Bytes) } +@available(gRPCSwift 2.0, *) extension RPCRequestPart: Sendable where Bytes: Sendable {} +@available(gRPCSwift 2.0, *) extension RPCRequestPart: Hashable where Bytes: Hashable {} +@available(gRPCSwift 2.0, *) extension RPCRequestPart: Equatable where Bytes: Equatable {} /// Part of a response sent from a server to a client in a stream. +@available(gRPCSwift 2.0, *) public enum RPCResponsePart { /// Key-value pairs sent at the start of the response stream. At most one ``metadata(_:)`` value /// may be sent to the client. If the server sends ``metadata(_:)`` it must be the first part in @@ -48,6 +53,9 @@ public enum RPCResponsePart { case status(Status, Metadata) } +@available(gRPCSwift 2.0, *) extension RPCResponsePart: Sendable where Bytes: Sendable {} +@available(gRPCSwift 2.0, *) extension RPCResponsePart: Hashable where Bytes: Hashable {} +@available(gRPCSwift 2.0, *) extension RPCResponsePart: Equatable where Bytes: Equatable {} diff --git a/Sources/GRPCCore/Transport/RPCStream.swift b/Sources/GRPCCore/Transport/RPCStream.swift index 445d27f45..0c976265f 100644 --- a/Sources/GRPCCore/Transport/RPCStream.swift +++ b/Sources/GRPCCore/Transport/RPCStream.swift @@ -15,6 +15,7 @@ */ /// A bidirectional communication channel between a client and server for a given method. +@available(gRPCSwift 2.0, *) public struct RPCStream< Inbound: AsyncSequence & Sendable, Outbound: ClosableRPCWriterProtocol & Sendable diff --git a/Sources/GRPCCore/Transport/RetryThrottle.swift b/Sources/GRPCCore/Transport/RetryThrottle.swift index 6b52739d9..7c6b05baa 100644 --- a/Sources/GRPCCore/Transport/RetryThrottle.swift +++ b/Sources/GRPCCore/Transport/RetryThrottle.swift @@ -30,6 +30,7 @@ private import Synchronization /// the server. /// /// See also [gRFC A6: client retries](https://github.com/grpc/proposal/blob/0e1807a6e30a1a915c0dcadc873bca92b9fa9720/A6-client-retries.md). +@available(gRPCSwift 2.0, *) public final class RetryThrottle: Sendable { // Note: only three figures after the decimal point from the original token ratio are used so // all computation is done a scaled number of tokens (tokens * 1000). This allows us to do all diff --git a/Sources/GRPCCore/Transport/ServerTransport.swift b/Sources/GRPCCore/Transport/ServerTransport.swift index c3f2c7df7..d3891147d 100644 --- a/Sources/GRPCCore/Transport/ServerTransport.swift +++ b/Sources/GRPCCore/Transport/ServerTransport.swift @@ -22,6 +22,7 @@ /// gRPC provides an in-process transport in the `GRPCInProcessTransport` module and HTTP/2 /// transport built on top of SwiftNIO in the https://github.com/grpc/grpc-swift-nio-transport /// package. +@available(gRPCSwift 2.0, *) public protocol ServerTransport: Sendable { /// The bag-of-bytes type used by the transport. associatedtype Bytes: GRPCContiguousBytes & Sendable diff --git a/Sources/GRPCInProcessTransport/InProcessTransport+Client.swift b/Sources/GRPCInProcessTransport/InProcessTransport+Client.swift index 070f08b67..703b9f62c 100644 --- a/Sources/GRPCInProcessTransport/InProcessTransport+Client.swift +++ b/Sources/GRPCInProcessTransport/InProcessTransport+Client.swift @@ -17,6 +17,7 @@ public import GRPCCore private import Synchronization +@available(gRPCSwift 2.0, *) extension InProcessTransport { /// An in-process implementation of a `ClientTransport`. /// diff --git a/Sources/GRPCInProcessTransport/InProcessTransport+Server.swift b/Sources/GRPCInProcessTransport/InProcessTransport+Server.swift index 11ce7a792..cc01e2046 100644 --- a/Sources/GRPCInProcessTransport/InProcessTransport+Server.swift +++ b/Sources/GRPCInProcessTransport/InProcessTransport+Server.swift @@ -17,6 +17,7 @@ public import GRPCCore private import Synchronization +@available(gRPCSwift 2.0, *) extension InProcessTransport { /// An in-process implementation of a `ServerTransport`. /// diff --git a/Sources/GRPCInProcessTransport/InProcessTransport.swift b/Sources/GRPCInProcessTransport/InProcessTransport.swift index e73beee91..4dc5d3f83 100644 --- a/Sources/GRPCInProcessTransport/InProcessTransport.swift +++ b/Sources/GRPCInProcessTransport/InProcessTransport.swift @@ -16,6 +16,7 @@ public import GRPCCore +@available(gRPCSwift 2.0, *) public struct InProcessTransport: Sendable { public let server: Self.Server public let client: Self.Client diff --git a/Tests/GRPCCodeGenTests/Internal/Renderer/TextBasedRendererTests.swift b/Tests/GRPCCodeGenTests/Internal/Renderer/TextBasedRendererTests.swift index 036eb41e9..080204962 100644 --- a/Tests/GRPCCodeGenTests/Internal/Renderer/TextBasedRendererTests.swift +++ b/Tests/GRPCCodeGenTests/Internal/Renderer/TextBasedRendererTests.swift @@ -30,8 +30,8 @@ import XCTest @testable import GRPCCodeGen +@available(gRPCSwift 2.0, *) final class Test_TextBasedRenderer: XCTestCase { - func testComment() throws { try _test( .inline( @@ -1029,6 +1029,7 @@ final class Test_TextBasedRenderer: XCTestCase { } } +@available(gRPCSwift 2.0, *) extension Test_TextBasedRenderer { func _test( _ input: Input, diff --git a/Tests/GRPCCodeGenTests/Internal/StructuredSwift+ClientTests.swift b/Tests/GRPCCodeGenTests/Internal/StructuredSwift+ClientTests.swift index 700a8b895..4e697a87e 100644 --- a/Tests/GRPCCodeGenTests/Internal/StructuredSwift+ClientTests.swift +++ b/Tests/GRPCCodeGenTests/Internal/StructuredSwift+ClientTests.swift @@ -26,6 +26,7 @@ extension StructuredSwiftTests { arguments: AccessModifier.allCases, RPCKind.allCases ) + @available(gRPCSwift 2.0, *) func clientMethodSignature(access: AccessModifier, kind: RPCKind) { let decl: FunctionSignatureDescription = .clientMethod( accessLevel: access, @@ -59,6 +60,7 @@ extension StructuredSwiftTests { arguments: AccessModifier.allCases, [true, false] ) + @available(gRPCSwift 2.0, *) func clientMethodSignatureWithDefaults(access: AccessModifier, streamsOutput: Bool) { let decl: FunctionSignatureDescription = .clientMethod( accessLevel: access, @@ -96,6 +98,7 @@ extension StructuredSwiftTests { } @Test("protocol Foo_ClientProtocol: Sendable { ... }", arguments: AccessModifier.allCases) + @available(gRPCSwift 2.0, *) func clientProtocol(access: AccessModifier) { let decl: ProtocolDescription = .clientProtocol( accessLevel: access, @@ -143,6 +146,7 @@ extension StructuredSwiftTests { } @Test("func foo(...) { try await self.foo(...) }", arguments: AccessModifier.allCases) + @available(gRPCSwift 2.0, *) func clientMethodFunctionWithDefaults(access: AccessModifier) { let decl: FunctionDescription = .clientMethodWithDefaults( accessLevel: access, @@ -180,6 +184,7 @@ extension StructuredSwiftTests { "extension Foo_ClientProtocol { ... } (methods with defaults)", arguments: AccessModifier.allCases ) + @available(gRPCSwift 2.0, *) func extensionWithDefaultClientMethods(access: AccessModifier) { let decl: ExtensionDescription = .clientMethodSignatureWithDefaults( accessLevel: access, @@ -235,6 +240,7 @@ extension StructuredSwiftTests { arguments: AccessModifier.allCases, RPCKind.allCases ) + @available(gRPCSwift 2.0, *) func explodedClientMethodSignature(access: AccessModifier, kind: RPCKind) { let decl: FunctionSignatureDescription = .clientMethodExploded( accessLevel: access, @@ -296,6 +302,7 @@ extension StructuredSwiftTests { "func foo(_:metadata:options:onResponse:) -> Result (exploded body)", arguments: [true, false] ) + @available(gRPCSwift 2.0, *) func explodedClientMethodBody(streamingInput: Bool) { let blocks: [CodeBlock] = .clientMethodExploded( name: "foo", @@ -335,6 +342,7 @@ extension StructuredSwiftTests { } @Test("extension Foo_ClientProtocol { ... } (exploded)", arguments: AccessModifier.allCases) + @available(gRPCSwift 2.0, *) func explodedClientMethodExtension(access: AccessModifier) { let decl: ExtensionDescription = .explodedClientMethods( accessLevel: access, @@ -393,6 +401,7 @@ extension StructuredSwiftTests { "func foo(request:serializer:deserializer:options:onResponse:) (client method impl.)", arguments: AccessModifier.allCases ) + @available(gRPCSwift 2.0, *) func clientMethodImplementation(access: AccessModifier) { let decl: FunctionDescription = .clientMethod( accessLevel: access, @@ -430,6 +439,7 @@ extension StructuredSwiftTests { } @Test("struct FooClient: Foo_ClientProtocol { ... }", arguments: AccessModifier.allCases) + @available(gRPCSwift 2.0, *) func client(access: AccessModifier) { let decl: StructDescription = .client( accessLevel: access, diff --git a/Tests/GRPCCodeGenTests/Internal/StructuredSwift+ImportTests.swift b/Tests/GRPCCodeGenTests/Internal/StructuredSwift+ImportTests.swift index 88a6bc075..fdb8b6813 100644 --- a/Tests/GRPCCodeGenTests/Internal/StructuredSwift+ImportTests.swift +++ b/Tests/GRPCCodeGenTests/Internal/StructuredSwift+ImportTests.swift @@ -18,18 +18,21 @@ import GRPCCodeGen import Testing extension StructuredSwiftTests { - @Suite("Import") - struct Import { - static let translator = IDLToStructuredSwiftTranslator() + @available(gRPCSwift 2.0, *) + static let translator = IDLToStructuredSwiftTranslator() - static let allAccessLevels: [CodeGenerator.Config.AccessLevel] = [ - .internal, .public, .package, - ] + @available(gRPCSwift 2.0, *) + static let allAccessLevels: [CodeGenerator.Config.AccessLevel] = [ + .internal, .public, .package, + ] + @Suite("Import") + struct Import { @Test( "import rendering", arguments: allAccessLevels ) + @available(gRPCSwift 2.0, *) func imports(accessLevel: CodeGenerator.Config.AccessLevel) throws { var dependencies = [Dependency]() dependencies.append(Dependency(module: "Foo", accessLevel: .public)) @@ -104,7 +107,7 @@ extension StructuredSwiftTests { package import func Foo.Bak """ - let imports = try StructuredSwiftTests.Import.translator.makeImports( + let imports = try StructuredSwiftTests.translator.makeImports( dependencies: dependencies, accessLevel: accessLevel, accessLevelOnImports: true, @@ -116,8 +119,9 @@ extension StructuredSwiftTests { @Test( "preconcurrency import rendering", - arguments: allAccessLevels + arguments: StructuredSwiftTests.allAccessLevels ) + @available(gRPCSwift 2.0, *) func preconcurrencyImports(accessLevel: CodeGenerator.Config.AccessLevel) throws { var dependencies = [Dependency]() dependencies.append( @@ -155,7 +159,7 @@ extension StructuredSwiftTests { #endif """ - let imports = try StructuredSwiftTests.Import.translator.makeImports( + let imports = try StructuredSwiftTests.translator.makeImports( dependencies: dependencies, accessLevel: accessLevel, accessLevelOnImports: true, @@ -167,8 +171,9 @@ extension StructuredSwiftTests { @Test( "SPI import rendering", - arguments: allAccessLevels + arguments: StructuredSwiftTests.allAccessLevels ) + @available(gRPCSwift 2.0, *) func spiImports(accessLevel: CodeGenerator.Config.AccessLevel) throws { var dependencies = [Dependency]() dependencies.append( @@ -190,7 +195,7 @@ extension StructuredSwiftTests { @_spi(Secret) internal import enum Foo.Bar """ - let imports = try StructuredSwiftTests.Import.translator.makeImports( + let imports = try StructuredSwiftTests.translator.makeImports( dependencies: dependencies, accessLevel: accessLevel, accessLevelOnImports: true, @@ -201,6 +206,7 @@ extension StructuredSwiftTests { } @Test("gRPC module name") + @available(gRPCSwift 2.0, *) func grpcModuleName() throws { let translator = IDLToStructuredSwiftTranslator() let imports = try translator.makeImports( diff --git a/Tests/GRPCCodeGenTests/Internal/StructuredSwift+MetadataTests.swift b/Tests/GRPCCodeGenTests/Internal/StructuredSwift+MetadataTests.swift index 06c87be43..1f297e66f 100644 --- a/Tests/GRPCCodeGenTests/Internal/StructuredSwift+MetadataTests.swift +++ b/Tests/GRPCCodeGenTests/Internal/StructuredSwift+MetadataTests.swift @@ -22,6 +22,7 @@ extension StructuredSwiftTests { @Suite("Metadata") struct Metadata { @Test("typealias Input = ", arguments: AccessModifier.allCases) + @available(gRPCSwift 2.0, *) func methodInputTypealias(access: AccessModifier) { let decl: TypealiasDescription = .methodInput(accessModifier: access, name: "Foo") let expected = "\(access) typealias Input = Foo" @@ -29,6 +30,7 @@ extension StructuredSwiftTests { } @Test("typealias Output = ", arguments: AccessModifier.allCases) + @available(gRPCSwift 2.0, *) func methodOutputTypealias(access: AccessModifier) { let decl: TypealiasDescription = .methodOutput(accessModifier: access, name: "Foo") let expected = "\(access) typealias Output = Foo" @@ -39,6 +41,7 @@ extension StructuredSwiftTests { "static let descriptor = GRPCCore.MethodDescriptor(...)", arguments: AccessModifier.allCases ) + @available(gRPCSwift 2.0, *) func staticMethodDescriptorProperty(access: AccessModifier) { let decl: VariableDescription = .methodDescriptor( accessModifier: access, @@ -59,6 +62,7 @@ extension StructuredSwiftTests { "static let descriptor = GRPCCore.ServiceDescriptor(fullyQualifiedService:)", arguments: AccessModifier.allCases ) + @available(gRPCSwift 2.0, *) func staticServiceDescriptorProperty(access: AccessModifier) { let decl: VariableDescription = .serviceDescriptor( accessModifier: access, @@ -72,6 +76,7 @@ extension StructuredSwiftTests { } @Test("extension GRPCCore.ServiceDescriptor { ... }", arguments: AccessModifier.allCases) + @available(gRPCSwift 2.0, *) func staticServiceDescriptorPropertyExtension(access: AccessModifier) { let decl: ExtensionDescription = .serviceDescriptor( accessModifier: access, @@ -92,6 +97,7 @@ extension StructuredSwiftTests { "static let descriptors: [GRPCCore.MethodDescriptor] = [...]", arguments: AccessModifier.allCases ) + @available(gRPCSwift 2.0, *) func staticMethodDescriptorsArray(access: AccessModifier) { let decl: VariableDescription = .methodDescriptorsArray( accessModifier: access, @@ -109,6 +115,7 @@ extension StructuredSwiftTests { } @Test("enum { ... }", arguments: AccessModifier.allCases) + @available(gRPCSwift 2.0, *) func methodNamespaceEnum(access: AccessModifier) { let decl: EnumDescription = .methodNamespace( accessModifier: access, @@ -136,6 +143,7 @@ extension StructuredSwiftTests { } @Test("enum Method { ... }", arguments: AccessModifier.allCases) + @available(gRPCSwift 2.0, *) func methodsNamespaceEnum(access: AccessModifier) { let decl: EnumDescription = .methodsNamespace( accessModifier: access, @@ -176,6 +184,7 @@ extension StructuredSwiftTests { } @Test("enum Method { ... } (no methods)", arguments: AccessModifier.allCases) + @available(gRPCSwift 2.0, *) func methodsNamespaceEnumNoMethods(access: AccessModifier) { let decl: EnumDescription = .methodsNamespace( accessModifier: access, @@ -193,6 +202,7 @@ extension StructuredSwiftTests { } @Test("enum { ... }", arguments: AccessModifier.allCases) + @available(gRPCSwift 2.0, *) func serviceNamespaceEnum(access: AccessModifier) { let decl: EnumDescription = .serviceNamespace( accessModifier: access, @@ -239,6 +249,7 @@ extension StructuredSwiftTests { } @Test("enum { ... } (no methods)", arguments: AccessModifier.allCases) + @available(gRPCSwift 2.0, *) func serviceNamespaceEnumNoMethods(access: AccessModifier) { let decl: EnumDescription = .serviceNamespace( accessModifier: access, diff --git a/Tests/GRPCCodeGenTests/Internal/StructuredSwift+ServerTests.swift b/Tests/GRPCCodeGenTests/Internal/StructuredSwift+ServerTests.swift index 7db009ce4..50bfed96f 100644 --- a/Tests/GRPCCodeGenTests/Internal/StructuredSwift+ServerTests.swift +++ b/Tests/GRPCCodeGenTests/Internal/StructuredSwift+ServerTests.swift @@ -26,6 +26,7 @@ extension StructuredSwiftTests { arguments: AccessModifier.allCases, RPCKind.allCases ) + @available(gRPCSwift 2.0, *) func serverMethodSignature(access: AccessModifier, kind: RPCKind) { let decl: FunctionSignatureDescription = .serverMethod( accessLevel: access, @@ -73,6 +74,7 @@ extension StructuredSwiftTests { } @Test("protocol StreamingServiceProtocol { ... }", arguments: AccessModifier.allCases) + @available(gRPCSwift 2.0, *) func serverStreamingServiceProtocol(access: AccessModifier) { let decl: ProtocolDescription = .streamingService( accessLevel: access, @@ -115,6 +117,7 @@ extension StructuredSwiftTests { } @Test("protocol ServiceProtocol { ... }", arguments: AccessModifier.allCases) + @available(gRPCSwift 2.0, *) func serverServiceProtocol(access: AccessModifier) { let decl: ProtocolDescription = .service( accessLevel: access, @@ -158,6 +161,7 @@ extension StructuredSwiftTests { } @Test("{ router, context in try await self.(...) }") + @available(gRPCSwift 2.0, *) func routerHandlerInvokingRPC() { let expression: ClosureInvocationDescription = .routerHandlerInvokingRPC(method: "foo") let expected = """ @@ -172,6 +176,7 @@ extension StructuredSwiftTests { } @Test("router.registerHandler(...) { ... }") + @available(gRPCSwift 2.0, *) func registerMethodsWithRouter() { let expression: FunctionCallDescription = .registerWithRouter( serviceNamespace: "FooService", @@ -199,6 +204,7 @@ extension StructuredSwiftTests { } @Test("func registerMethods(router:)", arguments: AccessModifier.allCases) + @available(gRPCSwift 2.0, *) func registerMethods(access: AccessModifier) { let expression: FunctionDescription = .registerMethods( accessLevel: access, @@ -243,6 +249,7 @@ extension StructuredSwiftTests { arguments: AccessModifier.allCases, RPCKind.allCases ) + @available(gRPCSwift 2.0, *) func serverStreamingMethodsCallingMethod(access: AccessModifier, kind: RPCKind) { let expression: FunctionDescription = .serverStreamingMethodsCallingMethod( accessLevel: access, @@ -314,6 +321,7 @@ extension StructuredSwiftTests { } @Test("extension FooService_ServiceProtocol { ... }", arguments: AccessModifier.allCases) + @available(gRPCSwift 2.0, *) func streamingServiceProtocolDefaultImplementation(access: AccessModifier) { let decl: ExtensionDescription = .streamingServiceProtocolDefaultImplementation( accessModifier: access, @@ -362,6 +370,7 @@ extension StructuredSwiftTests { arguments: AccessModifier.allCases, RPCKind.allCases ) + @available(gRPCSwift 2.0, *) func simpleServerMethod(access: AccessModifier, kind: RPCKind) { let decl: FunctionSignatureDescription = .simpleServerMethod( accessLevel: access, @@ -413,6 +422,7 @@ extension StructuredSwiftTests { } @Test("protocol SimpleServiceProtocol { ... }", arguments: AccessModifier.allCases) + @available(gRPCSwift 2.0, *) func simpleServiceProtocol(access: AccessModifier) { let decl: ProtocolDescription = .simpleServiceProtocol( accessModifier: access, diff --git a/Tests/GRPCCodeGenTests/Internal/StructuredSwiftTestHelpers.swift b/Tests/GRPCCodeGenTests/Internal/StructuredSwiftTestHelpers.swift index b2c0d2847..5146aaaa1 100644 --- a/Tests/GRPCCodeGenTests/Internal/StructuredSwiftTestHelpers.swift +++ b/Tests/GRPCCodeGenTests/Internal/StructuredSwiftTestHelpers.swift @@ -22,24 +22,28 @@ import Testing @Suite("Structured Swift") struct StructuredSwiftTests {} +@available(gRPCSwift 2.0, *) func render(_ declaration: Declaration) -> String { let renderer = TextBasedRenderer(indentation: 2) renderer.renderDeclaration(declaration) return renderer.renderedContents() } +@available(gRPCSwift 2.0, *) func render(_ expression: Expression) -> String { let renderer = TextBasedRenderer(indentation: 2) renderer.renderExpression(expression) return renderer.renderedContents() } +@available(gRPCSwift 2.0, *) func render(_ blocks: [CodeBlock]) -> String { let renderer = TextBasedRenderer(indentation: 2) renderer.renderCodeBlocks(blocks) return renderer.renderedContents() } +@available(gRPCSwift 2.0, *) func render(_ imports: [ImportDescription]) -> String { let renderer = TextBasedRenderer(indentation: 2) renderer.renderImports(imports) diff --git a/Tests/GRPCCodeGenTests/Internal/Translator/ClientCodeTranslatorSnippetBasedTests.swift b/Tests/GRPCCodeGenTests/Internal/Translator/ClientCodeTranslatorSnippetBasedTests.swift index 064791b78..5a449e29e 100644 --- a/Tests/GRPCCodeGenTests/Internal/Translator/ClientCodeTranslatorSnippetBasedTests.swift +++ b/Tests/GRPCCodeGenTests/Internal/Translator/ClientCodeTranslatorSnippetBasedTests.swift @@ -21,6 +21,7 @@ import Testing @Suite struct ClientCodeTranslatorSnippetBasedTests { @Test + @available(gRPCSwift 2.0, *) func translate() { let method = MethodDescriptor( documentation: "/// Documentation for MethodA", @@ -206,6 +207,7 @@ struct ClientCodeTranslatorSnippetBasedTests { #expect(rendered == expectedSwift) } + @available(gRPCSwift 2.0, *) private func render( accessLevel: AccessModifier, service: ServiceDescriptor diff --git a/Tests/GRPCCodeGenTests/Internal/Translator/DocsTests.swift b/Tests/GRPCCodeGenTests/Internal/Translator/DocsTests.swift index 69426663b..c100582a6 100644 --- a/Tests/GRPCCodeGenTests/Internal/Translator/DocsTests.swift +++ b/Tests/GRPCCodeGenTests/Internal/Translator/DocsTests.swift @@ -20,6 +20,7 @@ import Testing @Suite("Docs tests") struct DocsTests { @Test("Suffix with additional docs") + @available(gRPCSwift 2.0, *) func suffixWithAdditional() { let foo = """ /// Foo @@ -42,6 +43,7 @@ struct DocsTests { } @Test("Suffix with empty additional docs") + @available(gRPCSwift 2.0, *) func suffixWithEmptyAdditional() { let foo = """ /// Foo @@ -52,6 +54,7 @@ struct DocsTests { } @Test("Interpose additional docs") + @available(gRPCSwift 2.0, *) func interposeDocs() { let header = """ /// Header @@ -81,6 +84,7 @@ struct DocsTests { } @Test("Interpose empty additional docs") + @available(gRPCSwift 2.0, *) func interposeEmpty() { let header = """ /// Header diff --git a/Tests/GRPCCodeGenTests/Internal/Translator/IDLToStructuredSwiftTranslatorSnippetBasedTests.swift b/Tests/GRPCCodeGenTests/Internal/Translator/IDLToStructuredSwiftTranslatorSnippetBasedTests.swift index eb9c85e5a..33f4b0d87 100644 --- a/Tests/GRPCCodeGenTests/Internal/Translator/IDLToStructuredSwiftTranslatorSnippetBasedTests.swift +++ b/Tests/GRPCCodeGenTests/Internal/Translator/IDLToStructuredSwiftTranslatorSnippetBasedTests.swift @@ -20,6 +20,7 @@ import XCTest @testable import GRPCCodeGen +@available(gRPCSwift 2.0, *) final class IDLToStructuredSwiftTranslatorSnippetBasedTests: XCTestCase { func testGeneration() throws { var dependencies = [Dependency]() diff --git a/Tests/GRPCCodeGenTests/Internal/Translator/ServerCodeTranslatorSnippetBasedTests.swift b/Tests/GRPCCodeGenTests/Internal/Translator/ServerCodeTranslatorSnippetBasedTests.swift index bdbfcba9d..9db99776f 100644 --- a/Tests/GRPCCodeGenTests/Internal/Translator/ServerCodeTranslatorSnippetBasedTests.swift +++ b/Tests/GRPCCodeGenTests/Internal/Translator/ServerCodeTranslatorSnippetBasedTests.swift @@ -21,6 +21,7 @@ import Testing @Suite final class ServerCodeTranslatorSnippetBasedTests { @Test + @available(gRPCSwift 2.0, *) func translate() { let method = MethodDescriptor( documentation: "/// Documentation for unaryMethod", @@ -191,6 +192,7 @@ final class ServerCodeTranslatorSnippetBasedTests { #expect(rendered == expectedSwift) } + @available(gRPCSwift 2.0, *) private func render( accessLevel: AccessModifier, service: ServiceDescriptor diff --git a/Tests/GRPCCodeGenTests/Internal/Translator/TestFunctions.swift b/Tests/GRPCCodeGenTests/Internal/Translator/TestFunctions.swift index afd957638..ee516e0e3 100644 --- a/Tests/GRPCCodeGenTests/Internal/Translator/TestFunctions.swift +++ b/Tests/GRPCCodeGenTests/Internal/Translator/TestFunctions.swift @@ -71,6 +71,7 @@ internal func XCTAssertEqualWithDiff( ) } +@available(gRPCSwift 2.0, *) internal func makeCodeGenerationRequest( services: [ServiceDescriptor] = [], dependencies: [Dependency] = [] diff --git a/Tests/GRPCCodeGenTests/Internal/Translator/TypealiasTranslatorSnippetBasedTests.swift b/Tests/GRPCCodeGenTests/Internal/Translator/TypealiasTranslatorSnippetBasedTests.swift index 4f6168c4b..59250a2e4 100644 --- a/Tests/GRPCCodeGenTests/Internal/Translator/TypealiasTranslatorSnippetBasedTests.swift +++ b/Tests/GRPCCodeGenTests/Internal/Translator/TypealiasTranslatorSnippetBasedTests.swift @@ -21,6 +21,7 @@ import Testing @Suite struct TypealiasTranslatorSnippetBasedTests { @Test + @available(gRPCSwift 2.0, *) func testTypealiasTranslator() throws { let method = MethodDescriptor( documentation: "Documentation for MethodA", @@ -77,6 +78,7 @@ struct TypealiasTranslatorSnippetBasedTests { } } +@available(gRPCSwift 2.0, *) extension TypealiasTranslatorSnippetBasedTests { func render( accessLevel: CodeGenerator.Config.AccessLevel, diff --git a/Tests/GRPCCoreTests/Call/Client/ClientRequestTests.swift b/Tests/GRPCCoreTests/Call/Client/ClientRequestTests.swift index c5f0dbb9f..677228131 100644 --- a/Tests/GRPCCoreTests/Call/Client/ClientRequestTests.swift +++ b/Tests/GRPCCoreTests/Call/Client/ClientRequestTests.swift @@ -18,6 +18,7 @@ import XCTest @testable import GRPCCore +@available(gRPCSwift 2.0, *) final class ClientRequestTests: XCTestCase { func testSingleToStreamConversion() async throws { let (messages, continuation) = AsyncStream.makeStream(of: String.self) diff --git a/Tests/GRPCCoreTests/Call/Client/ClientResponseTests.swift b/Tests/GRPCCoreTests/Call/Client/ClientResponseTests.swift index 46b0f19ae..30df1465c 100644 --- a/Tests/GRPCCoreTests/Call/Client/ClientResponseTests.swift +++ b/Tests/GRPCCoreTests/Call/Client/ClientResponseTests.swift @@ -18,6 +18,7 @@ import XCTest @testable import GRPCCore +@available(gRPCSwift 2.0, *) final class ClientResponseTests: XCTestCase { func testAcceptedSingleResponseConvenienceMethods() { let response = ClientResponse( diff --git a/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTestSupport/ClientRPCExecutorTestHarness+ServerBehavior.swift b/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTestSupport/ClientRPCExecutorTestHarness+ServerBehavior.swift index cf4a4ccc1..11d661dde 100644 --- a/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTestSupport/ClientRPCExecutorTestHarness+ServerBehavior.swift +++ b/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTestSupport/ClientRPCExecutorTestHarness+ServerBehavior.swift @@ -18,6 +18,7 @@ import XCTest @testable import GRPCCore +@available(gRPCSwift 2.0, *) extension ClientRPCExecutorTestHarness { struct ServerStreamHandler: Sendable { private let handler: @@ -58,6 +59,7 @@ extension ClientRPCExecutorTestHarness { } } +@available(gRPCSwift 2.0, *) extension ClientRPCExecutorTestHarness.ServerStreamHandler { static var echo: Self { return Self { stream in diff --git a/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTestSupport/ClientRPCExecutorTestHarness+Transport.swift b/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTestSupport/ClientRPCExecutorTestHarness+Transport.swift index c80a63b7b..c1ae7869a 100644 --- a/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTestSupport/ClientRPCExecutorTestHarness+Transport.swift +++ b/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTestSupport/ClientRPCExecutorTestHarness+Transport.swift @@ -17,6 +17,7 @@ import GRPCCore import GRPCInProcessTransport +@available(gRPCSwift 2.0, *) extension InProcessTransport.Server { func spawnClientTransport( throttle: RetryThrottle = RetryThrottle(maxTokens: 10, tokenRatio: 0.1) diff --git a/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTestSupport/ClientRPCExecutorTestHarness.swift b/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTestSupport/ClientRPCExecutorTestHarness.swift index 2b09af76b..18a5d06c2 100644 --- a/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTestSupport/ClientRPCExecutorTestHarness.swift +++ b/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTestSupport/ClientRPCExecutorTestHarness.swift @@ -25,6 +25,7 @@ import XCTest /// of the server to allow for flexible testing scenarios with minimal boilerplate. The harness /// also tracks how many streams the client has opened, how many streams the server accepted, and /// how many streams the client failed to open. +@available(gRPCSwift 2.0, *) struct ClientRPCExecutorTestHarness { private let server: ServerStreamHandler private let clientTransport: StreamCountingClientTransport diff --git a/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTests+Hedging.swift b/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTests+Hedging.swift index 14b31b0c5..77a64e9e9 100644 --- a/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTests+Hedging.swift +++ b/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTests+Hedging.swift @@ -16,6 +16,7 @@ import GRPCCore import XCTest +@available(gRPCSwift 2.0, *) extension ClientRPCExecutorTests { func testHedgingWhenAllAttemptsResultInNonFatalCodes() async throws { let harness = ClientRPCExecutorTestHarness( @@ -185,6 +186,7 @@ extension ClientRPCExecutorTests { } } +@available(gRPCSwift 2.0, *) extension CallOptions { fileprivate static func hedge( maxAttempts: Int = 5, diff --git a/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTests+Retries.swift b/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTests+Retries.swift index d4e1e210c..e8abaa857 100644 --- a/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTests+Retries.swift +++ b/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTests+Retries.swift @@ -16,6 +16,7 @@ import GRPCCore import XCTest +@available(gRPCSwift 2.0, *) extension ClientRPCExecutorTests { fileprivate func makeHarnessForRetries( rejectUntilAttempt firstSuccessfulAttempt: Int, @@ -288,6 +289,7 @@ extension ClientRPCExecutorTests { } } +@available(gRPCSwift 2.0, *) extension CallOptions { fileprivate static func retry( _ policy: RetryPolicy diff --git a/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTests.swift b/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTests.swift index 4639dedb0..474640f95 100644 --- a/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTests.swift +++ b/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTests.swift @@ -18,6 +18,7 @@ import XCTest @testable import GRPCCore +@available(gRPCSwift 2.0, *) final class ClientRPCExecutorTests: XCTestCase { func testUnaryEcho() async throws { let tester = ClientRPCExecutorTestHarness(server: .echo) diff --git a/Tests/GRPCCoreTests/Call/Client/RetryDelaySequenceTests.swift b/Tests/GRPCCoreTests/Call/Client/RetryDelaySequenceTests.swift index 71fa0a495..4811700df 100644 --- a/Tests/GRPCCoreTests/Call/Client/RetryDelaySequenceTests.swift +++ b/Tests/GRPCCoreTests/Call/Client/RetryDelaySequenceTests.swift @@ -17,6 +17,7 @@ import XCTest @testable import GRPCCore +@available(gRPCSwift 2.0, *) final class RetryDelaySequenceTests: XCTestCase { func testSequence() { let policy = RetryPolicy( diff --git a/Tests/GRPCCoreTests/Call/ConditionalInterceptorTests.swift b/Tests/GRPCCoreTests/Call/ConditionalInterceptorTests.swift index cd688f3c6..bbaa05d05 100644 --- a/Tests/GRPCCoreTests/Call/ConditionalInterceptorTests.swift +++ b/Tests/GRPCCoreTests/Call/ConditionalInterceptorTests.swift @@ -39,6 +39,7 @@ struct ConditionalInterceptorTests { ), ] as [(ConditionalInterceptor.Subject, [MethodDescriptor], [MethodDescriptor])] ) + @available(gRPCSwift 2.0, *) func appliesTo( target: ConditionalInterceptor.Subject, applicableMethods: [MethodDescriptor], @@ -54,6 +55,7 @@ struct ConditionalInterceptorTests { } } +@available(gRPCSwift 2.0, *) extension MethodDescriptor { fileprivate static let fooBar = Self(fullyQualifiedService: "pkg.foo", method: "bar") fileprivate static let fooBaz = Self(fullyQualifiedService: "pkg.foo", method: "baz") diff --git a/Tests/GRPCCoreTests/Call/Server/Internal/ServerCancellationManagerTests.swift b/Tests/GRPCCoreTests/Call/Server/Internal/ServerCancellationManagerTests.swift index 528ab88c3..87f8b200a 100644 --- a/Tests/GRPCCoreTests/Call/Server/Internal/ServerCancellationManagerTests.swift +++ b/Tests/GRPCCoreTests/Call/Server/Internal/ServerCancellationManagerTests.swift @@ -20,12 +20,14 @@ import Testing @Suite struct ServerCancellationManagerTests { @Test("Isn't cancelled after init") + @available(gRPCSwift 2.0, *) func isNotCancelled() { let manager = ServerCancellationManager() #expect(!manager.isRPCCancelled) } @Test("Is cancelled") + @available(gRPCSwift 2.0, *) func isCancelled() { let manager = ServerCancellationManager() manager.cancelRPC() @@ -33,6 +35,7 @@ struct ServerCancellationManagerTests { } @Test("Cancellation handler runs") + @available(gRPCSwift 2.0, *) func addCancellationHandler() async throws { let manager = ServerCancellationManager() let signal = AsyncStream.makeStream(of: Void.self) @@ -48,6 +51,7 @@ struct ServerCancellationManagerTests { } @Test("Cancellation handler runs immediately when already cancelled") + @available(gRPCSwift 2.0, *) func addCancellationHandlerAfterCancelled() async throws { let manager = ServerCancellationManager() let signal = AsyncStream.makeStream(of: Void.self) @@ -63,6 +67,7 @@ struct ServerCancellationManagerTests { } @Test("Remove cancellation handler") + @available(gRPCSwift 2.0, *) func removeCancellationHandler() async throws { let manager = ServerCancellationManager() @@ -76,6 +81,7 @@ struct ServerCancellationManagerTests { } @Test("Wait for cancellation") + @available(gRPCSwift 2.0, *) func waitForCancellation() async throws { let manager = ServerCancellationManager() try await withThrowingTaskGroup(of: Void.self) { group in diff --git a/Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTestSupport/ServerRPCExecutorTestHarness.swift b/Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTestSupport/ServerRPCExecutorTestHarness.swift index d7f976ba3..f0f156c2a 100644 --- a/Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTestSupport/ServerRPCExecutorTestHarness.swift +++ b/Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTestSupport/ServerRPCExecutorTestHarness.swift @@ -17,6 +17,7 @@ import XCTest @testable import GRPCCore +@available(gRPCSwift 2.0, *) struct ServerRPCExecutorTestHarness { struct ServerHandler: Sendable { let fn: @@ -148,6 +149,7 @@ struct ServerRPCExecutorTestHarness { } } +@available(gRPCSwift 2.0, *) extension ServerRPCExecutorTestHarness.ServerHandler where Input == Output { static var echo: Self { return Self { request, context in diff --git a/Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTests.swift b/Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTests.swift index 215584ebf..73f9ba82f 100644 --- a/Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTests.swift +++ b/Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTests.swift @@ -18,6 +18,7 @@ import XCTest @testable import GRPCCore +@available(gRPCSwift 2.0, *) final class ServerRPCExecutorTests: XCTestCase { func testEchoNoMessages() async throws { let harness = ServerRPCExecutorTestHarness() diff --git a/Tests/GRPCCoreTests/Call/Server/RPCRouterTests.swift b/Tests/GRPCCoreTests/Call/Server/RPCRouterTests.swift index 7ae55b2da..5ec97ddbf 100644 --- a/Tests/GRPCCoreTests/Call/Server/RPCRouterTests.swift +++ b/Tests/GRPCCoreTests/Call/Server/RPCRouterTests.swift @@ -17,6 +17,7 @@ import GRPCCore import XCTest +@available(gRPCSwift 2.0, *) final class RPCRouterTests: XCTestCase { func testEmptyRouter() async throws { var router = RPCRouter() @@ -64,6 +65,7 @@ final class RPCRouterTests: XCTestCase { } } +@available(gRPCSwift 2.0, *) struct NoServerTransport: ServerTransport { typealias Bytes = [UInt8] diff --git a/Tests/GRPCCoreTests/Call/Server/ServerContextTests.swift b/Tests/GRPCCoreTests/Call/Server/ServerContextTests.swift index c524519ff..f575d8f30 100644 --- a/Tests/GRPCCoreTests/Call/Server/ServerContextTests.swift +++ b/Tests/GRPCCoreTests/Call/Server/ServerContextTests.swift @@ -22,6 +22,7 @@ struct ServerContextTests { @Suite("CancellationHandle") struct CancellationHandle { @Test("Is cancelled") + @available(gRPCSwift 2.0, *) func isCancelled() async throws { await withServerContextRPCCancellationHandle { handle in #expect(!handle.isCancelled) @@ -31,6 +32,7 @@ struct ServerContextTests { } @Test("Wait for cancellation") + @available(gRPCSwift 2.0, *) func waitForCancellation() async throws { await withServerContextRPCCancellationHandle { handle in await withTaskGroup(of: Void.self) { group in @@ -44,6 +46,7 @@ struct ServerContextTests { } @Test("Binds task local") + @available(gRPCSwift 2.0, *) func bindsTaskLocal() async throws { await withServerContextRPCCancellationHandle { handle in let signal = AsyncStream.makeStream(of: Void.self) diff --git a/Tests/GRPCCoreTests/Call/Server/ServerRequestTests.swift b/Tests/GRPCCoreTests/Call/Server/ServerRequestTests.swift index c341bc992..c83aa3fc7 100644 --- a/Tests/GRPCCoreTests/Call/Server/ServerRequestTests.swift +++ b/Tests/GRPCCoreTests/Call/Server/ServerRequestTests.swift @@ -16,6 +16,7 @@ @_spi(Testing) import GRPCCore import XCTest +@available(gRPCSwift 2.0, *) final class ServerRequestTests: XCTestCase { func testSingleToStreamConversion() async throws { let single = ServerRequest(metadata: ["bar": "baz"], message: "foo") diff --git a/Tests/GRPCCoreTests/Call/Server/ServerResponseTests.swift b/Tests/GRPCCoreTests/Call/Server/ServerResponseTests.swift index 2152143c4..0267405c3 100644 --- a/Tests/GRPCCoreTests/Call/Server/ServerResponseTests.swift +++ b/Tests/GRPCCoreTests/Call/Server/ServerResponseTests.swift @@ -20,6 +20,7 @@ import Testing @Suite("ServerResponse") struct ServerResponseTests { @Test("ServerResponse(message:metadata:trailingMetadata:)") + @available(gRPCSwift 2.0, *) func responseInitSuccess() throws { let response = ServerResponse( message: "message", @@ -34,6 +35,7 @@ struct ServerResponseTests { } @Test("ServerResponse(of:error:)") + @available(gRPCSwift 2.0, *) func responseInitError() throws { let error = RPCError(code: .aborted, message: "Aborted") let response = ServerResponse(of: String.self, error: error) @@ -46,6 +48,7 @@ struct ServerResponseTests { } @Test("StreamingServerResponse(of:metadata:producer:)") + @available(gRPCSwift 2.0, *) func streamingResponseInitSuccess() async throws { let response = StreamingServerResponse( of: String.self, @@ -62,6 +65,7 @@ struct ServerResponseTests { } @Test("StreamingServerResponse(of:error:)") + @available(gRPCSwift 2.0, *) func streamingResponseInitError() async throws { let error = RPCError(code: .aborted, message: "Aborted") let response = StreamingServerResponse(of: String.self, error: error) @@ -74,6 +78,7 @@ struct ServerResponseTests { } @Test("StreamingServerResponse(single:) (accepted)") + @available(gRPCSwift 2.0, *) func singleToStreamConversionForSuccessfulResponse() async throws { let single = ServerResponse( message: "foo", @@ -100,6 +105,7 @@ struct ServerResponseTests { } @Test("StreamingServerResponse(single:) (rejected)") + @available(gRPCSwift 2.0, *) func singleToStreamConversionForFailedResponse() async throws { let error = RPCError(code: .aborted, message: "aborted") let single = ServerResponse(of: String.self, error: error) @@ -114,6 +120,7 @@ struct ServerResponseTests { } @Test("Mutate metadata on response", arguments: [true, false]) + @available(gRPCSwift 2.0, *) func mutateMetadataOnResponse(accepted: Bool) { var response: ServerResponse if accepted { @@ -127,6 +134,7 @@ struct ServerResponseTests { } @Test("Mutate metadata on streaming response", arguments: [true, false]) + @available(gRPCSwift 2.0, *) func mutateMetadataOnStreamingResponse(accepted: Bool) { var response: StreamingServerResponse if accepted { diff --git a/Tests/GRPCCoreTests/Coding/CodingTests.swift b/Tests/GRPCCoreTests/Coding/CodingTests.swift index dab5ecece..d50fd93f2 100644 --- a/Tests/GRPCCoreTests/Coding/CodingTests.swift +++ b/Tests/GRPCCoreTests/Coding/CodingTests.swift @@ -16,6 +16,7 @@ import GRPCCore import XCTest +@available(gRPCSwift 2.0, *) final class CodingTests: XCTestCase { func testJSONRoundtrip() throws { // This test just demonstrates that the API is suitable. diff --git a/Tests/GRPCCoreTests/Coding/CompressionAlgorithmTests.swift b/Tests/GRPCCoreTests/Coding/CompressionAlgorithmTests.swift index 351538816..69d2e2c3e 100644 --- a/Tests/GRPCCoreTests/Coding/CompressionAlgorithmTests.swift +++ b/Tests/GRPCCoreTests/Coding/CompressionAlgorithmTests.swift @@ -17,6 +17,7 @@ import GRPCCore import XCTest +@available(gRPCSwift 2.0, *) final class CompressionAlgorithmTests: XCTestCase { func testCompressionAlgorithmSetContains() { var algorithms = CompressionAlgorithmSet() diff --git a/Tests/GRPCCoreTests/Configuration/MethodConfigCodingTests.swift b/Tests/GRPCCoreTests/Configuration/MethodConfigCodingTests.swift index 634ef3399..9a3d1f6a7 100644 --- a/Tests/GRPCCoreTests/Configuration/MethodConfigCodingTests.swift +++ b/Tests/GRPCCoreTests/Configuration/MethodConfigCodingTests.swift @@ -43,6 +43,7 @@ struct MethodConfigCodingTests { (MethodConfig.Name(service: "", method: ""), #"{"method":"","service":""}"#), ] as [(MethodConfig.Name, String)] ) + @available(gRPCSwift 2.0, *) func methodConfigName(name: MethodConfig.Name, expected: String) throws { let json = try self.encodeToJSON(name) #expect(json == expected) @@ -56,6 +57,7 @@ struct MethodConfigCodingTests { (.milliseconds(100_123), #""100.123s""#), ] as [(Duration, String)] ) + @available(gRPCSwift 2.0, *) func protobufDuration(duration: Duration, expected: String) throws { let json = try self.encodeToJSON(GoogleProtobufDuration(duration: duration)) #expect(json == expected) @@ -83,12 +85,14 @@ struct MethodConfigCodingTests { (.unauthenticated, #""UNAUTHENTICATED""#), ] as [(Status.Code, String)] ) + @available(gRPCSwift 2.0, *) func rpcCode(code: Status.Code, expected: String) throws { let json = try self.encodeToJSON(GoogleRPCCode(code: code)) #expect(json == expected) } @Test("RetryPolicy") + @available(gRPCSwift 2.0, *) func retryPolicy() throws { let policy = RetryPolicy( maxAttempts: 3, @@ -105,6 +109,7 @@ struct MethodConfigCodingTests { } @Test("HedgingPolicy") + @available(gRPCSwift 2.0, *) func hedgingPolicy() throws { let policy = HedgingPolicy( maxAttempts: 3, @@ -174,6 +179,7 @@ struct MethodConfigCodingTests { ("method_config.name.empty", MethodConfig.Name(service: "", method: "")), ] as [(String, MethodConfig.Name)] ) + @available(gRPCSwift 2.0, *) func name(_ fileName: String, expected: MethodConfig.Name) throws { let decoded = try self.decodeFromFile(fileName, as: MethodConfig.Name.self) #expect(decoded == expected) @@ -190,6 +196,7 @@ struct MethodConfigCodingTests { ("100.123s", .milliseconds(100_123)), ] as [(String, Duration)] ) + @available(gRPCSwift 2.0, *) func googleProtobufDuration(duration: String, expectedDuration: Duration) throws { let json = "\"\(duration)\"" let decoded = try self.decodeFromJSONString(json, as: GoogleProtobufDuration.self) @@ -206,6 +213,7 @@ struct MethodConfigCodingTests { } @Test("Invalid GoogleProtobufDuration", arguments: ["1", "1ss", "1S", "1.0S"]) + @available(gRPCSwift 2.0, *) func googleProtobufDuration(invalidDuration: String) throws { let json = "\"\(invalidDuration)\"" #expect { @@ -217,6 +225,7 @@ struct MethodConfigCodingTests { } @Test("GoogleRPCCode from case name", arguments: zip(Self.codeNames, Status.Code.all)) + @available(gRPCSwift 2.0, *) func rpcCode(name: String, expected: Status.Code) throws { let json = "\"\(name)\"" let decoded = try self.decodeFromJSONString(json, as: GoogleRPCCode.self) @@ -224,6 +233,7 @@ struct MethodConfigCodingTests { } @Test("GoogleRPCCode from rawValue", arguments: zip(0 ... 16, Status.Code.all)) + @available(gRPCSwift 2.0, *) func rpcCode(rawValue: Int, expected: Status.Code) throws { let json = "\(rawValue)" let decoded = try self.decodeFromJSONString(json, as: GoogleRPCCode.self) @@ -231,6 +241,7 @@ struct MethodConfigCodingTests { } @Test("RetryPolicy") + @available(gRPCSwift 2.0, *) func retryPolicy() throws { let decoded = try self.decodeFromFile("method_config.retry_policy", as: RetryPolicy.self) let expected = RetryPolicy( @@ -253,6 +264,7 @@ struct MethodConfigCodingTests { "method_config.retry_policy.invalid.retryable_status_codes", ] ) + @available(gRPCSwift 2.0, *) func invalidRetryPolicy(fileName: String) throws { #expect(throws: RuntimeError.self) { try self.decodeFromFile(fileName, as: RetryPolicy.self) @@ -260,6 +272,7 @@ struct MethodConfigCodingTests { } @Test("HedgingPolicy") + @available(gRPCSwift 2.0, *) func hedgingPolicy() throws { let decoded = try self.decodeFromFile("method_config.hedging_policy", as: HedgingPolicy.self) let expected = HedgingPolicy( @@ -276,6 +289,7 @@ struct MethodConfigCodingTests { "method_config.hedging_policy.invalid.max_attempts" ] ) + @available(gRPCSwift 2.0, *) func invalidHedgingPolicy(fileName: String) throws { #expect(throws: RuntimeError.self) { try self.decodeFromFile(fileName, as: HedgingPolicy.self) @@ -283,6 +297,7 @@ struct MethodConfigCodingTests { } @Test("MethodConfig") + @available(gRPCSwift 2.0, *) func methodConfig() throws { let expected = MethodConfig( names: [ @@ -302,6 +317,7 @@ struct MethodConfigCodingTests { } @Test("MethodConfig with hedging") + @available(gRPCSwift 2.0, *) func methodConfigWithHedging() throws { let expected = MethodConfig( names: [ @@ -328,6 +344,7 @@ struct MethodConfigCodingTests { } @Test("MethodConfig with retries") + @available(gRPCSwift 2.0, *) func methodConfigWithRetries() throws { let expected = MethodConfig( names: [ @@ -406,6 +423,7 @@ struct MethodConfigCodingTests { "method_config.with_hedging", ] ) + @available(gRPCSwift 2.0, *) func roundTripCodingAndDecoding(fileName: String) throws { try self.roundTrip(type: MethodConfig.self, fileName: fileName) } diff --git a/Tests/GRPCCoreTests/Configuration/MethodConfigTests.swift b/Tests/GRPCCoreTests/Configuration/MethodConfigTests.swift index 8d01bcfd6..f549de2cb 100644 --- a/Tests/GRPCCoreTests/Configuration/MethodConfigTests.swift +++ b/Tests/GRPCCoreTests/Configuration/MethodConfigTests.swift @@ -19,6 +19,7 @@ import Testing struct MethodConfigTests { @Test("RetryPolicy clamps max attempts") + @available(gRPCSwift 2.0, *) func retryPolicyClampsMaxAttempts() { var policy = RetryPolicy( maxAttempts: 10, @@ -36,6 +37,7 @@ struct MethodConfigTests { } @Test("HedgingPolicy clamps max attempts") + @available(gRPCSwift 2.0, *) func hedgingPolicyClampsMaxAttempts() { var policy = HedgingPolicy( maxAttempts: 10, diff --git a/Tests/GRPCCoreTests/Configuration/ServiceConfigCodingTests.swift b/Tests/GRPCCoreTests/Configuration/ServiceConfigCodingTests.swift index 787d87e0f..bdf5671c0 100644 --- a/Tests/GRPCCoreTests/Configuration/ServiceConfigCodingTests.swift +++ b/Tests/GRPCCoreTests/Configuration/ServiceConfigCodingTests.swift @@ -19,6 +19,7 @@ import GRPCCore import SwiftProtobuf import XCTest +@available(gRPCSwift 2.0, *) final class ServiceConfigCodingTests: XCTestCase { private let encoder = JSONEncoder() private let decoder = JSONDecoder() diff --git a/Tests/GRPCCoreTests/GRPCClientTests.swift b/Tests/GRPCCoreTests/GRPCClientTests.swift index f038760d8..9e6db0cdb 100644 --- a/Tests/GRPCCoreTests/GRPCClientTests.swift +++ b/Tests/GRPCCoreTests/GRPCClientTests.swift @@ -19,6 +19,7 @@ import GRPCInProcessTransport import Testing import XCTest +@available(gRPCSwift 2.0, *) final class GRPCClientTests: XCTestCase { func withInProcessConnectedClient( services: [any RegistrableRPCService], @@ -398,6 +399,7 @@ final class GRPCClientTests: XCTestCase { @Suite("GRPC Client Tests") struct ClientTests { @Test("Interceptors are applied only to specified services") + @available(gRPCSwift 2.0, *) func testInterceptorsAreAppliedToSpecifiedServices() async throws { let onlyBinaryEchoCounter = AtomicCounter() let allServicesCounter = AtomicCounter() @@ -461,6 +463,7 @@ struct ClientTests { } @Test("Interceptors are applied only to specified methods") + @available(gRPCSwift 2.0, *) func testInterceptorsAreAppliedToSpecifiedMethods() async throws { let onlyBinaryEchoGetCounter = AtomicCounter() let onlyBinaryEchoCollectCounter = AtomicCounter() @@ -523,6 +526,7 @@ struct ClientTests { } } + @available(gRPCSwift 2.0, *) func withInProcessConnectedClient( services: [any RegistrableRPCService], interceptorPipeline: [ConditionalInterceptor] = [], diff --git a/Tests/GRPCCoreTests/GRPCServerTests.swift b/Tests/GRPCCoreTests/GRPCServerTests.swift index acf29b8e5..9e35bded6 100644 --- a/Tests/GRPCCoreTests/GRPCServerTests.swift +++ b/Tests/GRPCCoreTests/GRPCServerTests.swift @@ -19,6 +19,7 @@ import GRPCInProcessTransport import Testing import XCTest +@available(gRPCSwift 2.0, *) final class GRPCServerTests: XCTestCase { func withInProcessClientConnectedToServer( services: [any RegistrableRPCService], @@ -378,6 +379,7 @@ final class GRPCServerTests: XCTestCase { @Suite("GRPC Server Tests") struct ServerTests { @Test("Interceptors are applied only to specified services") + @available(gRPCSwift 2.0, *) func testInterceptorsAreAppliedToSpecifiedServices() async throws { let onlyBinaryEchoCounter = AtomicCounter() let allServicesCounter = AtomicCounter() @@ -465,6 +467,7 @@ struct ServerTests { } @Test("Interceptors are applied only to specified methods") + @available(gRPCSwift 2.0, *) func testInterceptorsAreAppliedToSpecifiedMethods() async throws { let onlyBinaryEchoGetCounter = AtomicCounter() let onlyBinaryEchoCollectCounter = AtomicCounter() @@ -551,6 +554,7 @@ struct ServerTests { } } + @available(gRPCSwift 2.0, *) func withInProcessClientConnectedToServer( services: [any RegistrableRPCService], interceptorPipeline: [ConditionalInterceptor] = [], @@ -578,6 +582,7 @@ struct ServerTests { } } + @available(gRPCSwift 2.0, *) func assertMetadata( _ part: RPCResponsePart?, metadataHandler: (Metadata) -> Void = { _ in } @@ -590,6 +595,7 @@ struct ServerTests { } } + @available(gRPCSwift 2.0, *) func assertMessage( _ part: RPCResponsePart?, messageHandler: (Bytes) -> Void = { _ in } @@ -602,6 +608,7 @@ struct ServerTests { } } + @available(gRPCSwift 2.0, *) func assertStatus( _ part: RPCResponsePart?, statusHandler: (Status, Metadata) -> Void = { _, _ in } diff --git a/Tests/GRPCCoreTests/Internal/Metadata+GRPCTests.swift b/Tests/GRPCCoreTests/Internal/Metadata+GRPCTests.swift index a6bb11a84..b4b59bcef 100644 --- a/Tests/GRPCCoreTests/Internal/Metadata+GRPCTests.swift +++ b/Tests/GRPCCoreTests/Internal/Metadata+GRPCTests.swift @@ -18,6 +18,7 @@ import XCTest @testable import GRPCCore +@available(gRPCSwift 2.0, *) final class MetadataGRPCTests: XCTestCase { func testPreviousRPCAttemptsValidValues() { let testData = [("0", 0), ("1", 1), ("-1", -1)] diff --git a/Tests/GRPCCoreTests/Internal/MethodConfigsTests.swift b/Tests/GRPCCoreTests/Internal/MethodConfigsTests.swift index bac916763..1f9cf7bdf 100644 --- a/Tests/GRPCCoreTests/Internal/MethodConfigsTests.swift +++ b/Tests/GRPCCoreTests/Internal/MethodConfigsTests.swift @@ -16,6 +16,7 @@ import GRPCCore import XCTest +@available(gRPCSwift 2.0, *) final class MethodConfigsTests: XCTestCase { func testGetConfigurationForKnownMethod() async throws { let policy = HedgingPolicy( diff --git a/Tests/GRPCCoreTests/Internal/Result+CatchingTests.swift b/Tests/GRPCCoreTests/Internal/Result+CatchingTests.swift index d5bc65cd1..644bc72dd 100644 --- a/Tests/GRPCCoreTests/Internal/Result+CatchingTests.swift +++ b/Tests/GRPCCoreTests/Internal/Result+CatchingTests.swift @@ -18,6 +18,7 @@ import XCTest @testable import GRPCCore +@available(gRPCSwift 2.0, *) final class ResultCatchingTests: XCTestCase { func testResultCatching() async { let result = await Result { diff --git a/Tests/GRPCCoreTests/MetadataTests.swift b/Tests/GRPCCoreTests/MetadataTests.swift index 617d2263d..715869fdb 100644 --- a/Tests/GRPCCoreTests/MetadataTests.swift +++ b/Tests/GRPCCoreTests/MetadataTests.swift @@ -20,6 +20,7 @@ import Testing @Suite("Metadata") struct MetadataTests { @Test("Initialize from Sequence") + @available(gRPCSwift 2.0, *) func initFromSequence() { let elements: [Metadata.Element] = [ (key: "key1", value: "value1"), @@ -33,6 +34,7 @@ struct MetadataTests { } @Test("Add string Value") + @available(gRPCSwift 2.0, *) func addStringValue() { var metadata = Metadata() #expect(metadata.isEmpty) @@ -47,6 +49,7 @@ struct MetadataTests { } @Test("Add binary value") + @available(gRPCSwift 2.0, *) func addBinaryValue() { var metadata = Metadata() #expect(metadata.isEmpty) @@ -61,6 +64,7 @@ struct MetadataTests { } @Test("Initialize from dictionary literal") + @available(gRPCSwift 2.0, *) func initFromDictionaryLiteral() { let metadata: Metadata = [ "testKey": "stringValue", @@ -83,52 +87,52 @@ struct MetadataTests { struct ReplaceOrAdd { @Suite("String") struct StringValues { - var metadata: Metadata = [ - "key1": "value1", - "key1": "value2", - ] - @Test("Add different key") + @available(gRPCSwift 2.0, *) mutating func addNewKey() async throws { - self.metadata.replaceOrAddString("value3", forKey: "key2") - #expect(Array(self.metadata[stringValues: "key1"]) == ["value1", "value2"]) - #expect(Array(self.metadata[stringValues: "key2"]) == ["value3"]) - #expect(self.metadata.count == 3) + var metadata: Metadata = ["key1": "value1", "key1": "value2"] + metadata.replaceOrAddString("value3", forKey: "key2") + #expect(Array(metadata[stringValues: "key1"]) == ["value1", "value2"]) + #expect(Array(metadata[stringValues: "key2"]) == ["value3"]) + #expect(metadata.count == 3) } @Test("Replace values for existing key") + @available(gRPCSwift 2.0, *) mutating func replaceValues() async throws { - self.metadata.replaceOrAddString("value3", forKey: "key1") - #expect(Array(self.metadata[stringValues: "key1"]) == ["value3"]) - #expect(self.metadata.count == 1) + var metadata: Metadata = ["key1": "value1", "key1": "value2"] + metadata.replaceOrAddString("value3", forKey: "key1") + #expect(Array(metadata[stringValues: "key1"]) == ["value3"]) + #expect(metadata.count == 1) } } @Suite("Binary") struct BinaryValues { - var metadata: Metadata = [ - "key1-bin": [0], - "key1-bin": [1], - ] @Test("Add different key") + @available(gRPCSwift 2.0, *) mutating func addNewKey() async throws { - self.metadata.replaceOrAddBinary([2], forKey: "key2-bin") - #expect(Array(self.metadata[binaryValues: "key1-bin"]) == [[0], [1]]) - #expect(Array(self.metadata[binaryValues: "key2-bin"]) == [[2]]) - #expect(self.metadata.count == 3) + var metadata: Metadata = ["key1-bin": [0], "key1-bin": [1]] + metadata.replaceOrAddBinary([2], forKey: "key2-bin") + #expect(Array(metadata[binaryValues: "key1-bin"]) == [[0], [1]]) + #expect(Array(metadata[binaryValues: "key2-bin"]) == [[2]]) + #expect(metadata.count == 3) } @Test("Replace values for existing key") + @available(gRPCSwift 2.0, *) mutating func replaceValues() async throws { - self.metadata.replaceOrAddBinary([2], forKey: "key1-bin") - #expect(Array(self.metadata[binaryValues: "key1-bin"]) == [[2]]) - #expect(self.metadata.count == 1) + var metadata: Metadata = ["key1-bin": [0], "key1-bin": [1]] + metadata.replaceOrAddBinary([2], forKey: "key1-bin") + #expect(Array(metadata[binaryValues: "key1-bin"]) == [[2]]) + #expect(metadata.count == 1) } } } @Test("Reserve more capacity increases capacity") + @available(gRPCSwift 2.0, *) func reserveMoreCapacity() { var metadata = Metadata() #expect(metadata.capacity == 0) @@ -138,6 +142,7 @@ struct MetadataTests { } @Test("Reserve less capacity doesn't reduce capacity") + @available(gRPCSwift 2.0, *) func reserveCapacity() { var metadata = Metadata() #expect(metadata.capacity == 0) @@ -148,6 +153,7 @@ struct MetadataTests { } @Test("Iterate over all values for a key") + @available(gRPCSwift 2.0, *) func iterateOverValuesForKey() { let metadata: Metadata = [ "key-bin": "1", @@ -162,6 +168,7 @@ struct MetadataTests { } @Test("Iterate over string values for a key") + @available(gRPCSwift 2.0, *) func iterateOverStringsForKey() { let metadata: Metadata = [ "key-bin": "1", @@ -176,6 +183,7 @@ struct MetadataTests { } @Test("Iterate over binary values for a key") + @available(gRPCSwift 2.0, *) func iterateOverBinaryForKey() { let metadata: Metadata = [ "key-bin": "1", @@ -190,6 +198,7 @@ struct MetadataTests { } @Test("Iterate over base64 encoded binary values for a key") + @available(gRPCSwift 2.0, *) func iterateOverBase64BinaryEncodedValuesForKey() { let metadata: Metadata = [ "key-bin": "c3RyaW5nMQ==", @@ -213,6 +222,7 @@ struct MetadataTests { } @Test("Subscripts are case-insensitive") + @available(gRPCSwift 2.0, *) func subscriptIsCaseInsensitive() { let metadata: Metadata = [ "key1": "value1", @@ -228,50 +238,57 @@ struct MetadataTests { @Suite("Remove all") struct RemoveAll { - var metadata: Metadata = [ - "key1": "value1", - "key2": "value2", - "key3": "value1", - ] - @Test("Where value matches") + @available(gRPCSwift 2.0, *) mutating func removeAllWhereValueMatches() async throws { - self.metadata.removeAll { _, value in + var metadata: Metadata = ["key1": "value1", "key2": "value2", "key3": "value1"] + metadata.removeAll { _, value in value == "value1" } - #expect(self.metadata == ["key2": "value2"]) + #expect(metadata == ["key2": "value2"]) } @Test("Where key matches") + @available(gRPCSwift 2.0, *) mutating func removeAllWhereKeyMatches() async throws { - self.metadata.removeAll { key, _ in + var metadata: Metadata = ["key1": "value1", "key2": "value2", "key3": "value1"] + metadata.removeAll { key, _ in key == "key2" } - #expect(self.metadata == ["key1": "value1", "key3": "value1"]) + #expect(metadata == ["key1": "value1", "key3": "value1"]) } } @Suite("Merge") struct Merge { - var metadata: Metadata = [ - "key1": "value1-1", - "key2": "value2", - "key3": "value3", - ] - var otherMetadata: Metadata = [ - "key4": "value4", - "key5": "value5", - ] + @available(gRPCSwift 2.0, *) + var metadata: Metadata { + [ + "key1": "value1-1", + "key2": "value2", + "key3": "value3", + ] + } + @available(gRPCSwift 2.0, *) + var otherMetadata: Metadata { + [ + "key4": "value4", + "key5": "value5", + ] + } @Test("Where key is already present with a different value") + @available(gRPCSwift 2.0, *) mutating func mergeWhereKeyIsAlreadyPresentWithDifferentValue() async throws { - self.otherMetadata.addString("value1-2", forKey: "key1") - self.metadata.add(contentsOf: self.otherMetadata) + var otherMetadata = self.otherMetadata + otherMetadata.addString("value1-2", forKey: "key1") + var metadata = metadata + metadata.add(contentsOf: otherMetadata) #expect( - self.metadata == [ + metadata == [ "key1": "value1-1", "key2": "value2", "key3": "value3", @@ -283,12 +300,15 @@ struct MetadataTests { } @Test("Where key is already present with same value") + @available(gRPCSwift 2.0, *) mutating func mergeWhereKeyIsAlreadyPresentWithSameValue() async throws { - self.otherMetadata.addString("value1-1", forKey: "key1") - self.metadata.add(contentsOf: self.otherMetadata) + var otherMetadata = otherMetadata + otherMetadata.addString("value1-1", forKey: "key1") + var metadata = metadata + metadata.add(contentsOf: otherMetadata) #expect( - self.metadata == [ + metadata == [ "key1": "value1-1", "key2": "value2", "key3": "value3", @@ -300,11 +320,13 @@ struct MetadataTests { } @Test("Where key is not already present") + @available(gRPCSwift 2.0, *) mutating func mergeWhereKeyIsNotAlreadyPresent() async throws { - self.metadata.add(contentsOf: self.otherMetadata) + var metadata = self.metadata + metadata.add(contentsOf: self.otherMetadata) #expect( - self.metadata == [ + metadata == [ "key1": "value1-1", "key2": "value2", "key3": "value3", @@ -317,18 +339,23 @@ struct MetadataTests { @Suite("Description") struct Description { - let metadata: Metadata = [ - "key1": "value1", - "key2": "value2", - "key-bin": .binary([1, 2, 3]), - ] + @available(gRPCSwift 2.0, *) + var metadata: Metadata { + [ + "key1": "value1", + "key2": "value2", + "key-bin": .binary([1, 2, 3]), + ] + } @Test("Metadata") + @available(gRPCSwift 2.0, *) func describeMetadata() async throws { #expect("\(self.metadata)" == #"["key1": "value1", "key2": "value2", "key-bin": [1, 2, 3]]"#) } @Test("Metadata.Value") + @available(gRPCSwift 2.0, *) func describeMetadataValue() async throws { for (key, value) in self.metadata { switch key { diff --git a/Tests/GRPCCoreTests/MethodDescriptorTests.swift b/Tests/GRPCCoreTests/MethodDescriptorTests.swift index 889a0c878..12329ffc0 100644 --- a/Tests/GRPCCoreTests/MethodDescriptorTests.swift +++ b/Tests/GRPCCoreTests/MethodDescriptorTests.swift @@ -19,6 +19,7 @@ import Testing @Suite struct MethodDescriptorTests { @Test("Fully qualified name") + @available(gRPCSwift 2.0, *) func testFullyQualifiedName() { let descriptor = MethodDescriptor(fullyQualifiedService: "foo.bar", method: "Baz") #expect(descriptor.service == ServiceDescriptor(fullyQualifiedService: "foo.bar")) @@ -27,6 +28,7 @@ struct MethodDescriptorTests { } @Test("CustomStringConvertible") + @available(gRPCSwift 2.0, *) func description() { let descriptor = MethodDescriptor( service: ServiceDescriptor(fullyQualifiedService: "foo.Foo"), diff --git a/Tests/GRPCCoreTests/RPCErrorTests.swift b/Tests/GRPCCoreTests/RPCErrorTests.swift index b4eba43d0..7c9968423 100644 --- a/Tests/GRPCCoreTests/RPCErrorTests.swift +++ b/Tests/GRPCCoreTests/RPCErrorTests.swift @@ -19,6 +19,7 @@ import Testing @Suite("RPCError Tests") struct RPCErrorTests { @Test("Custom String Convertible") + @available(gRPCSwift 2.0, *) func testCustomStringConvertible() { #expect(String(describing: RPCError(code: .dataLoss, message: "")) == #"dataLoss: """#) #expect( @@ -36,6 +37,7 @@ struct RPCErrorTests { } @Test("Error from Status") + @available(gRPCSwift 2.0, *) func testErrorFromStatus() throws { var status = Status(code: .ok, message: "") // ok isn't an error @@ -77,11 +79,13 @@ struct RPCErrorTests { (Status.Code.unauthenticated, RPCError.Code.unauthenticated), ] ) + @available(gRPCSwift 2.0, *) func testErrorCodeFromStatusCode(statusCode: Status.Code, rpcErrorCode: RPCError.Code?) throws { #expect(RPCError.Code(statusCode) == rpcErrorCode) } @Test("Equatable Conformance") + @available(gRPCSwift 2.0, *) func testEquatableConformance() { #expect( RPCError(code: .cancelled, message: "") @@ -135,11 +139,13 @@ struct RPCErrorTests { (.unauthenticated, 16), ] ) + @available(gRPCSwift 2.0, *) func testStatusCodeRawValues(statusCode: RPCError.Code, rawValue: Int) { #expect(statusCode.rawValue == rawValue, "\(statusCode) had unexpected raw value") } @Test("Flatten causes with same status code") + @available(gRPCSwift 2.0, *) func testFlattenCausesWithSameStatusCode() { let error1 = RPCError(code: .unknown, message: "Error 1.") let error2 = RPCError(code: .unknown, message: "Error 2.", cause: error1) @@ -162,6 +168,7 @@ struct RPCErrorTests { } @Test("Causes of errors with different status codes aren't flattened") + @available(gRPCSwift 2.0, *) func testDifferentStatusCodeAreNotFlattened() throws { let error1 = RPCError(code: .unknown, message: "Error 1.") let error2 = RPCError(code: .dataLoss, message: "Error 2.", cause: error1) @@ -191,6 +198,7 @@ struct RPCErrorTests { } @Test("Convert type to RPCError") + @available(gRPCSwift 2.0, *) func convertTypeUsingRPCErrorConvertible() { struct Cause: Error {} struct ConvertibleError: RPCErrorConvertible { @@ -208,6 +216,7 @@ struct RPCErrorTests { } @Test("Convert type to RPCError with defaults") + @available(gRPCSwift 2.0, *) func convertTypeUsingRPCErrorConvertibleDefaults() { struct ConvertibleType: RPCErrorConvertible { var rpcErrorCode: RPCError.Code { .unknown } @@ -222,6 +231,7 @@ struct RPCErrorTests { } @Test("Convert error to RPCError with defaults") + @available(gRPCSwift 2.0, *) func convertErrorUsingRPCErrorConvertibleDefaults() { struct ConvertibleType: RPCErrorConvertible, Error { var rpcErrorCode: RPCError.Code { .unknown } diff --git a/Tests/GRPCCoreTests/RPCPartsTests.swift b/Tests/GRPCCoreTests/RPCPartsTests.swift index 3bf72e85e..605821fb0 100644 --- a/Tests/GRPCCoreTests/RPCPartsTests.swift +++ b/Tests/GRPCCoreTests/RPCPartsTests.swift @@ -16,6 +16,7 @@ import GRPCCore import XCTest +@available(gRPCSwift 2.0, *) final class RPCPartsTests: XCTestCase { func testPartsFitInExistentialContainer() { XCTAssertLessThanOrEqual(MemoryLayout>.size, 24) diff --git a/Tests/GRPCCoreTests/RuntimeErrorTests.swift b/Tests/GRPCCoreTests/RuntimeErrorTests.swift index fb8411687..9881a60e5 100644 --- a/Tests/GRPCCoreTests/RuntimeErrorTests.swift +++ b/Tests/GRPCCoreTests/RuntimeErrorTests.swift @@ -16,6 +16,7 @@ import GRPCCore import XCTest +@available(gRPCSwift 2.0, *) final class RuntimeErrorTests: XCTestCase { func testCopyOnWrite() { // RuntimeError has a heap based storage, so check CoW semantics are correctly implemented. diff --git a/Tests/GRPCCoreTests/ServiceDescriptorTests.swift b/Tests/GRPCCoreTests/ServiceDescriptorTests.swift index ef4ec8988..20c5897cd 100644 --- a/Tests/GRPCCoreTests/ServiceDescriptorTests.swift +++ b/Tests/GRPCCoreTests/ServiceDescriptorTests.swift @@ -29,6 +29,7 @@ struct ServiceDescriptorTests { ("", "", ""), ] ) + @available(gRPCSwift 2.0, *) func packageAndService(fullyQualified: String, package: String, service: String) { let descriptor = ServiceDescriptor(fullyQualifiedService: fullyQualified) #expect(descriptor.fullyQualifiedService == fullyQualified) @@ -37,6 +38,7 @@ struct ServiceDescriptorTests { } @Test("CustomStringConvertible") + @available(gRPCSwift 2.0, *) func description() { let descriptor = ServiceDescriptor(fullyQualifiedService: "foo.Foo") #expect(String(describing: descriptor) == "foo.Foo") diff --git a/Tests/GRPCCoreTests/StatusTests.swift b/Tests/GRPCCoreTests/StatusTests.swift index fd442586a..345ba664f 100644 --- a/Tests/GRPCCoreTests/StatusTests.swift +++ b/Tests/GRPCCoreTests/StatusTests.swift @@ -22,6 +22,7 @@ struct StatusTests { @Suite("Code") struct Code { @Test("rawValue", arguments: zip(Status.Code.all, 0 ... 16)) + @available(gRPCSwift 2.0, *) func rawValueOfStatusCodes(code: Status.Code, expected: Int) { #expect(code.rawValue == expected) } @@ -33,28 +34,33 @@ struct StatusTests { Status.Code.all.dropFirst() // Drop '.ok', there is no '.ok' error code. ) ) + @available(gRPCSwift 2.0, *) func initFromRPCErrorCode(errorCode: RPCError.Code, expected: Status.Code) { #expect(Status.Code(errorCode) == expected) } @Test("Initialize from rawValue", arguments: zip(0 ... 16, Status.Code.all)) + @available(gRPCSwift 2.0, *) func initFromRawValue(rawValue: Int, expected: Status.Code) { #expect(Status.Code(rawValue: rawValue) == expected) } @Test("Initialize from invalid rawValue", arguments: [-1, 17, 100, .max]) + @available(gRPCSwift 2.0, *) func initFromInvalidRawValue(rawValue: Int) { #expect(Status.Code(rawValue: rawValue) == nil) } } @Test("CustomStringConvertible conformance") + @available(gRPCSwift 2.0, *) func customStringConvertible() { #expect("\(Status(code: .ok, message: ""))" == #"ok: """#) #expect("\(Status(code: .dataLoss, message: "oh no"))" == #"dataLoss: "oh no""#) } @Test("Equatable conformance") + @available(gRPCSwift 2.0, *) func equatable() { let ok = Status(code: .ok, message: "") let okWithMessage = Status(code: .ok, message: "message") @@ -66,6 +72,7 @@ struct StatusTests { } @Test("Fits in existential container") + @available(gRPCSwift 2.0, *) func fitsInExistentialContainer() { #expect(MemoryLayout.size <= 24) } @@ -84,6 +91,7 @@ struct StatusTests { (418, Status(code: .unknown, message: "HTTP 418")), ] ) + @available(gRPCSwift 2.0, *) func convertFromHTTPStatusCode(code: Int, expected: Status) { let status = Status(httpStatusCode: code) #expect(status == expected) diff --git a/Tests/GRPCCoreTests/Streaming/Internal/AsyncSequenceOfOne.swift b/Tests/GRPCCoreTests/Streaming/Internal/AsyncSequenceOfOne.swift index 79cfef19d..a612649cf 100644 --- a/Tests/GRPCCoreTests/Streaming/Internal/AsyncSequenceOfOne.swift +++ b/Tests/GRPCCoreTests/Streaming/Internal/AsyncSequenceOfOne.swift @@ -18,6 +18,7 @@ import XCTest @testable import GRPCCore +@available(gRPCSwift 2.0, *) internal final class AsyncSequenceOfOneTests: XCTestCase { func testSuccessPath() async throws { let sequence = RPCAsyncSequence.one("foo") diff --git a/Tests/GRPCCoreTests/Streaming/Internal/BroadcastAsyncSequenceTests.swift b/Tests/GRPCCoreTests/Streaming/Internal/BroadcastAsyncSequenceTests.swift index 55479d38c..969025063 100644 --- a/Tests/GRPCCoreTests/Streaming/Internal/BroadcastAsyncSequenceTests.swift +++ b/Tests/GRPCCoreTests/Streaming/Internal/BroadcastAsyncSequenceTests.swift @@ -18,6 +18,7 @@ import XCTest @testable import GRPCCore +@available(gRPCSwift 2.0, *) final class BroadcastAsyncSequenceTests: XCTestCase { func testSingleSubscriberToEmptyStream() async throws { let (stream, source) = BroadcastAsyncSequence.makeStream(of: Int.self, bufferSize: 16) diff --git a/Tests/GRPCCoreTests/Test Utilities/AtomicCounter.swift b/Tests/GRPCCoreTests/Test Utilities/AtomicCounter.swift index cf9c4f679..dc38b25d9 100644 --- a/Tests/GRPCCoreTests/Test Utilities/AtomicCounter.swift +++ b/Tests/GRPCCoreTests/Test Utilities/AtomicCounter.swift @@ -16,6 +16,7 @@ import Synchronization +@available(gRPCSwift 2.0, *) final class AtomicCounter: Sendable { private let counter: Atomic diff --git a/Tests/GRPCCoreTests/Test Utilities/Call/Client/ClientInterceptors.swift b/Tests/GRPCCoreTests/Test Utilities/Call/Client/ClientInterceptors.swift index ba6c1abf1..3c46a35d5 100644 --- a/Tests/GRPCCoreTests/Test Utilities/Call/Client/ClientInterceptors.swift +++ b/Tests/GRPCCoreTests/Test Utilities/Call/Client/ClientInterceptors.swift @@ -16,6 +16,7 @@ import GRPCCore +@available(gRPCSwift 2.0, *) extension ClientInterceptor where Self == RejectAllClientInterceptor { static func rejectAll(with error: RPCError) -> Self { return RejectAllClientInterceptor(reject: error) @@ -27,6 +28,7 @@ extension ClientInterceptor where Self == RejectAllClientInterceptor { } +@available(gRPCSwift 2.0, *) extension ClientInterceptor where Self == RequestCountingClientInterceptor { static func requestCounter(_ counter: AtomicCounter) -> Self { return RequestCountingClientInterceptor(counter: counter) @@ -34,6 +36,7 @@ extension ClientInterceptor where Self == RequestCountingClientInterceptor { } /// Rejects all RPCs with the provided error. +@available(gRPCSwift 2.0, *) struct RejectAllClientInterceptor: ClientInterceptor { enum Mode: Sendable { /// Throw the error rather. @@ -69,6 +72,7 @@ struct RejectAllClientInterceptor: ClientInterceptor { } } +@available(gRPCSwift 2.0, *) struct RequestCountingClientInterceptor: ClientInterceptor { /// The number of requests made. let counter: AtomicCounter diff --git a/Tests/GRPCCoreTests/Test Utilities/Call/Server/ServerInterceptors.swift b/Tests/GRPCCoreTests/Test Utilities/Call/Server/ServerInterceptors.swift index 8340aa130..5918102db 100644 --- a/Tests/GRPCCoreTests/Test Utilities/Call/Server/ServerInterceptors.swift +++ b/Tests/GRPCCoreTests/Test Utilities/Call/Server/ServerInterceptors.swift @@ -16,6 +16,7 @@ import GRPCCore +@available(gRPCSwift 2.0, *) extension ServerInterceptor where Self == RejectAllServerInterceptor { static func rejectAll(with error: RPCError) -> Self { return RejectAllServerInterceptor(reject: error) @@ -26,6 +27,7 @@ extension ServerInterceptor where Self == RejectAllServerInterceptor { } } +@available(gRPCSwift 2.0, *) extension ServerInterceptor where Self == RequestCountingServerInterceptor { static func requestCounter(_ counter: AtomicCounter) -> Self { RequestCountingServerInterceptor(counter: counter) @@ -33,6 +35,7 @@ extension ServerInterceptor where Self == RequestCountingServerInterceptor { } /// Rejects all RPCs with the provided error. +@available(gRPCSwift 2.0, *) struct RejectAllServerInterceptor: ServerInterceptor { enum Mode: Sendable { /// Throw the error rather. @@ -68,6 +71,7 @@ struct RejectAllServerInterceptor: ServerInterceptor { } } +@available(gRPCSwift 2.0, *) struct RequestCountingServerInterceptor: ServerInterceptor { /// The number of requests made. let counter: AtomicCounter diff --git a/Tests/GRPCCoreTests/Test Utilities/Coding+Identity.swift b/Tests/GRPCCoreTests/Test Utilities/Coding+Identity.swift index 35eca49c8..cc27182b5 100644 --- a/Tests/GRPCCoreTests/Test Utilities/Coding+Identity.swift +++ b/Tests/GRPCCoreTests/Test Utilities/Coding+Identity.swift @@ -15,12 +15,14 @@ */ import GRPCCore +@available(gRPCSwift 2.0, *) struct IdentitySerializer: MessageSerializer { func serialize(_ message: [UInt8]) throws -> Bytes { return Bytes(message) } } +@available(gRPCSwift 2.0, *) struct IdentityDeserializer: MessageDeserializer { func deserialize(_ serializedMessageBytes: Bytes) throws -> [UInt8] { return serializedMessageBytes.withUnsafeBytes { diff --git a/Tests/GRPCCoreTests/Test Utilities/Coding+JSON.swift b/Tests/GRPCCoreTests/Test Utilities/Coding+JSON.swift index d2c6ef452..bb734479f 100644 --- a/Tests/GRPCCoreTests/Test Utilities/Coding+JSON.swift +++ b/Tests/GRPCCoreTests/Test Utilities/Coding+JSON.swift @@ -20,6 +20,7 @@ import struct Foundation.Data import class Foundation.JSONDecoder import class Foundation.JSONEncoder +@available(gRPCSwift 2.0, *) struct JSONSerializer: MessageSerializer { func serialize(_ message: Message) throws -> Bytes { do { @@ -32,6 +33,7 @@ struct JSONSerializer: MessageSerializer { } } +@available(gRPCSwift 2.0, *) struct JSONDeserializer: MessageDeserializer { func deserialize(_ serializedMessageBytes: Bytes) throws -> Message { do { diff --git a/Tests/GRPCCoreTests/Test Utilities/RPCAsyncSequence+Utilities.swift b/Tests/GRPCCoreTests/Test Utilities/RPCAsyncSequence+Utilities.swift index 950e2c61a..64c7c85dd 100644 --- a/Tests/GRPCCoreTests/Test Utilities/RPCAsyncSequence+Utilities.swift +++ b/Tests/GRPCCoreTests/Test Utilities/RPCAsyncSequence+Utilities.swift @@ -15,6 +15,7 @@ */ import GRPCCore +@available(gRPCSwift 2.0, *) extension RPCAsyncSequence where Failure == any Error { static func elements(_ elements: Element...) -> Self { return .elements(elements) diff --git a/Tests/GRPCCoreTests/Test Utilities/RPCWriter+Utilities.swift b/Tests/GRPCCoreTests/Test Utilities/RPCWriter+Utilities.swift index eafd569ab..d4426c4e9 100644 --- a/Tests/GRPCCoreTests/Test Utilities/RPCWriter+Utilities.swift +++ b/Tests/GRPCCoreTests/Test Utilities/RPCWriter+Utilities.swift @@ -16,6 +16,7 @@ import GRPCCore import XCTest +@available(gRPCSwift 2.0, *) extension RPCWriter { /// Returns a writer which calls `XCTFail(_:)` on every write. static func failTestOnWrite(elementType: Element.Type = Element.self) -> Self { diff --git a/Tests/GRPCCoreTests/Test Utilities/Services/BinaryEcho.swift b/Tests/GRPCCoreTests/Test Utilities/Services/BinaryEcho.swift index 4783d03e2..1bd5bbbc4 100644 --- a/Tests/GRPCCoreTests/Test Utilities/Services/BinaryEcho.swift +++ b/Tests/GRPCCoreTests/Test Utilities/Services/BinaryEcho.swift @@ -15,6 +15,7 @@ */ import GRPCCore +@available(gRPCSwift 2.0, *) struct BinaryEcho: RegistrableRPCService { static let serviceDescriptor = ServiceDescriptor(package: "echo", service: "Echo") diff --git a/Tests/GRPCCoreTests/Test Utilities/Services/HelloWorld.swift b/Tests/GRPCCoreTests/Test Utilities/Services/HelloWorld.swift index a543defc8..12777517f 100644 --- a/Tests/GRPCCoreTests/Test Utilities/Services/HelloWorld.swift +++ b/Tests/GRPCCoreTests/Test Utilities/Services/HelloWorld.swift @@ -16,6 +16,7 @@ import Foundation import GRPCCore +@available(gRPCSwift 2.0, *) struct HelloWorld: RegistrableRPCService { static let serviceDescriptor = ServiceDescriptor(package: "helloworld", service: "HelloWorld") diff --git a/Tests/GRPCCoreTests/Test Utilities/Transport/AnyTransport.swift b/Tests/GRPCCoreTests/Test Utilities/Transport/AnyTransport.swift index d8f4fb053..2e97f8f0b 100644 --- a/Tests/GRPCCoreTests/Test Utilities/Transport/AnyTransport.swift +++ b/Tests/GRPCCoreTests/Test Utilities/Transport/AnyTransport.swift @@ -15,6 +15,7 @@ */ @testable import GRPCCore +@available(gRPCSwift 2.0, *) struct AnyClientTransport: ClientTransport, Sendable { typealias Bytes = [UInt8] @@ -78,6 +79,7 @@ struct AnyClientTransport: ClientTransport, Sendable { } } +@available(gRPCSwift 2.0, *) struct AnyServerTransport: ServerTransport, Sendable { typealias Bytes = [UInt8] diff --git a/Tests/GRPCCoreTests/Test Utilities/Transport/StreamCountingTransport.swift b/Tests/GRPCCoreTests/Test Utilities/Transport/StreamCountingTransport.swift index 50fe696e3..5b1ef428f 100644 --- a/Tests/GRPCCoreTests/Test Utilities/Transport/StreamCountingTransport.swift +++ b/Tests/GRPCCoreTests/Test Utilities/Transport/StreamCountingTransport.swift @@ -16,6 +16,7 @@ @testable import GRPCCore +@available(gRPCSwift 2.0, *) struct StreamCountingClientTransport: ClientTransport, Sendable { typealias Bytes = [UInt8] @@ -75,6 +76,7 @@ struct StreamCountingClientTransport: ClientTransport, Sendable { } } +@available(gRPCSwift 2.0, *) struct StreamCountingServerTransport: ServerTransport, Sendable { typealias Bytes = [UInt8] diff --git a/Tests/GRPCCoreTests/Test Utilities/Transport/ThrowingTransport.swift b/Tests/GRPCCoreTests/Test Utilities/Transport/ThrowingTransport.swift index e8ee489f7..c635dc249 100644 --- a/Tests/GRPCCoreTests/Test Utilities/Transport/ThrowingTransport.swift +++ b/Tests/GRPCCoreTests/Test Utilities/Transport/ThrowingTransport.swift @@ -15,6 +15,7 @@ */ @testable import GRPCCore +@available(gRPCSwift 2.0, *) struct ThrowOnStreamCreationTransport: ClientTransport { typealias Bytes = [UInt8] @@ -49,6 +50,7 @@ struct ThrowOnStreamCreationTransport: ClientTransport { } } +@available(gRPCSwift 2.0, *) struct ThrowOnRunServerTransport: ServerTransport { typealias Bytes = [UInt8] @@ -69,6 +71,7 @@ struct ThrowOnRunServerTransport: ServerTransport { } } +@available(gRPCSwift 2.0, *) struct ThrowOnSignalServerTransport: ServerTransport { typealias Bytes = [UInt8] diff --git a/Tests/GRPCCoreTests/Test Utilities/XCTest+Utilities.swift b/Tests/GRPCCoreTests/Test Utilities/XCTest+Utilities.swift index 07acf664e..0e4b5e960 100644 --- a/Tests/GRPCCoreTests/Test Utilities/XCTest+Utilities.swift +++ b/Tests/GRPCCoreTests/Test Utilities/XCTest+Utilities.swift @@ -65,6 +65,7 @@ func XCTAssertThrowsErrorAsync( } } +@available(gRPCSwift 2.0, *) func XCTAssertThrowsRPCError( _ expression: @autoclosure () throws -> T, _ errorHandler: (RPCError) -> Void @@ -78,6 +79,7 @@ func XCTAssertThrowsRPCError( } } +@available(gRPCSwift 2.0, *) func XCTAssertThrowsRPCErrorAsync( _ expression: () async throws -> T, errorHandler: (RPCError) -> Void @@ -92,6 +94,7 @@ func XCTAssertThrowsRPCErrorAsync( } } +@available(gRPCSwift 2.0, *) func XCTAssertRejected( _ response: StreamingClientResponse, errorHandler: (RPCError) -> Void @@ -104,6 +107,7 @@ func XCTAssertRejected( } } +@available(gRPCSwift 2.0, *) func XCTAssertRejected( _ response: ClientResponse, errorHandler: (RPCError) -> Void @@ -116,6 +120,7 @@ func XCTAssertRejected( } } +@available(gRPCSwift 2.0, *) func XCTAssertMetadata( _ part: RPCResponsePart?, metadataHandler: (Metadata) -> Void = { _ in } @@ -128,6 +133,7 @@ func XCTAssertMetadata( } } +@available(gRPCSwift 2.0, *) func XCTAssertMetadata( _ part: RPCRequestPart?, metadataHandler: (Metadata) async throws -> Void = { _ in } @@ -140,6 +146,7 @@ func XCTAssertMetadata( } } +@available(gRPCSwift 2.0, *) func XCTAssertMessage( _ part: RPCResponsePart?, messageHandler: (Bytes) -> Void = { _ in } @@ -152,6 +159,7 @@ func XCTAssertMessage( } } +@available(gRPCSwift 2.0, *) func XCTAssertMessage( _ part: RPCRequestPart?, messageHandler: (Bytes) async throws -> Void = { _ in } @@ -164,6 +172,7 @@ func XCTAssertMessage( } } +@available(gRPCSwift 2.0, *) func XCTAssertStatus( _ part: RPCResponsePart?, statusHandler: (Status, Metadata) -> Void = { _, _ in } diff --git a/Tests/GRPCCoreTests/TimeoutTests.swift b/Tests/GRPCCoreTests/TimeoutTests.swift index a22bb32be..de0caaef5 100644 --- a/Tests/GRPCCoreTests/TimeoutTests.swift +++ b/Tests/GRPCCoreTests/TimeoutTests.swift @@ -20,6 +20,7 @@ import Testing struct TimeoutTests { @Test("Initialize from invalid String value", arguments: ["", "H", "123", "100000000S", "123j"]) + @available(gRPCSwift 2.0, *) func initFromStringWithInvalidValue(_ value: String) throws { #expect(Timeout(decoding: value) == nil) } @@ -35,6 +36,7 @@ struct TimeoutTests { ("123n", .nanoseconds(123)), ] as [(String, Duration)] ) + @available(gRPCSwift 2.0, *) func initFromString(_ value: String, expected: Duration) throws { let timeout = try #require(Timeout(decoding: value)) #expect(timeout.duration == expected) @@ -51,6 +53,7 @@ struct TimeoutTests { .nanoseconds(100), ] as [Duration] ) + @available(gRPCSwift 2.0, *) func initFromDuration(_ value: Duration) { let timeout = Timeout(duration: value) #expect(timeout.duration == value) @@ -77,6 +80,7 @@ struct TimeoutTests { (Duration(secondsComponent: 1, attosecondsComponent: Int64(1e11)), .seconds(1)), ] as [(Duration, Duration)] ) + @available(gRPCSwift 2.0, *) func initFromDurationWithLossOfPrecision(original: Duration, rounded: Duration) { let timeout = Timeout(duration: original) #expect(timeout.duration == rounded) diff --git a/Tests/GRPCCoreTests/Transport/RetryThrottleTests.swift b/Tests/GRPCCoreTests/Transport/RetryThrottleTests.swift index 9e89e032d..123ca966e 100644 --- a/Tests/GRPCCoreTests/Transport/RetryThrottleTests.swift +++ b/Tests/GRPCCoreTests/Transport/RetryThrottleTests.swift @@ -18,6 +18,7 @@ import XCTest @testable import GRPCCore +@available(gRPCSwift 2.0, *) final class RetryThrottleTests: XCTestCase { func testThrottleOnInit() { let throttle = RetryThrottle(maxTokens: 10, tokenRatio: 0.1) diff --git a/Tests/GRPCInProcessTransportTests/ClientServerWithMethods.swift b/Tests/GRPCInProcessTransportTests/ClientServerWithMethods.swift index 930b18183..16391c1d9 100644 --- a/Tests/GRPCInProcessTransportTests/ClientServerWithMethods.swift +++ b/Tests/GRPCInProcessTransportTests/ClientServerWithMethods.swift @@ -21,6 +21,7 @@ import Testing @Suite("withGRPCServer / withGRPCClient") struct WithMethods { @Test("Actor isolation") + @available(gRPCSwift 2.0, *) func actorIsolation() async throws { let testActor = TestActor() #expect(await !testActor.hasRun) @@ -29,6 +30,7 @@ struct WithMethods { } } +@available(gRPCSwift 2.0, *) fileprivate actor TestActor { private(set) var hasRun = false diff --git a/Tests/GRPCInProcessTransportTests/InProcessClientTransportTests.swift b/Tests/GRPCInProcessTransportTests/InProcessClientTransportTests.swift index c64f97646..9dd66feb9 100644 --- a/Tests/GRPCInProcessTransportTests/InProcessClientTransportTests.swift +++ b/Tests/GRPCInProcessTransportTests/InProcessClientTransportTests.swift @@ -18,6 +18,7 @@ import GRPCCore import GRPCInProcessTransport import XCTest +@available(gRPCSwift 2.0, *) final class InProcessClientTransportTests: XCTestCase { struct FailTest: Error {} @@ -271,6 +272,7 @@ final class InProcessClientTransportTests: XCTestCase { } } + @available(gRPCSwift 2.0, *) func makeClient( server: InProcessTransport.Server = InProcessTransport.Server(peer: "in-process:1234") ) -> InProcessTransport.Client { @@ -299,6 +301,7 @@ final class InProcessClientTransportTests: XCTestCase { } } +@available(gRPCSwift 2.0, *) extension MethodDescriptor { static let testTest = Self(fullyQualifiedService: "test", method: "test") } diff --git a/Tests/GRPCInProcessTransportTests/InProcessServerTransportTests.swift b/Tests/GRPCInProcessTransportTests/InProcessServerTransportTests.swift index 92c3c5c8e..7d9a70093 100644 --- a/Tests/GRPCInProcessTransportTests/InProcessServerTransportTests.swift +++ b/Tests/GRPCInProcessTransportTests/InProcessServerTransportTests.swift @@ -19,6 +19,7 @@ import XCTest @testable import GRPCCore @testable import GRPCInProcessTransport +@available(gRPCSwift 2.0, *) final class InProcessServerTransportTests: XCTestCase { func testStartListening() async throws { let transport = InProcessTransport.Server(peer: "in-process:1234") diff --git a/Tests/GRPCInProcessTransportTests/InProcessTransportTests.swift b/Tests/GRPCInProcessTransportTests/InProcessTransportTests.swift index 5751d74a1..40a2e0b46 100644 --- a/Tests/GRPCInProcessTransportTests/InProcessTransportTests.swift +++ b/Tests/GRPCInProcessTransportTests/InProcessTransportTests.swift @@ -22,6 +22,7 @@ import Testing struct InProcessTransportTests { private static let cancellationModes = ["await-cancelled", "with-cancellation-handler"] + @available(gRPCSwift 2.0, *) private func withTestServerAndClient( execute: ( GRPCServer, @@ -46,6 +47,7 @@ struct InProcessTransportTests { } @Test("RPC cancelled by graceful shutdown", arguments: Self.cancellationModes) + @available(gRPCSwift 2.0, *) func cancelledByGracefulShutdown(mode: String) async throws { try await self.withTestServerAndClient { server, client in try await client.serverStreaming( @@ -69,6 +71,7 @@ struct InProcessTransportTests { } @Test("Peer info") + @available(gRPCSwift 2.0, *) func peerInfo() async throws { try await self.withTestServerAndClient { server, client in defer { @@ -91,6 +94,7 @@ struct InProcessTransportTests { } } +@available(gRPCSwift 2.0, *) private struct TestService: RegistrableRPCService { func cancellation( request: ServerRequest, @@ -154,6 +158,7 @@ private struct TestService: RegistrableRPCService { } } +@available(gRPCSwift 2.0, *) extension MethodDescriptor { fileprivate static let testCancellation = Self( fullyQualifiedService: "test", @@ -171,12 +176,14 @@ private struct PeerInfo: Codable { var remote: String } +@available(gRPCSwift 2.0, *) private struct UTF8Serializer: MessageSerializer { func serialize(_ message: String) throws -> Bytes { Bytes(message.utf8) } } +@available(gRPCSwift 2.0, *) private struct UTF8Deserializer: MessageDeserializer { func deserialize(_ serializedMessageBytes: Bytes) throws -> String { serializedMessageBytes.withUnsafeBytes { @@ -185,12 +192,14 @@ private struct UTF8Deserializer: MessageDeserializer { } } +@available(gRPCSwift 2.0, *) private struct VoidSerializer: MessageSerializer { func serialize(_ message: Void) throws -> Bytes { Bytes(repeating: 0, count: 0) } } +@available(gRPCSwift 2.0, *) private struct VoidDeserializer: MessageDeserializer { func deserialize(_ serializedMessageBytes: Bytes) throws { } diff --git a/Tests/GRPCInProcessTransportTests/Test Utilities/JSONSerializing.swift b/Tests/GRPCInProcessTransportTests/Test Utilities/JSONSerializing.swift index 905e90525..ed44053c9 100644 --- a/Tests/GRPCInProcessTransportTests/Test Utilities/JSONSerializing.swift +++ b/Tests/GRPCInProcessTransportTests/Test Utilities/JSONSerializing.swift @@ -20,6 +20,7 @@ import struct Foundation.Data import class Foundation.JSONDecoder import class Foundation.JSONEncoder +@available(gRPCSwift 2.0, *) struct JSONSerializer: MessageSerializer { func serialize(_ message: Message) throws -> Bytes { do { @@ -32,6 +33,7 @@ struct JSONSerializer: MessageSerializer { } } +@available(gRPCSwift 2.0, *) struct JSONDeserializer: MessageDeserializer { func deserialize(_ serializedMessageBytes: Bytes) throws -> Message { do {