I am trying to bridge both the continuation methods provided for Error
type and Never
type with a rethrow protocol:
@rethrows
public protocol Continuable {
associatedtype Success
associatedtype Failure: Error
func resume(returning value: Success)
func resume(throwing error: Failure)
func resume(with result: Result<Success, Failure>)
static func with(_ body: (Self) -> Void) async throws -> Success
}
public extension Continuable {
// provide default implementation to handle
// for failure type different than never and error
static func with(_ body: (Self) -> Void) async throws -> Success {
throw CancellationError()
}
}
Then I am providing custom implementation with CheckedContinuation
based on error type is Error
or Never
:
extension CheckedContinuation: Continuable {
public static func with(_ body: (Self) -> Void) async throws -> T where E == Error {
return try await withCheckedThrowingContinuation(body)
}
public static func with(_ body: (Self) -> Void) async -> T where E == Never {
return await withCheckedContinuation(body)
}
}
Here, I am getting a warning:
Static method 'with' nearly matches defaulted requirement 'with' of protocol 'Continuable'
and it seems that conditional implementation on generic types might not work when default implementation is provided in protocol extension.
Then I am creating a wrapper around continuation like this:
@rethrows
protocol ContinuationWrapper: Continuable {
associatedtype Continuation: Continuable
where Continuation.Success == Success, Continuation.Failure == Failure
init(with value: Continuation)
}
extension ContinuationWrapper {
public static func with(function: String, _ body: (Self) -> Void) async rethrows -> Success {
return try await Continuation.with { continuation in
body(Self(with: continuation))
}
}
}
struct WrappedContinuation<C: Continuable>: ContinuationWrapper {
let value: C
init(with value: C) {
self.value = value
}
func resume(returning value: C.Success) {
self.value.resume(returning: value)
}
func resume(throwing error: C.Failure) {
self.value.resume(throwing: error)
}
func resume(with result: Result<C.Success, C.Failure>) {
self.value.resume(with: result)
}
}
After all these changes whenever I am using continuation with CheckedContinuation.with
method I am getting proper rethrow behavior in the sanse that I don't have to use try
when error type is Never
. But when I am using WrappedContinuation.with
I always have to prefix the call with try
:
func continuationTest() async throws {
await CheckedContinuation<Void, Never>.with { continuation in
continuation.resume()
}
try await CheckedContinuation<Void, Error>.with { continuation in
continuation.resume()
}
// always requires try
try await WrappedContinuation<CheckedContinuation<Void, Never>>.with { continuation in
continuation.resume(returning: ())
}
}
Am I doing something wrong here? Is there any changes I can do to achieve what I want?