File Coverage

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