Mojo-AsyncAwait
view release on metacpan or search on metacpan
lib/Mojo/AsyncAwait/Backend/Coro.pm view on Meta::CPAN
use Mojo::Promise;
use Sub::Util ();
use Exporter 'import';
our @EXPORT = (qw/async await/);
my $main = Coro::State->new;
$main->{desc} = 'Mojo::AsyncAwait::Backend::Coro/$main';
# LIFO stack of coroutines waiting to come back to
# always has $main as the bottom of the stack
my @stack = ($main);
# Coroutines that are ostensible done but need someone to kill them
my @clean;
# _push adds a coroutine to the stack and enters it
# when control returns to the original pusher, it will clean up
# any coroutines that are waiting to be cleaned up
sub _push {
push @stack, @_;
$stack[-2]->transfer($stack[-1]);
$_->cancel for @clean;
@clean = ();
}
# _pop pops the current coroutine off the stack. If given a callback, it calls
# a callback on it, otherwise, schedules it for cleanup. It then transfers to
# the next one on the stack. Note that it can't pop-and-return (which would
# make more sense) because any action on it must happen before control is
# transfered away from it
sub _pop (;&) {
Carp::croak "Cannot leave the main thread"
if $stack[-1] == $main;
my ($cb) = @_;
my $current = pop @stack;
lib/Mojo/AsyncAwait/Backend/Coro.pm view on Meta::CPAN
$bodyname .= "($name)";
}
my $desc = "declared at $caller[1] line $caller[2]";
Sub::Util::set_subname($bodyname => $body)
if Sub::Util::subname($body) =~ /::__ANON__$/;
my $wrapped = sub {
my @caller = caller;
my $promise = Mojo::Promise->new;
my $coro = Coro::State->new(sub {
eval {
BEGIN { $^H{'Mojo::AsyncAwait::Backend::Coro/async'} = 1 }
$promise->resolve($body->(@_)); 1
} or $promise->reject($@);
_pop;
}, @_);
$coro->{desc} = "$subname called at $caller[1] line $caller[2], $desc";
_push $coro;
return $promise;
};
if ($opts->{-install}) {
Mojo::Util::monkey_patch $caller[0], $opts->{-name} => $wrapped;
return;
}
Sub::Util::set_subname $subname => $wrapped;
return $wrapped;
t/promise_actions.t view on Meta::CPAN
use Test::Mojo;
if (eval{ Mojolicious->VERSION(8.28); 1}) {
plan skip_all => 'Mojolicious 8.28+ handles PromiseActions in core';
}
# specifically use development mode for the exception page
app->mode('development');
# manually install the guts of Mojolicious::Plugin::PromiseActions
# this tests that exception handling at the main coro can be accomplished from the hook
hook around_action => sub {
my ($next, $c) = @_;
my $res = $next->();
if (blessed($res) && $res->can('then')) {
my $tx = $c->render_later;
$res->then(undef, sub { $c->reply->exception('XXX:' . pop) and undef $tx })->wait;
}
return $res;
};
( run in 0.286 second using v1.01-cache-2.11-cpan-3cd7ad12f66 )