Acme-Sort-Sleep
view release on metacpan or search on metacpan
local/lib/perl5/Future.pm view on Meta::CPAN
$self->{ready} = 1;
$self->{ready_at} = _shortmess "fail" if DEBUG;
$self->{failure} = [ $exception, @details ];
}
if( DEBUG ) {
my $at = Carp::shortmess( "failed" );
chomp $at; $at =~ s/\.$//;
$self->{ready_at} = $at;
}
return $self;
}
sub fail_cb
{
my $self = shift;
return sub { $self->fail( @_ ) };
}
=head2 die
$future->die( $message, @details )
I<Since version 0.09.>
A convenient wrapper around C<fail>. If the exception is a non-reference that
does not end in a linefeed, its value will be extended by the file and line
number of the caller, similar to the logic that C<die> uses.
Returns the C<$future>.
=cut
sub die :method
{
my $self = shift;
my ( $exception, @details ) = @_;
if( !ref $exception and $exception !~ m/\n$/ ) {
$exception .= sprintf " at %s line %d\n", (caller)[1,2];
}
$self->fail( $exception, @details );
}
=head2 on_cancel
$future->on_cancel( $code )
If the future is not yet ready, adds a callback to be invoked if the future is
cancelled by the C<cancel> method. If the future is already ready, throws an
exception.
If the future is cancelled, the callbacks will be invoked in the reverse order
to that in which they were registered.
$on_cancel->( $future )
If passed another C<Future> instance, the passed instance will be cancelled
when the original future is cancelled. This method does nothing if the future
is already complete.
=cut
sub on_cancel
{
my $self = shift;
my ( $code ) = @_;
my $is_future = blessed( $code ) && $code->isa( "Future" );
$is_future or _callable( $code ) or
Carp::croak "Expected \$code to be callable or a Future in ->on_cancel";
$self->{ready} and return $self;
push @{ $self->{on_cancel} }, $code;
return $self;
}
=head2 is_cancelled
$cancelled = $future->is_cancelled
Returns true if the future has been cancelled by C<cancel>.
=cut
sub is_cancelled
{
my $self = shift;
return $self->{cancelled};
}
=head1 USER METHODS
These methods would primarily be used by users of asynchronous interfaces, on
objects returned by such an interface.
=cut
=head2 is_ready
$ready = $future->is_ready
Returns true on a leaf future if a result has been provided to the C<done>
method, failed using the C<fail> method, or cancelled using the C<cancel>
method.
Returns true on a convergent future if it is ready to yield a result,
depending on its component futures.
=cut
sub is_ready
{
my $self = shift;
return $self->{ready};
}
=head2 on_ready
$future->on_ready( $code )
If the future is not yet ready, adds a callback to be invoked when the future
is ready. If the future is already ready, invokes it immediately.
In either case, the callback will be passed the future object itself. The
invoked code can then obtain the list of results by calling the C<get> method.
$on_ready->( $future )
If passed another C<Future> instance, the passed instance will have its
C<done>, C<fail> or C<cancel> methods invoked when the original future
completes successfully, fails, or is cancelled respectively.
Returns the C<$future>.
=cut
sub on_ready
{
my $self = shift;
my ( $code ) = @_;
my $is_future = blessed( $code ) && $code->isa( "Future" );
$is_future or _callable( $code ) or
Carp::croak "Expected \$code to be callable or a Future in ->on_ready";
if( $self->{ready} ) {
my $fail = defined $self->{failure};
my $done = !$fail && !$self->{cancelled};
$self->{reported} = 1 if $fail;
$is_future ? ( $done ? $code->done( $self->get ) :
$fail ? $code->fail( $self->failure ) :
$code->cancel )
: $code->( $self );
}
else {
push @{ $self->{callbacks} }, [ CB_ALWAYS|CB_SELF, $self->wrap_cb( on_ready => $code ) ];
}
return $self;
}
=head2 is_done
$done = $future->is_done
Returns true on a future if it is ready and completed successfully. Returns
false if it is still pending, failed, or was cancelled.
=cut
sub is_done
{
my $self = shift;
return $self->{ready} && !$self->{failure} && !$self->{cancelled};
}
=head2 get
@result = $future->get
$result = $future->get
If the future is ready and completed successfully, returns the list of
results that had earlier been given to the C<done> method on a leaf future,
or the list of component futures it was waiting for on a convergent future. In
scalar context it returns just the first result value.
If the future is ready but failed, this method raises as an exception the
local/lib/perl5/Future.pm view on Meta::CPAN
sub get
{
my $self = shift;
$self->await until $self->{ready};
if( $self->{failure} ) {
$self->{reported} = 1;
my $exception = $self->{failure}->[0];
!ref $exception && $exception =~ m/\n$/ ? CORE::die $exception : Carp::croak $exception;
}
$self->{cancelled} and Carp::croak "${\$self->__selfstr} was cancelled";
return $self->{result}->[0] unless wantarray;
return @{ $self->{result} };
}
=head2 unwrap
@values = Future->unwrap( @values )
I<Since version 0.26.>
If given a single argument which is a C<Future> reference, this method will
call C<get> on it and return the result. Otherwise, it returns the list of
values directly in list context, or the first value in scalar. Since it
involves an implicit C<await>, this method can only be used on immediate
futures or subclasses that implement C<await>.
This will ensure that an outgoing argument is definitely not a C<Future>, and
may be useful in such cases as adapting synchronous code to fit asynchronous
libraries that return C<Future> instances.
=cut
sub unwrap
{
shift; # $class
my @values = @_;
if( @values == 1 and blessed $values[0] and $values[0]->isa( __PACKAGE__ ) ) {
return $values[0]->get;
}
else {
return $values[0] if !wantarray;
return @values;
}
}
=head2 on_done
$future->on_done( $code )
If the future is not yet ready, adds a callback to be invoked when the future
is ready, if it completes successfully. If the future completed successfully,
invokes it immediately. If it failed or was cancelled, it is not invoked at
all.
The callback will be passed the result passed to the C<done> method.
$on_done->( @result )
If passed another C<Future> instance, the passed instance will have its
C<done> method invoked when the original future completes successfully.
Returns the C<$future>.
=cut
sub on_done
{
my $self = shift;
my ( $code ) = @_;
my $is_future = blessed( $code ) && $code->isa( "Future" );
$is_future or _callable( $code ) or
Carp::croak "Expected \$code to be callable or a Future in ->on_done";
if( $self->{ready} ) {
return $self if $self->{failure} or $self->{cancelled};
$is_future ? $code->done( $self->get )
: $code->( $self->get );
}
else {
push @{ $self->{callbacks} }, [ CB_DONE|CB_RESULT, $self->wrap_cb( on_done => $code ) ];
}
return $self;
}
=head2 is_failed
$failed = $future->is_failed
I<Since version 0.26.>
Returns true on a future if it is ready and it failed. Returns false if it is
still pending, completed successfully, or was cancelled.
=cut
sub is_failed
{
my $self = shift;
return $self->{ready} && !!$self->{failure}; # boolify
}
=head2 failure
$exception = $future->failure
$exception, @details = $future->failure
Returns the exception passed to the C<fail> method, C<undef> if the future
completed successfully via the C<done> method, or raises an exception if
called on a future that is not yet ready.
If called in list context, will additionally yield a list of the details
provided to the C<fail> method.
Because the exception value must be true, this can be used in a simple C<if>
statement:
if( my $exception = $future->failure ) {
...
}
else {
my @result = $future->get;
...
}
=cut
sub failure
{
my $self = shift;
$self->await until $self->{ready};
return unless $self->{failure};
$self->{reported} = 1;
return $self->{failure}->[0] if !wantarray;
return @{ $self->{failure} };
}
=head2 on_fail
$future->on_fail( $code )
If the future is not yet ready, adds a callback to be invoked when the future
is ready, if it fails. If the future has already failed, invokes it
immediately. If it completed successfully or was cancelled, it is not invoked
at all.
The callback will be passed the exception and details passed to the C<fail>
method.
$on_fail->( $exception, @details )
If passed another C<Future> instance, the passed instance will have its
C<fail> method invoked when the original future fails.
To invoke a C<done> method on a future when another one fails, use a CODE
reference:
$future->on_fail( sub { $f->done( @_ ) } );
Returns the C<$future>.
=cut
sub on_fail
{
my $self = shift;
my ( $code ) = @_;
my $is_future = blessed( $code ) && $code->isa( "Future" );
$is_future or _callable( $code ) or
Carp::croak "Expected \$code to be callable or a Future in ->on_fail";
if( $self->{ready} ) {
return $self if not $self->{failure};
$self->{reported} = 1;
$is_future ? $code->fail( $self->failure )
: $code->( $self->failure );
}
else {
push @{ $self->{callbacks} }, [ CB_FAIL|CB_RESULT, $self->wrap_cb( on_fail => $code ) ];
}
return $self;
}
=head2 cancel
$future->cancel
Requests that the future be cancelled, immediately marking it as ready. This
will invoke all of the code blocks registered by C<on_cancel>, in the reverse
order. When called on a convergent future, all its component futures are also
cancelled. It is not an error to attempt to cancel a future that is already
complete or cancelled; it simply has no effect.
Returns the C<$future>.
=cut
sub cancel
{
my $self = shift;
return $self if $self->{ready};
$self->{cancelled}++;
foreach my $code ( reverse @{ $self->{on_cancel} || [] } ) {
my $is_future = blessed( $code ) && $code->isa( "Future" );
$is_future ? $code->cancel
: $code->( $self );
}
$self->_mark_ready( "cancel" );
local/lib/perl5/Future.pm view on Meta::CPAN
=head2 transform
$future = $f1->transform( %args )
Returns a new sequencing C<Future> that wraps the one given as C<$f1>. With no
arguments this will be a trivial wrapper; C<$future> will complete or fail
when C<$f1> does, and C<$f1> will be cancelled when C<$future> is.
By passing the following named arguments, the returned C<$future> can be made
to behave differently to C<$f1>:
=over 8
=item done => CODE
Provides a function to use to modify the result of a successful completion.
When C<$f1> completes successfully, the result of its C<get> method is passed
into this function, and whatever it returns is passed to the C<done> method of
C<$future>
=item fail => CODE
Provides a function to use to modify the result of a failure. When C<$f1>
fails, the result of its C<failure> method is passed into this function, and
whatever it returns is passed to the C<fail> method of C<$future>.
=back
=cut
sub transform
{
my $self = shift;
my %args = @_;
my $xfrm_done = $args{done};
my $xfrm_fail = $args{fail};
return $self->_sequence( sub {
my $self = shift;
if( !$self->{failure} ) {
return $self unless $xfrm_done;
my @result = $xfrm_done->( $self->get );
return $self->new->done( @result );
}
else {
return $self unless $xfrm_fail;
my @failure = $xfrm_fail->( $self->failure );
return $self->new->fail( @failure );
}
}, CB_SEQ_ONDONE|CB_SEQ_ONFAIL|CB_SELF );
}
=head2 then_with_f
$future = $f1->then_with_f( ... )
I<Since version 0.21.>
Returns a new sequencing C<Future> that behaves like C<then>, but also passes
the original future, C<$f1>, to any functions it invokes.
$f2 = $done_code->( $f1, @result )
$f2 = $catch_code->( $f1, $name, @other_details )
$f2 = $fail_code->( $f1, @details )
This is useful for conditional execution cases where the code block may just
return the same result of the original future. In this case it is more
efficient to return the original future itself.
=cut
sub then_with_f
{
my $self = shift;
my $done_code = shift;
my $fail_code = ( @_ % 2 ) ? pop : undef;
my @catch_list = @_;
if( $done_code and !@catch_list and !$fail_code ) {
return $self->_sequence( $done_code, CB_SEQ_ONDONE|CB_SELF|CB_RESULT );
}
return $self->_sequence( $make_donecatchfail_sub->(
1, $done_code, $fail_code, @catch_list,
), CB_SEQ_ONDONE|CB_SEQ_ONFAIL|CB_SELF );
}
=head2 then_done
=head2 then_fail
$future = $f->then_done( @result )
$future = $f->then_fail( $exception, @details )
I<Since version 0.22.>
Convenient shortcuts to returning an immediate future from a C<then> block,
when the result is already known.
=cut
sub then_done
{
my $self = shift;
my ( @result ) = @_;
return $self->_sequence( \@result, CB_SEQ_ONDONE|CB_SEQ_IMDONE );
}
sub then_fail
{
my $self = shift;
my ( @failure ) = @_;
return $self->_sequence( \@failure, CB_SEQ_ONDONE|CB_SEQ_IMFAIL );
}
=head2 else_with_f
$future = $f1->else_with_f( \&code )
I<Since version 0.21.>
Returns a new sequencing C<Future> that runs the code if the first fails.
Identical to C<else>, except that the code reference will be passed both the
original future, C<$f1>, and its exception and details.
$f2 = $code->( $f1, $exception, @details )
This is useful for conditional execution cases where the code block may just
return the same result of the original future. In this case it is more
efficient to return the original future itself.
=cut
sub else_with_f
{
my $self = shift;
my ( $fail_code ) = @_;
return $self->_sequence( $fail_code, CB_SEQ_ONFAIL|CB_SELF|CB_RESULT );
}
=head2 else_done
=head2 else_fail
$future = $f->else_done( @result )
$future = $f->else_fail( $exception, @details )
I<Since version 0.22.>
Convenient shortcuts to returning an immediate future from a C<else> block,
when the result is already known.
=cut
sub else_done
{
my $self = shift;
my ( @result ) = @_;
return $self->_sequence( \@result, CB_SEQ_ONFAIL|CB_SEQ_IMDONE );
}
sub else_fail
{
my $self = shift;
my ( @failure ) = @_;
return $self->_sequence( \@failure, CB_SEQ_ONFAIL|CB_SEQ_IMFAIL );
}
=head2 catch_with_f
$future = $f1->catch_with_f( ... )
I<Since version 0.33.>
Returns a new sequencing C<Future> that behaves like C<catch>, but also passes
the original future, C<$f1>, to any functions it invokes.
=cut
sub catch_with_f
{
my $self = shift;
my $fail_code = ( @_ % 2 ) ? pop : undef;
my @catch_list = @_;
return $self->_sequence( $make_donecatchfail_sub->(
1, undef, $fail_code, @catch_list,
), CB_SEQ_ONDONE|CB_SEQ_ONFAIL|CB_SELF );
}
=head2 followed_by
$future = $f1->followed_by( \&code )
Returns a new sequencing C<Future> that runs the code regardless of success or
failure. Once C<$f1> is ready the code reference will be invoked and is passed
one argument, C<$f1>. It should return a future, C<$f2>. Once C<$f2> completes
the sequence future will then be marked as complete with whatever result
C<$f2> gave.
$f2 = $code->( $f1 )
=cut
sub followed_by
{
my $self = shift;
my ( $code ) = @_;
return $self->_sequence( $code, CB_SEQ_ONDONE|CB_SEQ_ONFAIL|CB_SELF );
}
=head2 without_cancel
$future = $f1->without_cancel
I<Since version 0.30.>
Returns a new sequencing C<Future> that will complete with the success or
failure of the original future, but if cancelled, will not cancel the
original. This may be useful if the original future represents an operation
that is being shared among multiple sequences; cancelling one should not
prevent the others from running too.
=cut
sub without_cancel
{
my $self = shift;
my $new = $self->new;
$self->on_ready( sub {
my $self = shift;
if( $self->failure ) {
$new->fail( $self->failure );
}
else {
$new->done( $self->get );
}
});
return $new;
}
=head1 CONVERGENT FUTURES
The following constructors all take a list of component futures, and return a
new future whose readiness somehow depends on the readiness of those
components. The first derived class component future will be used as the
prototype for constructing the return value, so it respects subclassing
correctly, or failing that a plain C<Future>.
=cut
sub _new_convergent
{
shift; # ignore this class
my ( $subs ) = @_;
foreach my $sub ( @$subs ) {
blessed $sub and $sub->isa( "Future" ) or Carp::croak "Expected a Future, got $_";
}
# Find the best prototype. Ideally anything derived if we can find one.
my $self;
ref($_) eq "Future" or $self = $_->new, last for @$subs;
# No derived ones; just have to be a basic class then
$self ||= Future->new;
$self->{subs} = $subs;
# This might be called by a DESTROY during global destruction so it should
# be as defensive as possible (see RT88967)
$self->on_cancel( sub {
foreach my $sub ( @$subs ) {
$sub->cancel if $sub and !$sub->{ready};
}
} );
return $self;
( run in 2.968 seconds using v1.01-cache-2.11-cpan-437f7b0c052 )