Sources/SPTDataLoaderSwift/Request+Concurrency.swift (91 lines of code) (raw):

// Copyright 2015-2023 Spotify AB // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #if compiler(>=5.5.2) && canImport(_Concurrency) import Foundation @available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) public extension Request { func task() -> ResponseTask<Void> { return ResponseTask(request: self) } func dataTask() -> ResponseTask<Data> { return ResponseTask(request: self) } func decodableTask<Value: Decodable>( type: Value.Type = Value.self, decoder: ResponseDecoder = JSONDecoder() ) -> ResponseTask<Value> { return ResponseTask(request: self, decodableType: type, decoder: decoder) } func jsonTask(options: JSONSerialization.ReadingOptions = []) -> ResponseTask<Any> { return ResponseTask(request: self, options: options) } func serializableTask<Serializer: ResponseSerializer>(serializer: Serializer) -> ResponseTask<Serializer.Output> { return ResponseTask(request: self, serializer: serializer) } } // MARK: - @available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) public struct ResponseTask<Value> { private let task: Task<Response<Value, Error>, Never> fileprivate init( request: Request, continuation: @escaping (CheckedContinuation<Response<Value, Error>, Never>) -> Void ) { self.task = Task { await withTaskCancellationHandler( operation: { await withCheckedContinuation(continuation) }, onCancel: { request.cancel() } ) } } public func cancel() { task.cancel() } public var response: Response<Value, Error> { get async { await task.value } } public var result: Result<Value, Error> { get async { await response.result } } public var value: Value { get async throws { try await result.get() } } } @available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) private extension ResponseTask { init(request: Request) where Value == Void { self.init(request: request) { continuation in request.response { response in continuation.resume(returning: response) } } } init(request: Request) where Value == Data { self.init(request: request) { continuation in request.responseData { response in continuation.resume(returning: response) } } } init(request: Request, decodableType: Value.Type, decoder: ResponseDecoder) where Value: Decodable { self.init(request: request) { continuation in request.responseDecodable(type: decodableType, decoder: decoder) { response in continuation.resume(returning: response) } } } init(request: Request, options: JSONSerialization.ReadingOptions) where Value == Any { self.init(request: request) { continuation in request.responseJSON(options: options) { response in continuation.resume(returning: response) } } } init<Serializer: ResponseSerializer>(request: Request, serializer: Serializer) where Value == Serializer.Output { self.init(request: request) { continuation in request.responseSerializable(serializer: serializer) { response in continuation.resume(returning: response) } } } } #endif