File: Deferred.pm

package info (click to toggle)
libpromise-xs-perl 0.20-1
  • links: PTS
  • area: main
  • in suites: forky, sid, trixie
  • size: 908 kB
  • sloc: perl: 1,097; ansic: 355; makefile: 3
file content (143 lines) | stat: -rw-r--r-- 3,136 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package Promise::XS::Deferred;

use strict;
use warnings;

=encoding utf-8

=head1 NAME

Promise::XS::Deferred - deferred object

=head1 SYNOPSIS

See L<Promise::XS>.

=head1 DESCRIPTION

This class implements a promise’s “producer” behavior. It is not
to be instantiated directly, but rather via L<Promise::XS>.

=head1 BASIC METHODS

The following are what’s needed to implement normal promise workflows:

=head2 $obj = I<OBJ>->resolve( @ARGUMENTS )

Resolves I<OBJ>’s promise, assigning the given @ARGUMENTS as the value.
Returns I<OBJ>.

B<IMPORTANT:> Behavior here is B<not> defined if anything in @ARGUMENTS is
itself a promise.

=head2 $obj = I<OBJ>->reject( @ARGUMENTS )

Like C<resolve()> but rejects the promise instead.

=head1 ADDITIONAL METHODS

=head2 $yn = I<OBJ>->is_pending()

Returns a boolean that indicates whether the promise is still pending
(as opposed to resolved or rejected).

This shouldn’t normally be necessary but can be useful in debugging.

For compatibility with preexisting promise libraries, C<is_in_progress()>
exists as an alias for this logic.

=head2 $obj = I<OBJ>->clear_unhandled_rejection()

Ordinarily, if a promise’s rejection is “unhandled”, a warning about the
unhandled rejection is produced. Call this after C<reject()> to silence
that warning. (It’s generally better, of course, to handle all errors.)

=cut

#----------------------------------------------------------------------

*is_in_progress = *is_pending;

our $_NOTHING_CR = sub { };

#----------------------------------------------------------------------
# Undocumented, by design:

sub set_deferral_AnyEvent() {
    require AnyEvent;

    ___set_deferral_generic(
        AnyEvent->can('postpone') || \&_anyevent_postpone_compat,
        undef,
        _DEFER_ANYEVENT(),
    );
}

sub set_deferral_IOAsync {
    my ($loop) = @_;

    ___set_deferral_generic(
        $loop->can('later') || \&_ioasync_later_compat,
        $loop,
        _DEFER_IOASYNC(),
        sub { $loop->stop() },
    );
}

sub set_deferral_Mojo() {
    require Mojo::IOLoop;

    ___set_deferral_generic(
        Mojo::IOLoop->can('next_tick') || \&_mojo_next_tick_compat,
        'Mojo::IOLoop',
        _DEFER_MOJO(),
        sub { Mojo::IOLoop->stop() },
    );
}

#----------------------------------------------------------------------
# Polyfills for old versions of the event loops that didn’t include
# zero-timer convenience functions:

my %ae_timer;

sub _anyevent_postpone_compat {
    my $cb = $_[0];

    my ($w, $w_str);

    $w = AnyEvent->timer( after => 0, cb => sub {
        delete $ae_timer{$w_str};
        $cb->();
    } );

    $w_str = "$w";
    $ae_timer{$w_str} = $w;
}

sub _ioasync_later_compat {
    local ($@, $!);
    require IO::Async::Timer;

    $_[0]->add( IO::Async::Timer->new(
        mode => 'countdown',
        delay => 0,
        on_expire => $_[1],
    )->start() );
}

sub _mojo_next_tick_compat {
    Mojo::IOLoop->timer( 0, $_[1] );
}

1;

__END__

sub _ioasync_wait_promise {
    my $loop = $_[1];

    $_[0]->catch(\&_NOTHING)->finally(sub { $loop->stop() } );

    $loop->run();
}