File Coverage

blib/lib/AnyEvent/Future.pm
Criterion Covered Total %
statement 63 63 100.0
branch 4 4 100.0
condition 2 3 66.6
subroutine 20 20 100.0
pod 6 7 85.7
total 95 97 97.9


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2014-2019 -- leonerd@leonerd.org.uk
5              
6             package AnyEvent::Future;
7              
8 4     4   273717 use strict;
  4         32  
  4         97  
9 4     4   17 use warnings;
  4         6  
  4         138  
10              
11             our $VERSION = '0.04';
12              
13 4     4   29 use base qw( Future );
  4         6  
  4         2361  
14             Future->VERSION( '0.05' ); # to respect subclassing
15              
16 4     4   37971 use Exporter 'import';
  4         9  
  4         205  
17             our @EXPORT_OK = qw(
18             as_future
19             as_future_cb
20             );
21              
22 4     4   846 use AnyEvent;
  4         4449  
  4         2160  
23              
24             =head1 NAME
25              
26             C - use L with L
27              
28             =head1 SYNOPSIS
29              
30             use AnyEvent;
31             use AnyEvent::Future;
32              
33             my $future = AnyEvent::Future->new;
34              
35             some_async_function( ..., cb => sub { $future->done( @_ ) } );
36              
37             print Future->wait_any(
38             $future,
39             AnyEvent::Future->new_timeout( after => 10 ),
40             )->get;
41              
42             Or
43              
44             use AnyEvent::Future qw( as_future_cb );
45              
46             print Future->wait_any(
47             as_future_cb {
48             some_async_function( ..., cb => shift )
49             },
50             AnyEvent::Future->new_timeout( after => 10 ),
51             )->get;
52              
53             =head1 DESCRIPTION
54              
55             This subclass of L integrates with L, allowing the C
56             method to block until the future is ready. It allows C-using code to
57             be written that returns C instances, so that it can make full use of
58             C's abilities, including L, and also that modules using
59             it can provide a C-based asynchronous interface of their own.
60              
61             For a full description on how to use Futures, see the L documentation.
62              
63             =cut
64              
65             # Forward
66             sub as_future(&);
67              
68             =head1 CONSTRUCTORS
69              
70             =cut
71              
72             =head2 new
73              
74             $f = AnyEvent::Future->new
75              
76             Returns a new leaf future instance, which will allow waiting for its result to
77             be made available, using the C method.
78              
79             =cut
80              
81             =head2 new_delay
82              
83             $f = AnyEvent::Future->new_delay( @args )
84              
85             =head2 new_timeout
86              
87             $f = AnyEvent::Future->new_timeout( @args )
88              
89             Returns a new leaf future instance that will become ready at the time given by
90             the arguments, which will be passed to the C<< AnyEvent->timer >> method.
91              
92             C returns a future that will complete successfully at the alotted
93             time, whereas C returns a future that will fail with the message
94             C. This is provided as a simple utility for small use-cases; for a
95             more find-grained control over the failure message and additional values you
96             may wish to use C combined with the C method:
97              
98             new_delay( after => 10 )
99             ->then_fail( "The operation timed out after 10 seconds", timeout => );
100              
101             =cut
102              
103             sub new_delay
104             {
105 1     1 1 92 shift;
106 1         4 my %args = @_;
107              
108             as_future {
109 1     1   2 my $f = shift;
110 1         8 AnyEvent->timer( %args, cb => sub { $f->done } );
  1         999218  
111 1         6 };
112             }
113              
114             sub new_timeout
115             {
116 1     1 1 1197 shift;
117 1         4 my %args = @_;
118              
119             as_future {
120 1     1   1 my $f = shift;
121 1         12 AnyEvent->timer( %args, cb => sub { $f->fail( "Timeout" ) } );
  1         999163  
122 1         24 };
123             }
124              
125             =head2 from_cv
126              
127             $f = AnyEvent::Future->from_cv( $cv )
128              
129             Returns a new leaf future instance that will become ready when the given
130             L instance is ready. The success or failure result of the
131             future will be the result passed to the condvar's C or C method.
132              
133             =cut
134              
135             sub from_cv
136             {
137 3     3 1 5782 my $class = shift;
138 3         7 my ( $cv ) = @_;
139              
140 3         14 my $f = $class->new;
141              
142 3         28 my $was_cb = $cv->cb;
143              
144             $cv->cb( sub {
145 3     3   513 my ( $cv ) = @_;
146 3         4 my @result;
147 3 100 66     4 eval { @result = $cv->recv; 1 } and $f->done( @result ) or
  3         10  
  2         24  
148             $f->fail( $@ );
149              
150 3 100       347 $was_cb->( @_ ) if $was_cb;
151 3         56 });
152              
153 3         22 return $f;
154             }
155              
156             =head1 METHODS
157              
158             =cut
159              
160             =head2 as_cv
161              
162             $cv = $f->as_cv
163              
164             Returns a new C instance that wraps the given future; it
165             will complete with success or failure when the future does.
166              
167             Note that because C<< AnyEvent::CondVar->croak >> takes only a single string
168             message for the argument, any subsequent failure detail values from the future
169             are lost by the condvar. To capture these as well, you may wish to use an
170             C callback or the C method, to obtain them.
171              
172             =cut
173              
174             sub as_cv
175             {
176 2     2 1 1223 my $self = shift;
177              
178 2         46 my $cv = AnyEvent->condvar;
179              
180 2     1   21 $self->on_done( sub { $cv->send( @_ ) } );
  1         56  
181 2     1   59 $self->on_fail( sub { $cv->croak( $_[0] ) } );
  1         54  
182              
183 2         36 return $cv;
184             }
185              
186             sub await
187             {
188 6     6 0 4207 my $self = shift;
189              
190 6         154 my $cv = AnyEvent->condvar;
191 6     6   320 $self->on_ready( sub { $cv->send } );
  6         2760  
192              
193 6         155 $cv->recv;
194             }
195              
196             =head1 UTILITY FUNCTIONS
197              
198             The following utility functions are exported as a convenience.
199              
200             =cut
201              
202             =head2 as_future
203              
204             $f = as_future { CODE }
205              
206             Returns a new leaf future instance, which is also passed in to the block of
207             code. The code is called in scalar context, and its return value is stored on
208             the future. This will be deleted if the future is cancelled.
209              
210             $w = CODE->( $f )
211              
212             This utility is provided for the common case of wanting to wrap an C
213             function which will want to receive a callback function to inform of
214             completion, and which will return a watcher object reference that needs to be
215             stored somewhere.
216              
217             =cut
218              
219             sub as_future(&)
220             {
221 6     6 1 1291 my ( $code ) = @_;
222              
223 6         32 my $f = AnyEvent::Future->new;
224              
225 6         48 $f->{w} = $code->( $f );
226 6     1   4124 $f->on_cancel( sub { undef shift->{w} } );
  1         22  
227              
228 6         114 return $f;
229             }
230              
231             =head2 as_future_cb
232              
233             $f = as_future_cb { CODE }
234              
235             A futher shortcut to C, where the code is passed two callback
236             functions for C and C directly, avoiding boilerplate in the common
237             case for creating these closures capturing the future variable. In many cases
238             this can reduce the code block to a single line.
239              
240             $w = CODE->( $done_cb, $fail_cb )
241              
242             =cut
243              
244             sub as_future_cb(&)
245             {
246 2     2 1 31343 my ( $code ) = @_;
247              
248             &as_future( sub {
249 2     2   5 my $f = shift;
250 2         9 $code->( sub { $f->done(@_) }, sub { $f->fail(@_) } );
  1         1124  
  1         1125  
251 2         10 });
252             }
253              
254             =head1 EXAMPLES
255              
256             =head2 Wrapping watcher-style C functions
257              
258             The C utility provides an excellent wrapper to take the common
259             style of C function that returns a watcher object and takes a
260             completion callback, and turn it into a C that can be used or combined
261             with other C-based code. For example, the L function
262             called C performs in this style.
263              
264             use AnyEvent::Future qw( as_future_cb );
265             use AnyEvent::HTTP qw( http_get );
266              
267             my $url = ...;
268              
269             my $f = as_future_cb {
270             my ( $done_cb ) = @_;
271              
272             http_get $url, $done_cb;
273             };
274              
275             This could of course be easily wrapped by a convenient function to return
276             futures:
277              
278             sub http_get_future
279             {
280             my @args = @_;
281              
282             as_future_cb {
283             my ( $done_cb ) = @_;
284              
285             http_get @args, $done_cb;
286             }
287             }
288              
289             =head2 Using Cs as enhanced Cs
290              
291             While at first glance it may appear that a C instance is much like an
292             L, the greater set of convergence methods (such as
293             C or C), and the various utility functions (in
294             L) makes it possible to write the same style of code in a more
295             concise or powerful way.
296              
297             For example, rather than using the C C and C methods, a
298             set of C-returning functions can be converted into C,
299             combined using C, and converted back to a C again:
300              
301             my $cv = Future->needs_all(
302             Future::AnyEvent->from_cv( FUNC1() ),
303             Future::AnyEvent->from_cv( FUNC2() ),
304             ...
305             )->as_cv;
306              
307             my @results = $cv->recv;
308              
309             This would become yet more useful if, instead of functions that return
310             C, we were operating on functions that return Cs directly.
311             Because the C will cancel any still-pending futures the moment one
312             of them failed, we get a nice neat cancellation of outstanding work if one of
313             them fails, in a way that would be much harder without the Cs. For
314             example, using the C function from above:
315              
316             my $cv = Future->needs_all(
317             http_get_future( "http://url-1" ),
318             http_get_future( "http://url-2" ),
319             http_get_future( "https://url-third/secret" ),
320             )->as_cv;
321              
322             my @results = $cv->recv;
323              
324             In this case, the moment any of the HTTP GET functions fails, the ones that
325             are still pending are all cancelled (by dropping their cancellation watcher
326             object) and the overall C call throws an exception.
327              
328             Of course, there is no need to convert the outermost C into a
329             C; the full set of waiting semantics are implemented on these
330             instances, so instead you may simply call C on it to achieve the same
331             effect:
332              
333             my $f = Future->needs_all(
334             http_get_future( "http://url-1" ),
335             ...
336             );
337              
338             my @results = $f->get;
339              
340             This has other side advantages, such as the list-valued semantics of failures
341             that can provide additional information besides just the error message, and
342             propagation of cancellation requests.
343              
344             =cut
345              
346             =head1 TODO
347              
348             =over 4
349              
350             =item *
351              
352             Consider whether or not it would be considered "evil" to inject a new method
353             into L; namely by doing
354              
355             sub AnyEvent::CondVar::as_future { AnyEvent::Future->from_cv( shift ) }
356              
357             =back
358              
359             =head1 AUTHOR
360              
361             Paul Evans
362              
363             =cut
364              
365             0x55AA;