1. # Waits for a promise to be kept or a channel to be able to receive a value
  2. # and, once it can, unwraps or returns the result. Under Perl 6.c, await will
  3. # really block the calling thread. In 6.d, if the thread is on the thread pool
  4. # then a continuation will be taken, and the thread is freed up.
  5. my role X::Await::Died {
  6. has $.await-backtrace;
  7. multi method gist(::?CLASS:D:) {
  8. "An operation first awaited:\n" ~
  9. ((try $!await-backtrace ~ "\n") // '<unknown location>') ~
  10. "Died with the exception:\n" ~
  11. callsame().indent(4)
  12. }
  13. }
  14. proto sub await(|) {*}
  15. multi sub await() {
  16. die "Must specify a Promise or Channel to await on (got an empty list)";
  17. }
  18. multi sub await(Any:U $x) {
  19. die "Must specify a defined Promise, Channel, or Supply to await on (got an undefined $x.^name())";
  20. }
  21. multi sub await(Any:D $x) {
  22. die "Must specify a Promise, Channel, or Supply to await on (got a $x.^name())";
  23. }
  24. multi sub await(Promise:D $p) {
  25. CATCH {
  26. unless nqp::istype($_, X::Await::Died) {
  27. ($_ but X::Await::Died(Backtrace.new(5))).rethrow
  28. }
  29. }
  30. my $*RAKUDO-AWAIT-BLOCKING := True;
  31. $*AWAITER.await($p)
  32. }
  33. multi sub await(Channel:D $c) {
  34. CATCH {
  35. unless nqp::istype($_, X::Await::Died) {
  36. ($_ but X::Await::Died(Backtrace.new(5))).rethrow
  37. }
  38. }
  39. my $*RAKUDO-AWAIT-BLOCKING := True;
  40. $*AWAITER.await($c)
  41. }
  42. multi sub await(Supply:D $s) {
  43. CATCH {
  44. unless nqp::istype($_, X::Await::Died) {
  45. ($_ but X::Await::Died(Backtrace.new(5))).rethrow
  46. }
  47. }
  48. my $*RAKUDO-AWAIT-BLOCKING := True;
  49. $*AWAITER.await($s)
  50. }
  51. multi sub await(Iterable:D $i) { eager $i.eager.map({ await $_ }) }
  52. multi sub await(*@awaitables) { eager @awaitables.eager.map({await $_}) }
  53. sub awaiterator(@promises) {
  54. Seq.new(class :: does Iterator {
  55. has @!todo;
  56. has @!done;
  57. method !SET-SELF(\todo) { @!todo = todo; self }
  58. method new(\todo) { nqp::create(self)!SET-SELF(todo) }
  59. method pull-one() is raw {
  60. if @!done {
  61. @!done.shift
  62. }
  63. elsif @!todo {
  64. Promise.anyof(@!todo).result;
  65. my @next;
  66. .status == Planned
  67. ?? @next.push($_)
  68. !! @!done.push($_.result)
  69. for @!todo;
  70. @!todo := @next;
  71. @!done.shift
  72. }
  73. else {
  74. IterationEnd
  75. }
  76. }
  77. method sink-all(--> IterationEnd) { Promise.allof(@promises).result }
  78. }.new(@promises))
  79. }