IO-Lambda
view release on metacpan or search on metacpan
lib/IO/Lambda.pm view on Meta::CPAN
my @ret;
my @frame = get_frame();
while ( 1) {
push @ret, map { $_-> peek } grep { $_-> {stopped} } @objects;
@objects = grep { not $_-> {stopped} } @objects;
last unless @objects;
yield;
}
set_frame(@frame);
return @ret;
}
# wait for at least one lambda to stop, return those that stopped
sub wait_for_any
{
my @objects = @_;
return unless @objects;
$_-> start for grep { $_-> is_passive } @objects;
my @frame = get_frame();
while ( 1) {
my @n = grep { $_-> {stopped} } @objects;
set_frame(@frame), return @n if @n;
yield;
}
set_frame(@frame);
return;
}
# run the event loop until no lambdas are left in the blocking state
sub run {
my @frame = get_frame();
do {} while yield;
set_frame(@frame);
}
#
# Part II - Procedural interface to the lambda-style programming
#
#################################################################
sub _lambda_restart { die "lambda() is not restartable" }
sub lambda(&)
{
my $cb = _subname(lambda => $_[0]);
my $l = __PACKAGE__-> new( sub {
# initial lambda code is usually executed by tail/tails inside another lambda,
# so protect the upper-level context
local *__ANON__ = "IO::Lambda::lambda::callback";
local $THIS = shift;
local @CONTEXT = ();
local $CALLBACK = $cb;
local $METHOD = \&_lambda_restart;
$cb ? $cb-> (@_) : @_;
});
if ( $DEBUG_CALLER) {
if ( $DEBUG_CALLER > 1) {
$l-> {caller} = Carp::longmess;
chomp $l-> {caller};
$l-> {caller} =~ s/^ at //;
} else {
$l-> {caller} = join(':', (caller)[1,2]);
}
}
$l;
}
sub _subname
{
subname(
caller(1 + ($_[2] || 0)) . '::_'. $_[0],
$_[1]
) if $DEBUG_CALLER and $_[1] and not $AGAIN;
return $_[1];
}
*io = \λ
# re-enter the latest (or other) frame
sub again
{
if ( @_ ) {
my $name = shift;
Carp::carp("no such frame:$name") unless exists $THIS->{frames}->{$name};
($METHOD, $CALLBACK, @CONTEXT) = @{ $THIS->{frames}->{$name} };
@CONTEXT = @_ if @_;
}
local $AGAIN = 1;
defined($METHOD) ?
$METHOD-> ($CALLBACK) :
confess "again() outside of a restartable call"
}
# define context
sub this { @_ ? ($THIS, @CONTEXT) = @_ : $THIS }
sub context { @_ ? (@CONTEXT) = @_ : @CONTEXT }
sub set_frame { ( $THIS, $METHOD, $CALLBACK, @CONTEXT) = @_ }
sub get_frame { ( $THIS, $METHOD, $CALLBACK, @CONTEXT) }
sub swap_frame { my @f = get_frame; set_frame(@_); @f }
sub clear { set_frame(); undef $AGAIN; }
sub delete_frame { delete $THIS->{frames}->{$_[0]} }
END { ( $THIS, $METHOD, $CALLBACK, @CONTEXT) = (); }
sub state($)
{
my $this = ($_[0] && ref($_[0])) ? shift(@_) : this;
@_ ? $this-> {state} = $_[0] : return $this-> {state};
}
sub restartable
{
my $name = @_ ? $_[0] : join(':', caller);
$THIS->{frames}->{$name} = [ $METHOD, $CALLBACK, @CONTEXT ];
return $name;
}
# exceptions and backtracing
sub catch(&$)
{
my ( $cb, $event) = @_;
my $who = (caller(1))[3];
( run in 1.970 second using v1.01-cache-2.11-cpan-302cb4679cc )