Skip to content

Commit 2d53488

Browse files
authored
[swift6][client] make api calls concurrent (#22790)
* [swift6][client] make api calls concurrent * [swift6][client] improve swift 6 thread safety * [swift6][client] improve swift 6 thread safety
1 parent 5926c31 commit 2d53488

108 files changed

Lines changed: 320 additions & 250 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

modules/openapi-generator/src/main/resources/swift6/APIHelper.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import Foundation{{#useVapor}}
88
import Vapor{{/useVapor}}
99

10-
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} struct APIHelper {
10+
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} struct APIHelper: Sendable {
1111
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} static func rejectNil(_ source: [String: (any Sendable)?]) -> [String: any Sendable]? {
1212
let destination = source.reduce(into: [String: any Sendable]()) { result, item in
1313
if let value = item.value {

modules/openapi-generator/src/main/resources/swift6/APIs.mustache

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ import Alamofire{{/useAlamofire}}
8282
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} static let shared = {{projectName}}APIConfiguration()
8383
}{{^useVapor}}
8484

85-
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class RequestBuilder<T>: @unchecked Sendable, Identifiable {
85+
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class RequestBuilder<T: Sendable>: @unchecked Sendable, Identifiable {
8686
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var credential: URLCredential?
8787
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var headers: [String: String]
8888
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} let parameters: [String: any Sendable]?
@@ -119,9 +119,24 @@ import Alamofire{{/useAlamofire}}
119119
}
120120

121121
{{#useAsyncAwait}}
122+
#if compiler(>=6.2)
123+
@concurrent
122124
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
123125
@discardableResult
124126
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} func execute() async throws(ErrorResponse) -> Response<T> {
127+
try await _execute()
128+
}
129+
#else
130+
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
131+
@discardableResult
132+
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} func execute() async throws(ErrorResponse) -> Response<T> {
133+
try await _execute()
134+
}
135+
#endif
136+
137+
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
138+
@discardableResult
139+
private func _execute() async throws(ErrorResponse) -> Response<T> {
125140
do {
126141
let requestTask = self.requestTask
127142
return try await withTaskCancellationHandler {
@@ -135,7 +150,6 @@ import Alamofire{{/useAlamofire}}
135150
self.execute { result in
136151
switch result {
137152
case let .success(response):
138-
nonisolated(unsafe) let response = response
139153
continuation.resume(returning: response)
140154
case let .failure(error):
141155
continuation.resume(throwing: error)
@@ -153,7 +167,7 @@ import Alamofire{{/useAlamofire}}
153167
}
154168
}
155169
}
156-
170+
157171
{{/useAsyncAwait}}
158172
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} func addHeader(name: String, value: String) -> Self {
159173
if !value.isEmpty {
@@ -167,7 +181,7 @@ import Alamofire{{/useAlamofire}}
167181
}
168182
}
169183

170-
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} protocol RequestBuilderFactory {
184+
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} protocol RequestBuilderFactory: Sendable {
171185
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type
172186
func getBuilder<T: Decodable>() -> RequestBuilder<T>.Type
173187
}{{/useVapor}}

modules/openapi-generator/src/main/resources/swift6/Models.mustache

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,19 +70,19 @@ extension NullEncodable: Codable where Wrapped: Codable {
7070
}
7171
}
7272

73-
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum ErrorResponse: Error {
73+
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum ErrorResponse: Error, @unchecked Sendable {
7474
case error(Int, Data?, URLResponse?, Error)
7575
}
7676

77-
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum DownloadException: Error {
77+
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum DownloadException: Error, Sendable {
7878
case responseDataMissing
7979
case responseFailed
8080
case requestMissing
8181
case requestMissingPath
8282
case requestMissingURL
8383
}
8484

85-
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum DecodableRequestBuilderError: Error {
85+
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum DecodableRequestBuilderError: Error, @unchecked Sendable {
8686
case emptyDataResponse
8787
case nilHTTPResponse
8888
case unsuccessfulHTTPStatusCode

modules/openapi-generator/src/main/resources/swift6/Validation.mustache

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,23 @@ extension NumericRule: Sendable where T: Sendable {}
2727
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var uniqueItems: Bool
2828
}
2929

30-
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum StringValidationErrorKind: Error {
30+
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum StringValidationErrorKind: Error, Sendable {
3131
case minLength, maxLength, pattern
3232
}
3333

34-
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum NumericValidationErrorKind: Error {
34+
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum NumericValidationErrorKind: Error, Sendable {
3535
case minimum, maximum, multipleOf
3636
}
3737

38-
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum ArrayValidationErrorKind: Error {
38+
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum ArrayValidationErrorKind: Error, Sendable {
3939
case minItems, maxItems, uniqueItems
4040
}
4141

42-
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} struct ValidationError<T: Error & Hashable>: Error {
42+
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} struct ValidationError<T: Error & Hashable & Sendable>: Error, Sendable {
4343
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} fileprivate(set) var kinds: Set<T>
4444
}
4545

46-
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} struct Validator {
46+
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} struct Validator: Sendable {
4747
/// Validate a string against a rule.
4848
/// - Parameter string: The String you wish to validate.
4949
/// - Parameter rule: The StringRule you wish to use for validation.

modules/openapi-generator/src/main/resources/swift6/libraries/alamofire/AlamofireImplementations.mustache

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import Foundation
88
import Alamofire
99

10-
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} class AlamofireRequestBuilderFactory: RequestBuilderFactory {
10+
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} final class AlamofireRequestBuilderFactory: RequestBuilderFactory, Sendable {
1111
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init() {}
1212

1313
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
@@ -27,7 +27,7 @@ fileprivate class AlamofireRequestBuilderConfiguration: @unchecked Sendable {
2727
var managerStore = SynchronizedDictionary<String, Alamofire.Session>()
2828
}
2929

30-
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class AlamofireRequestBuilder<T>: RequestBuilder<T>, @unchecked Sendable {
30+
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class AlamofireRequestBuilder<T: Sendable>: RequestBuilder<T>, @unchecked Sendable {
3131
required {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init(method: String, URLString: String, parameters: [String: any Sendable]?, headers: [String: String] = [:], requiresAuthentication: Bool, apiConfiguration: {{projectName}}APIConfiguration = {{projectName}}APIConfiguration.shared) {
3232
super.init(method: method, URLString: URLString, parameters: parameters, headers: headers, requiresAuthentication: requiresAuthentication, apiConfiguration: apiConfiguration)
3333
}
@@ -255,7 +255,7 @@ fileprivate class AlamofireRequestBuilderConfiguration: @unchecked Sendable {
255255

256256
}
257257

258-
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class AlamofireDecodableRequestBuilder<T: Decodable>: AlamofireRequestBuilder<T>, @unchecked Sendable {
258+
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class AlamofireDecodableRequestBuilder<T: Decodable & Sendable>: AlamofireRequestBuilder<T>, @unchecked Sendable {
259259
260260
override fileprivate func processRequest(request: DataRequest, managerId: String, completion: @Sendable @escaping (_ result: Swift.Result<Response<T>, ErrorResponse>) -> Void) {
261261
if let credential = self.credential {

modules/openapi-generator/src/main/resources/swift6/libraries/urlsession/URLSessionImplementations.mustache

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ extension URLSession: URLSessionProtocol {
4040

4141
extension URLSessionDataTask: URLSessionDataTaskProtocol {}
4242

43-
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} class URLSessionRequestBuilderFactory: RequestBuilderFactory {
43+
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} final class URLSessionRequestBuilderFactory: RequestBuilderFactory, Sendable {
4444
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init() {}
4545

4646
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
@@ -69,7 +69,7 @@ fileprivate class URLSessionRequestBuilderConfiguration: @unchecked Sendable {
6969
var credentialStore = SynchronizedDictionary<Int, URLCredential>()
7070
}
7171

72-
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class URLSessionRequestBuilder<T>: RequestBuilder<T>, @unchecked Sendable {
72+
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class URLSessionRequestBuilder<T: Sendable>: RequestBuilder<T>, @unchecked Sendable {
7373
7474
required {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init(method: String, URLString: String, parameters: [String: any Sendable]?, headers: [String: String] = [:], requiresAuthentication: Bool, apiConfiguration: {{projectName}}APIConfiguration = {{projectName}}APIConfiguration.shared) {
7575
super.init(method: method, URLString: URLString, parameters: parameters, headers: headers, requiresAuthentication: requiresAuthentication, apiConfiguration: apiConfiguration)
@@ -319,7 +319,7 @@ fileprivate class URLSessionRequestBuilderConfiguration: @unchecked Sendable {
319319

320320
}
321321

322-
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class URLSessionDecodableRequestBuilder<T: Decodable>: URLSessionRequestBuilder<T>, @unchecked Sendable {
322+
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class URLSessionDecodableRequestBuilder<T: Decodable & Sendable>: URLSessionRequestBuilder<T>, @unchecked Sendable {
323323
override fileprivate func processRequestResponse(urlRequest: URLRequest, data: Data?, httpResponse: HTTPURLResponse, error: Error?, completion: @Sendable @escaping (_ result: Swift.Result<Response<T>, ErrorResponse>) -> Void) {
324324
325325
switch T.self {

modules/openapi-generator/src/main/resources/swift6/modelObject.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{{^objcCompatible}}{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} {{#useClasses}}final class{{/useClasses}}{{^useClasses}}struct{{/useClasses}} {{{classname}}}: {{^useClasses}}Sendable, {{/useClasses}}{{#useClasses}}{{#readonlyProperties}}@unchecked Sendable, {{/readonlyProperties}}{{/useClasses}}{{#useVapor}}Content{{/useVapor}}{{^useVapor}}Codable{{/useVapor}}{{#vendorExtensions.x-swift-hashable}}, Hashable{{/vendorExtensions.x-swift-hashable}} {
2-
{{/objcCompatible}}{{#objcCompatible}}@objcMembers {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} class {{classname}}: NSObject, Codable {
2+
{{/objcCompatible}}{{#objcCompatible}}@objcMembers {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} final class {{classname}}: NSObject, Codable, @unchecked Sendable {
33
{{/objcCompatible}}
44

55
{{#allVars}}

samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/APIHelper.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import Foundation
88

9-
public struct APIHelper {
9+
public struct APIHelper: Sendable {
1010
public static func rejectNil(_ source: [String: (any Sendable)?]) -> [String: any Sendable]? {
1111
let destination = source.reduce(into: [String: any Sendable]()) { result, item in
1212
if let value = item.value {

samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/APIs.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ open class PetstoreClientAPIConfiguration: @unchecked Sendable {
6161
public static let shared = PetstoreClientAPIConfiguration()
6262
}
6363

64-
open class RequestBuilder<T>: @unchecked Sendable, Identifiable {
64+
open class RequestBuilder<T: Sendable>: @unchecked Sendable, Identifiable {
6565
public var credential: URLCredential?
6666
public var headers: [String: String]
6767
public let parameters: [String: any Sendable]?
@@ -109,7 +109,7 @@ open class RequestBuilder<T>: @unchecked Sendable, Identifiable {
109109
}
110110
}
111111

112-
public protocol RequestBuilderFactory {
112+
public protocol RequestBuilderFactory: Sendable {
113113
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type
114114
func getBuilder<T: Decodable>() -> RequestBuilder<T>.Type
115115
}

samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import Foundation
88
import Alamofire
99

10-
public class AlamofireRequestBuilderFactory: RequestBuilderFactory {
10+
public final class AlamofireRequestBuilderFactory: RequestBuilderFactory, Sendable {
1111
public init() {}
1212

1313
public func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
@@ -27,7 +27,7 @@ fileprivate class AlamofireRequestBuilderConfiguration: @unchecked Sendable {
2727
var managerStore = SynchronizedDictionary<String, Alamofire.Session>()
2828
}
2929

30-
open class AlamofireRequestBuilder<T>: RequestBuilder<T>, @unchecked Sendable {
30+
open class AlamofireRequestBuilder<T: Sendable>: RequestBuilder<T>, @unchecked Sendable {
3131
required public init(method: String, URLString: String, parameters: [String: any Sendable]?, headers: [String: String] = [:], requiresAuthentication: Bool, apiConfiguration: PetstoreClientAPIConfiguration = PetstoreClientAPIConfiguration.shared) {
3232
super.init(method: method, URLString: URLString, parameters: parameters, headers: headers, requiresAuthentication: requiresAuthentication, apiConfiguration: apiConfiguration)
3333
}
@@ -255,7 +255,7 @@ open class AlamofireRequestBuilder<T>: RequestBuilder<T>, @unchecked Sendable {
255255

256256
}
257257

258-
open class AlamofireDecodableRequestBuilder<T: Decodable>: AlamofireRequestBuilder<T>, @unchecked Sendable {
258+
open class AlamofireDecodableRequestBuilder<T: Decodable & Sendable>: AlamofireRequestBuilder<T>, @unchecked Sendable {
259259

260260
override fileprivate func processRequest(request: DataRequest, managerId: String, completion: @Sendable @escaping (_ result: Swift.Result<Response<T>, ErrorResponse>) -> Void) {
261261
if let credential = self.credential {

0 commit comments

Comments
 (0)