Async Affordances Wish List

Hi,

to help with async programming tasks, I could see the following affordances on async/await to be helpful:

1. Make existing Continuation Passing Style (CPS) APIs available via async/await.

2. Await with timeouts.

3. Possibility to cancel awaits.

To be more specific:

Ad 1.

I think it could be helpful if an API like:

`func foo(_ arg: Arg, completion: (val: Val) -> Void)`

could be invoked like this:

`let val: Val = await foo(arg)`

(i.e, having a mapped signature like: `func foo(_ arg: Arg) async -> Val`)

Often, the completion takes an error argument:

`func bar(_ arg: Arg, completion: (val: Val?, err: Error?) -> Void)`

Calling it via async/await might look like this:

do {
  let val: Val = try await bar(arg)
} catch {
  // handle error
}

I could imagine that new type attributes are needed to make this happen:

@continuation: the closure which continues the async control flow

`func bar(_ arg: Arg, completion: @continuation (val: Val?, err: Error?) -> Void)`

This function would transform to something like this:

`func bar(_ arg: Arg) throws async -> Val`

Some developers already have adopted a Result style - it would be nice to support the same conversion here too:

`func bar2(_ arg: Arg, completion: @continuation (result: Result<Val>) -> Void)` ->
`func bar2(_ arg: Arg) throws async -> Val`

Maybe `Result` has to adopt a specific protocol to allow this.

Ad 2 - Await with Timeouts

It could be helpful to have the option to specify how long an await should wait before throwing a timeout error:

do {
  let val = try await(for: 2.718) bar(arg)
} catch AsyncError.timeout {
  // handle timeout
} catch {
  // handle other errors
}

Ad 3 - Cancelation

Sometimes, I maybe want to cancel an async operation.

class C {
  var task: CancelableTask<Val>?
  
  func startProcess() {
    do {
      task = baz(arg)
      let val = try await task!
      …
    } catch AsyncError.cancelation {
      // handle cancelation
    } catch {
      // handle other errors
    }
  }

  func cancelProcess() {
    task?.cancel()
  }
}

To be cancelable, a function needs to support that:

func baz(_ arg: Arg) -> CancelableTask<Val> {
    let task = CancelableTask<Val>()
    let sess = URLSession.dataTask(with: arg.url) { data, resp, err in
      // No automatic CPS conversion here as dataTask does not return Void
      task.finish(with: data.val)
    }
    task.onCancellation {
      sess.cancel()
    }
    return task
} 

`baz` would have an equivalent signature of:

`func baz(_ arg: Arg) throws async cancelable-> Val`

Then, the non-cancellable `bar` function from above could also be written as:

`func bar(_ arg: Arg) -> Task<Val>` (aka. Promise, Future, …)

and the non-throwing `foo` function:

`func foo(_ arg: Arg) -> NonThrowingTask<Val>`

Of course, work on concurrency in Swift has a much bigger scope than this laundry list of
on async/await capabilities.

Cheers
Marc