You can use a class to box the returned value. Something like this works (with all the safety caveats mentioned):
fileprivate class Box<ResultType> {
var result: Result<ResultType, Error>? = nil
}
/// Unsafely awaits an async function from a synchronous context.
@available(*, deprecated, message: "Migrate to structured concurrency")
func _unsafeWait<ResultType>(_ f: @escaping () async throws -> ResultType) throws -> ResultType {
let box = Box<ResultType>()
let sema = DispatchSemaphore(value: 0)
Task {
do {
let val = try await f()
box.result = .success(val)
} catch {
box.result = .failure(error)
}
sema.signal()
}
sema.wait()
return try box.result!.get()
}
(You can also make a non-throwing version if needed. I don't think there's a way to make rethrows
work in this way).
Then can call:
// in a sync context
let data = try _unsafeWait {
let (data, _) = try await URLSession.shared.data(from: url)
return data
}