File Coverage

blib/lib/Venus/Future.pm
Criterion Covered Total %
statement 219 256 85.5
branch 97 156 62.1
condition 41 86 47.6
subroutine 37 38 97.3
pod 17 31 54.8
total 411 567 72.4


line stmt bran cond sub pod time code
1             package Venus::Future;
2              
3 1     1   33 use 5.018;
  1         3  
4              
5 1     1   7 use strict;
  1         2  
  1         30  
6 1     1   5 use warnings;
  1         2  
  1         45  
7              
8 1     1   8 use Venus::Class 'attr', 'base', 'with';
  1         2  
  1         12  
9              
10             base 'Venus::Kind::Utility';
11              
12             with 'Venus::Role::Buildable';
13              
14             # STATE
15              
16             state $FULFILLED = 'fulfilled';
17             state $PENDING = 'pending';
18             state $REJECTED = 'rejected';
19              
20             # HOOKS
21              
22             sub _time {
23             CORE::time();
24             }
25              
26             # BUILDERS
27              
28             sub build_arg {
29 1     1 0 4 my ($self, $data) = @_;
30              
31             return {
32 1         4 promise => $data,
33             };
34             }
35              
36             sub build_self {
37 83     83 0 155 my ($self, $data) = @_;
38              
39 83         214 $self->{status} = $PENDING;
40              
41 83 100       283 return $self if !exists $data->{promise};
42              
43 2         13 $self->promise($data->{promise});
44              
45 2         9 my $tryable = $self->try('fulfill')->error;
46              
47 2         8 my $result = $tryable->result;
48              
49 2 50       23 $self->reject($result) if UNIVERSAL::isa($result, 'Venus::Error');
50              
51 2         8 return $self;
52             }
53              
54             # METHODS
55              
56             sub catch {
57 2     2 1 7 my ($self, $on_reject) = @_;
58              
59 2         12 return $self->then(undef, $on_reject);
60             }
61              
62             sub finally {
63 3     3 1 11 my ($self, $on_finally) = @_;
64              
65 3         14 my $future = $self->class->new;
66              
67 3 50       17 my $is_rejectable = my $is_resolvable = ref $on_finally eq 'CODE'
68             ? true : false;
69              
70 3 50 33     77 if ($is_resolvable && $self->is_fulfilled) {
    50 33        
71 0         0 local $_ = $self->{value};
72 0         0 $on_finally->($self->{value});
73             }
74             elsif ($is_rejectable && $self->is_rejected) {
75 0         0 local $_ = $self->{issue};
76 0         0 $on_finally->($self->{issue});
77             }
78             else {
79 3 50 33     14 if ($is_resolvable && $is_rejectable) {
80 3         14 $self->on_finally($self->then_finally($future, $on_finally));
81             }
82             }
83              
84 3         56 return $future;
85             }
86              
87             sub fulfill {
88 14     14 1 40 my ($self) = @_;
89              
90 14 50       37 return true if !$self->is_pending;
91              
92 14         49 my $is_suspended = $self->is_suspended;
93              
94 14 100       54 $self->resume if $is_suspended;
95              
96 14 50       38 return $self->is_fulfilled ? true : false if $is_suspended;
    100          
97              
98 13 50       33 return false if !$self->{promise};
99              
100 13         49 my $rejectable = $self->try('reject');
101              
102 13         55 my $resolvable = $self->try('resolve');
103              
104 13         351 $self->{promise}->($resolvable, $rejectable);
105              
106 13 100       42 return $self->is_pending ? false : true;
107             }
108              
109             sub is {
110 3     3 1 7 my ($self, $name) = @_;
111              
112 3         9 my $method = "is_$name";
113              
114 3 50       17 return $self->can($method) ? ($self->$method ? true : false) : false;
    50          
115             }
116              
117             sub is_fulfilled {
118 42     42 1 7516 my ($self) = @_;
119              
120 42         94 my $status = $self->{status};
121              
122 42 100 66     245 return ($status && $status eq $FULFILLED) ? true : false;
123             }
124              
125             sub is_pending {
126 171     171 1 15185 my ($self) = @_;
127              
128 171         305 my $status = $self->{status};
129              
130 171 100 66     822 return ($status && $status eq $PENDING) ? true : false;
131             }
132              
133             sub is_promised {
134 3     3 1 8 my ($self) = @_;
135              
136 3 100       17 return exists $self->{promise} ? true : false;
137             }
138              
139             sub is_rejected {
140 20     20 1 2091 my ($self) = @_;
141              
142 20         48 my $status = $self->{status};
143              
144 20 100 66     129 return ($status && $status eq $REJECTED) ? true : false;
145             }
146              
147             sub is_resuming {
148 5     5 0 11 my ($self) = @_;
149              
150 5 100       22 return exists $self->{resuming} ? true : false;
151             }
152              
153             sub is_suspended {
154 124     124 0 222 my ($self) = @_;
155              
156 124 100       339 my $has_resume = exists $self->{resume} ? true : false;
157              
158 124 100       338 return false if !$has_resume;
159              
160 6 50       17 my $has_method = defined $self->{resume}->{method} ? true : false;
161              
162 6 50       14 return false if !$has_method;
163              
164 6 50       23 my $has_position = defined $self->{resume}->{position} ? true : false;
165              
166 6 50       16 return false if !$has_position;
167              
168 6 50       22 my $has_value = exists $self->{resume}->{value} ? true : false;
169              
170 6 50       13 return false if !$has_value;
171              
172 6         11 return true;
173             }
174              
175             sub is_thenable {
176 41     41 0 80 my ($self, $value) = @_;
177              
178 41 50       92 $value = $self if @_ < 2 ;
179              
180 41         147 require Scalar::Util;
181              
182 41         118 my $blessed = Scalar::Util::blessed($value);
183              
184 41 100       117 return false if !$blessed;
185              
186 26 100       126 my $is_future = $value->isa('Venus::Future') ? true : false;
187              
188 26 100       112 return true if $is_future;
189              
190 1 50       11 return $value->can('then') ? true : false;
191             }
192              
193             sub issue {
194 11     11 1 47 my ($self) = @_;
195              
196 11         64 return $self->{issue};
197             }
198              
199             sub on {
200 0     0 0 0 my ($self, @args) = @_;
201              
202 0         0 require Venus;
203 0         0 for my $pair (Venus::pairs(Venus::hashref(@args))) {
204 0         0 my ($name, $callback) = Venus::list($pair);
205 0         0 my $method = "on_$name";
206 0 0       0 $self->$method($callback) if $self->can($method);
207             }
208              
209 0         0 return $self;
210             }
211              
212             sub on_finally {
213 3     3 0 7 my ($self, $code) = @_;
214              
215 3 50       9 push @{$self->{on_finally}}, $code if $code;
  3         19  
216              
217 3         8 return $self;
218             }
219              
220             sub on_fulfilled {
221 19     19 0 42 my ($self, $code) = @_;
222              
223 19 50       45 push @{$self->{on_fulfilled}}, $code if $code;
  19         54  
224              
225 19         31 return $self;
226             }
227              
228             sub on_rejected {
229 7     7 0 17 my ($self, $code) = @_;
230              
231 7 50       27 push @{$self->{on_rejected}}, $code if $code;
  7         23  
232              
233 7         15 return $self;
234             }
235              
236             sub promise {
237 16     16 1 53 my ($self, $code) = @_;
238              
239 16 100 66     102 $self->{promise} ||= $code if $code;
240              
241 16         192 return $self;
242             }
243              
244             sub reject {
245 16     16 1 71 my ($self, $issue) = @_;
246              
247 16 50       67 return $self if !$self->is_pending;
248              
249 16         71 my $position = 0;
250              
251 16 50       64 if ($self->is_suspended) {
252 0         0 my $future = $self->{resume}->{future};
253 0         0 my $is_thenable = $self->is_thenable($future);
254 0         0 my $is_future = $future->isa('Venus::Future');
255              
256 0 0 0     0 return $self if $is_future && $future->is_pending;
257 0 0 0     0 return $self if $is_future && $future->is_fulfilled;
258              
259             $position
260             = ($is_future && $future->is_fulfilled)
261             ? ($self->{resume}->{position} + 1)
262 0 0 0     0 : $self->{resume}->{position};
263             }
264              
265 16   100     100 my $on_finally = $self->{on_finally} || [];
266              
267 16   100     86 my $on_rejected = $self->{on_rejected} || [];
268              
269 16         39 my @callbacks = (@{$on_rejected}, @{$on_finally});
  16         28  
  16         45  
270              
271 16         63 for (my $i = $position; $i < @callbacks; $i++) {
272 2         6 my $callback = $callbacks[$i];
273 2         6 local $_ = $issue;
274 2         7 my $future = $callback->($issue);
275 2 50 33     9 my $is_future = $self->is_thenable($future)
276             && $future->isa('Venus::Future') ? true : false;
277 2 50 33     13 if ($is_future && $future->is_pending) {
278 0         0 $future->resume;
279             }
280 2 50 33     12 if ($is_future && $future->is_pending) {
281 0         0 $self->suspend('reject', $i, $issue, $future);
282 0         0 last;
283             }
284             }
285              
286 16 50       49 return $self if $self->is_suspended;
287              
288 16         45 delete $self->{on_finally};
289 16         40 delete $self->{on_fulfilled};
290 16         36 delete $self->{on_rejected};
291 16         38 delete $self->{promise};
292 16         29 delete $self->{resume};
293 16         31 delete $self->{resuming};
294              
295 16         36 $self->{status} = $REJECTED;
296              
297 16         37 $self->{issue} = $issue;
298              
299 16         204 return $self;
300             }
301              
302             sub resolve {
303 39     39 1 127 my ($self, $value) = @_;
304              
305 39 50       89 return $self if !$self->is_pending;
306              
307 39         87 my $position = 0;
308              
309 39 100       106 if ($self->is_suspended) {
310 1         3 my $future = $self->{resume}->{future};
311 1         3 my $is_thenable = $self->is_thenable($future);
312 1         5 my $is_future = $future->isa('Venus::Future');
313              
314 1 50 33     6 return $self if $is_future && $future->is_pending;
315 1 50 33     5 return $self if $is_future && $future->is_rejected;
316              
317             $position
318             = ($is_future && $future->is_fulfilled)
319             ? ($self->{resume}->{position} + 1)
320 1 50 33     6 : $self->{resume}->{position};
321             }
322              
323 39   100     182 my $on_finally = $self->{on_finally} || [];
324              
325 39   100     128 my $on_fulfilled = $self->{on_fulfilled} || [];
326              
327 39         64 my @callbacks = (@{$on_fulfilled}, @{$on_finally});
  39         61  
  39         73  
328              
329 39         123 for (my $i = $position; $i < @callbacks; $i++) {
330 18         27 my $callback = $callbacks[$i];
331 18         35 local $_ = $value;
332 18         39 my $future = $callback->($value);
333 18 50 33     35 my $is_future = $self->is_thenable($future)
334             && $future->isa('Venus::Future') ? true : false;
335 18 100 66     58 if ($is_future && $future->is_pending) {
336 4         18 $future->resume;
337             }
338 18 100 66     65 if ($is_future && $future->is_pending) {
339 3         14 $self->suspend('resolve', $i, $value, $future);
340 3         7 last;
341             }
342             }
343              
344 39 100       90 return $self if $self->is_suspended;
345              
346 35         81 delete $self->{on_finally};
347 35         54 delete $self->{on_fulfilled};
348 35         62 delete $self->{on_rejected};
349 35         58 delete $self->{promise};
350 35         51 delete $self->{resume};
351 35         53 delete $self->{resuming};
352              
353 35         73 $self->{status} = $FULFILLED;
354              
355 35         92 $self->{value} = $value;
356              
357 35         314 return $self;
358             }
359              
360             sub resume {
361 5     5 0 12 my ($self) = @_;
362              
363 5 100       15 my $resume = delete $self->{resume} or return $self;
364              
365 3         9 $self->{resuming} = true;
366              
367 3         6 my $method = $resume->{method};
368              
369 3         5 my $value = $resume->{value};
370              
371 3         11 return $self->$method($value);
372             }
373              
374             sub status {
375 7     7 1 4234 my ($self) = @_;
376              
377 7         35 return $self->{status};
378             }
379              
380             sub suspend {
381 3     3 0 10 my ($self, $method, $position, $value, $future) = @_;
382              
383 3         7 delete $self->{resuming};
384              
385             $self->{resume} = {
386 3         13 method => $method,
387             position => $position,
388             value => $value,
389             future => $future,
390             };
391              
392 3         5 return $self;
393             }
394              
395             sub then {
396 23     23 1 59 my ($self, $on_fulfill, $on_reject) = @_;
397              
398 23         89 my $future = $self->class->new;
399              
400 23 100       129 my $is_rejectable = ref $on_reject eq 'CODE' ? true : false;
401 23 100       116 my $is_resolvable = ref $on_fulfill eq 'CODE' ? true : false;
402              
403 23 50 66     119 if ($is_resolvable && $self->is_fulfilled) {
    50 66        
404 0         0 local $_ = $self->{value};
405 0         0 $on_fulfill->($self->{value});
406             }
407             elsif ($is_rejectable && $self->is_rejected) {
408 0         0 local $_ = $self->{issue};
409 0         0 $on_reject->($self->{issue});
410             }
411             else {
412 23 100 66     80 if ($is_resolvable && $self->is_pending) {
413 19         81 $self->on_fulfilled($self->then_fulfill($future, $on_fulfill));
414             }
415 23 100 66     74 if ($is_rejectable && $self->is_pending) {
416 7         37 $self->on_rejected($self->then_reject($future, $on_reject));
417             }
418             }
419              
420 23         354 return $future;
421             }
422              
423             sub then_finally {
424 3     3 0 10 my ($self, $future, $on_finally) = @_;
425              
426             return sub {
427 2     2   6 my ($value) = @_;
428              
429 2 50       8 if (ref $on_finally eq 'CODE') {
430 2         5 local $_ = $value;
431 2         49 my $result = $on_finally->($value);
432 2 50       8 if ($self->is_thenable($result)) {
433 0 0 0     0 if ($self->is_resuming) {
    0          
434 0         0 return $future;
435             }
436             elsif ($result->isa('Venus::Future') && $result->is_fulfilled) {
437 0         0 return $result;
438             }
439             else {
440 0         0 return $result->then($future->defer('resolve'), $future->defer('reject'));
441             }
442             }
443             else {
444 2         10 return $future->resolve($result);
445             }
446             }
447             else {
448 0         0 return $future->resolve($value);
449             }
450 3         27 };
451             }
452              
453             sub then_fulfill {
454 19     19 0 42 my ($self, $future, $on_fulfill) = @_;
455              
456             return sub {
457 17     17   32 my ($value) = @_;
458              
459 17 50       44 if (ref $on_fulfill eq 'CODE') {
460 17         26 local $_ = $value;
461 17         346 my $result = $on_fulfill->($value);
462 17 100       49 if ($self->is_thenable($result)) {
463 5 100 100     14 if ($self->is_resuming) {
    100          
464 2         7 return $future;
465             }
466             elsif ($result->isa('Venus::Future') && $result->is_fulfilled) {
467 1         4 return $result;
468             }
469             else {
470 2         21 return $result->then($future->defer('resolve'), $future->defer('reject'));
471             }
472             }
473             else {
474 12         45 return $future->resolve($result);
475             }
476             }
477             else {
478 0         0 return $future->resolve($value);
479             }
480 19         118 };
481             }
482              
483             sub then_reject {
484 7     7 0 16 my ($self, $future, $on_reject) = @_;
485              
486             return sub {
487 1     1   3 my ($issue) = @_;
488              
489 1 50       4 if (ref $on_reject eq 'CODE') {
490 1         2 local $_ = $issue;
491 1         27 my $result = $on_reject->($issue);
492 1 50       20 if ($self->is_thenable($result)) {
493 0 0 0     0 if ($self->is_resuming) {
    0          
494 0         0 return $future;
495             }
496             elsif ($result->isa('Venus::Future') && $result->is_fulfilled) {
497 0         0 return $result;
498             }
499             else {
500 0         0 return $result->then($future->defer('resolve'), $future->defer('reject'));
501             }
502             }
503             else {
504 1         6 return $future->reject($result);
505             }
506             }
507             else {
508 0         0 return $future->reject($issue);
509             }
510 7         53 };
511             }
512              
513             sub value {
514 14     14 1 42 my ($self) = @_;
515              
516 14         80 return $self->{value};
517             }
518              
519             sub wait {
520 2     2 1 9 my ($self, $timeout) = @_;
521              
522 2 50       7 if (defined $timeout) {
523 2         7 my $seen = 0;
524 2         7 my $time = _time();
525 2         8 my $then = $time + $timeout;
526 2         7 while (time <= $then) {
527 1 50       8 last if $seen = $self->fulfill;
528             }
529 2 100       18 if (!$seen) {
530 1         14 $self->error({throw => 'error_on_timeout', timeout => $timeout});
531             }
532             }
533             else {
534 0         0 while (1) {
535 0 0       0 last if $self->fulfill;
536             }
537             }
538              
539 1         13 return $self;
540             }
541              
542             # ERRORS
543              
544             sub error_on_timeout {
545 2     2 1 6 my ($self, $data) = @_;
546              
547 2         4 my $message = 'Future timed-out after {{timeout}} seconds';
548              
549             my $stash = {
550             timeout => $data->{timeout},
551 2         6 };
552              
553 2         7 my $result = {
554             name => 'on.timeout',
555             raise => true,
556             stash => $stash,
557             message => $message,
558             };
559              
560 2         8 return $result;
561             }
562              
563             1;
564              
565              
566              
567             =head1 NAME
568              
569             Venus::Future - Future Class
570              
571             =cut
572              
573             =head1 ABSTRACT
574              
575             Future Class for Perl 5
576              
577             =cut
578              
579             =head1 SYNOPSIS
580              
581             package main;
582              
583             use Venus::Future;
584              
585             my $future = Venus::Future->new;
586              
587             # bless({...}, 'Venus::Future')
588              
589             # $future->promise(sub{
590             # my ($resolve, $reject) = @_;
591             # $resolve->result(1);
592             # });
593              
594             # bless({...}, 'Venus::Future')
595              
596             # $future->fulfill;
597              
598             # true
599              
600             =cut
601              
602             =head1 DESCRIPTION
603              
604             This package provides a framework-agnostic "Future" and implementation of the
605             "Promise/A+" pattern for asynchronous programming. The futures are non-blocking
606             and support "suspend" and "resume" allowing them to be used in any asynchronous
607             operating environment.
608              
609             =cut
610              
611             =head1 INHERITS
612              
613             This package inherits behaviors from:
614              
615             L
616              
617             =cut
618              
619             =head1 INTEGRATES
620              
621             This package integrates behaviors from:
622              
623             L
624              
625             =cut
626              
627             =head1 METHODS
628              
629             This package provides the following methods:
630              
631             =cut
632              
633             =head2 catch
634              
635             catch(coderef $on_reject) (Venus::Future)
636              
637             The catch method registers a rejection handler and returns the future that
638             invokes the handlers.
639              
640             I>
641              
642             =over 4
643              
644             =item catch example 1
645              
646             # given: synopsis
647              
648             package main;
649              
650             my $catch = $future->catch(sub{
651             my ($issue) = @_;
652              
653             return $issue;
654             });
655              
656             # bless(..., "Venus::Future")
657              
658             # $catch->then(sub{...});
659              
660             # bless(..., "Venus::Future")
661              
662             =back
663              
664             =over 4
665              
666             =item catch example 2
667              
668             # given: synopsis
669              
670             package main;
671              
672             my $catch = $future->catch(sub{
673             my ($issue) = @_;
674              
675             return $issue;
676             });
677              
678             # bless(..., "Venus::Future")
679              
680             $future = $future;
681              
682             # bless(..., "Venus::Future")
683              
684             # $future->reject('Oops!');
685              
686             # bless(..., "Venus::Future")
687              
688             =back
689              
690             =cut
691              
692             =head2 finally
693              
694             finally(coderef $on_finally) (Venus::Future)
695              
696             The finally method registers a finally handler and returns the future that
697             invokes the handlers.
698              
699             I>
700              
701             =over 4
702              
703             =item finally example 1
704              
705             # given: synopsis
706              
707             package main;
708              
709             my $finally = $future->finally(sub{
710             my ($data) = @_;
711              
712             return $data;
713             });
714              
715             # bless(..., "Venus::Future")
716              
717             # $finally->then(sub{...});
718              
719             # bless(..., "Venus::Future")
720              
721             =back
722              
723             =over 4
724              
725             =item finally example 2
726              
727             # given: synopsis
728              
729             package main;
730              
731             $future->then(sub{
732             $_
733             });
734              
735             my $finally = $future->finally(sub{
736             my ($data) = @_;
737              
738             $future->{stash} = $data;
739              
740             return $data;
741             });
742              
743             # bless(..., "Venus::Future")
744              
745             $future = $future;
746              
747             # bless(..., "Venus::Future")
748              
749             # $future->resolve('Hello.');
750              
751             # bless(..., "Venus::Future")
752              
753             =back
754              
755             =over 4
756              
757             =item finally example 3
758              
759             # given: synopsis
760              
761             package main;
762              
763             $future->then(sub{
764             $_
765             });
766              
767             my $finally = $future->finally(sub{
768             my ($data) = @_;
769              
770             $future->{stash} = $data;
771              
772             return $data;
773             });
774              
775             # bless(..., "Venus::Future")
776              
777             $future = $future;
778              
779             # bless(..., "Venus::Future")
780              
781             # $future->reject('Oops!');
782              
783             # bless(..., "Venus::Future")
784              
785             =back
786              
787             =cut
788              
789             =head2 fulfill
790              
791             fulfill() (Venus::Future)
792              
793             The fulfill method attempts to fulfill the L by actuating it,
794             or resuming a previously actuated promise, and returns true if the future has
795             been resolved, i.e. the future is either L or L, and
796             otherwise returns false.
797              
798             I>
799              
800             =over 4
801              
802             =item fulfill example 1
803              
804             # given: synopsis
805              
806             package main;
807              
808             $future->promise(sub{
809             # resolve
810             $_[0]->result;
811             });
812              
813             my $fulfilled = $future->fulfill;
814              
815             # true
816              
817             =back
818              
819             =over 4
820              
821             =item fulfill example 2
822              
823             # given: synopsis
824              
825             package main;
826              
827             $future->promise(sub{
828             # resolve
829             $_[0]->result;
830             });
831              
832             $future->fulfill;
833              
834             my $result = $future;
835              
836             # bless(..., "Venus::Future")
837              
838             # $result->is_fulfilled;
839              
840             # true
841              
842             # $result->value;
843              
844             # undef
845              
846             =back
847              
848             =over 4
849              
850             =item fulfill example 3
851              
852             # given: synopsis
853              
854             package main;
855              
856             $future->promise(sub{
857             # resolve
858             $_[1]->result;
859             });
860              
861             my $fulfilled = $future->fulfill;
862              
863             # true
864              
865             =back
866              
867             =over 4
868              
869             =item fulfill example 4
870              
871             # given: synopsis
872              
873             package main;
874              
875             $future->promise(sub{
876             # resolve
877             $_[1]->result;
878             });
879              
880             $future->fulfill;
881              
882             my $result = $future;
883              
884             # bless(..., "Venus::Future")
885              
886             # $result->is_rejected;
887              
888             # true
889              
890             # $result->issue;
891              
892             # undef
893              
894             =back
895              
896             =over 4
897              
898             =item fulfill example 5
899              
900             # given: synopsis
901              
902             package main;
903              
904             $future->promise(sub{
905             # resolve
906             $_[0]->result(1);
907             })->then(sub{
908             return $future->{stash} = $_ * 2; # 2
909             })->then(sub{
910             return $future->{stash} = $_ * 2; # 4
911             })->then(sub{
912             return $future->{stash} = $_ * 2; # 8
913             });
914              
915             $future->fulfill;
916              
917             my $result = $future;
918              
919             # bless(..., "Venus::Future")
920              
921             # $result->is_fulfilled;
922              
923             # true
924              
925             # $result->value;
926              
927             # 1
928              
929             =back
930              
931             =over 4
932              
933             =item fulfill example 6
934              
935             # given: synopsis
936              
937             package main;
938              
939             $future->promise(sub{
940             # resolve
941             $_[0]->result(1);
942             });
943              
944             $future->then(sub{
945             return $future->{stash} = $_ * 2; # 2
946             });
947              
948             $future->then(sub{
949             return $future->{stash} = $_ * 2; # 2
950             });
951              
952             $future->then(sub{
953             return $future->{stash} = $_ * 2; # 2
954             });
955              
956             $future->fulfill;
957              
958             my $result = $future;
959              
960             # bless(..., "Venus::Future")
961              
962             # $result->is_fulfilled;
963              
964             # true
965              
966             # $result->value;
967              
968             # 1
969              
970             =back
971              
972             =over 4
973              
974             =item fulfill example 7
975              
976             # given: synopsis
977              
978             package main;
979              
980             my $pending_future = Venus::Future->new;
981              
982             $future->promise(sub{
983             # resolve
984             $_[0]->result(1);
985             })->then(sub{
986             return $_
987             })->then(sub{
988             return $pending_future;
989             })->then(sub{
990             return $_
991             });
992              
993             $future->fulfill;
994              
995             my @results = ($future, $pending_future);
996              
997             # my $result = $future;
998              
999             # bless(..., "Venus::Future")
1000              
1001             # $result->is_fulfilled;
1002              
1003             # false
1004              
1005             # $result->is_pending;
1006              
1007             # true
1008              
1009             # $result->value;
1010              
1011             # undef
1012              
1013             # $pending_future->resolve(0);
1014              
1015             # bless(..., "Venus::Future")
1016              
1017             # $pending_future->is_fulfilled;
1018              
1019             # true
1020              
1021             # $result->fulfill;
1022              
1023             # true
1024              
1025             # $result->is_fulfilled;
1026              
1027             # true
1028              
1029             =back
1030              
1031             =over 4
1032              
1033             =item fulfill example 8
1034              
1035             # given: synopsis
1036              
1037             package Thenable;
1038              
1039             use Venus::Class;
1040              
1041             sub then {
1042             my ($self, $resolve, $reject) = @_;
1043              
1044             $resolve->(100);
1045             }
1046              
1047             package main;
1048              
1049             my $thenable_object = Thenable->new;
1050              
1051             $future->promise(sub{
1052             # resolve
1053             $_[0]->result(1);
1054             })->then(sub{
1055             return $_
1056             })->then(sub{
1057             return $thenable_object;
1058             })->then(sub{
1059             return $future->{stash} = $_
1060             });
1061              
1062             $future->fulfill;
1063              
1064             my @results = ($future, $thenable_object);
1065              
1066             # my $result = $future;
1067              
1068             # bless(..., "Venus::Future")
1069              
1070             # $result->is_fulfilled;
1071              
1072             # true
1073              
1074             # $result->value;
1075              
1076             # 1
1077              
1078             =back
1079              
1080             =cut
1081              
1082             =head2 is
1083              
1084             is(string $name) (boolean)
1085              
1086             The is method take a name and dispatches to the corresponding C
1087             method and returns the result.
1088              
1089             I>
1090              
1091             =over 4
1092              
1093             =item is example 1
1094              
1095             # given: synopsis
1096              
1097             package main;
1098              
1099             $future->resolve;
1100              
1101             my $is_fulfilled = $future->is('fulfilled');
1102              
1103             # true
1104              
1105             =back
1106              
1107             =over 4
1108              
1109             =item is example 2
1110              
1111             # given: synopsis
1112              
1113             package main;
1114              
1115             my $is_pending = $future->is('pending');
1116              
1117             # true
1118              
1119             =back
1120              
1121             =over 4
1122              
1123             =item is example 3
1124              
1125             # given: synopsis
1126              
1127             package main;
1128              
1129             $future->reject;
1130              
1131             my $is_rejected = $future->is('rejected');
1132              
1133             # true
1134              
1135             =back
1136              
1137             =cut
1138              
1139             =head2 is_fulfilled
1140              
1141             is_fulfilled() (boolean)
1142              
1143             The is_fulfilled method returns true if the future has been fulfilled,
1144             otherwise returns false.
1145              
1146             I>
1147              
1148             =over 4
1149              
1150             =item is_fulfilled example 1
1151              
1152             # given: synopsis
1153              
1154             package main;
1155              
1156             my $is_fulfilled = $future->is_fulfilled;
1157              
1158             # false
1159              
1160             =back
1161              
1162             =over 4
1163              
1164             =item is_fulfilled example 2
1165              
1166             # given: synopsis
1167              
1168             package main;
1169              
1170             $future->resolve;
1171              
1172             my $is_fulfilled = $future->is_fulfilled;
1173              
1174             # true
1175              
1176             =back
1177              
1178             =over 4
1179              
1180             =item is_fulfilled example 3
1181              
1182             # given: synopsis
1183              
1184             package main;
1185              
1186             $future->reject;
1187              
1188             my $is_fulfilled = $future->is_fulfilled;
1189              
1190             # false
1191              
1192             =back
1193              
1194             =cut
1195              
1196             =head2 is_pending
1197              
1198             is_pending() (boolean)
1199              
1200             The is_pending method returns true if the future has remained pending,
1201             otherwise returns false.
1202              
1203             I>
1204              
1205             =over 4
1206              
1207             =item is_pending example 1
1208              
1209             # given: synopsis
1210              
1211             package main;
1212              
1213             my $is_pending = $future->is_pending;
1214              
1215             # true
1216              
1217             =back
1218              
1219             =over 4
1220              
1221             =item is_pending example 2
1222              
1223             # given: synopsis
1224              
1225             package main;
1226              
1227             $future->resolve;
1228              
1229             my $is_pending = $future->is_pending;
1230              
1231             # false
1232              
1233             =back
1234              
1235             =over 4
1236              
1237             =item is_pending example 3
1238              
1239             # given: synopsis
1240              
1241             package main;
1242              
1243             $future->reject;
1244              
1245             my $is_pending = $future->is_pending;
1246              
1247             # false
1248              
1249             =back
1250              
1251             =cut
1252              
1253             =head2 is_promised
1254              
1255             is_promised() (boolean)
1256              
1257             The is_promised method returns true if the future a registered promise,
1258             otherwise returns false.
1259              
1260             I>
1261              
1262             =over 4
1263              
1264             =item is_promised example 1
1265              
1266             # given: synopsis
1267              
1268             package main;
1269              
1270             my $is_promised = $future->is_promised;
1271              
1272             # false
1273              
1274             =back
1275              
1276             =over 4
1277              
1278             =item is_promised example 2
1279              
1280             # given: synopsis
1281              
1282             package main;
1283              
1284             $future->promise;
1285              
1286             my $is_promised = $future->is_promised;
1287              
1288             # false
1289              
1290             =back
1291              
1292             =over 4
1293              
1294             =item is_promised example 3
1295              
1296             # given: synopsis
1297              
1298             package main;
1299              
1300             $future->promise(sub{$_[0]->result});
1301              
1302             my $is_promised = $future->is_promised;
1303              
1304             # true
1305              
1306             =back
1307              
1308             =cut
1309              
1310             =head2 is_rejected
1311              
1312             is_rejected() (boolean)
1313              
1314             The is_rejected method returns true if the future has been rejected, otherwise
1315             returns false.
1316              
1317             I>
1318              
1319             =over 4
1320              
1321             =item is_rejected example 1
1322              
1323             # given: synopsis
1324              
1325             package main;
1326              
1327             my $is_rejected = $future->is_rejected;
1328              
1329             # false
1330              
1331             =back
1332              
1333             =over 4
1334              
1335             =item is_rejected example 2
1336              
1337             # given: synopsis
1338              
1339             package main;
1340              
1341             $future->resolve;
1342              
1343             my $is_rejected = $future->is_rejected;
1344              
1345             # false
1346              
1347             =back
1348              
1349             =over 4
1350              
1351             =item is_rejected example 3
1352              
1353             # given: synopsis
1354              
1355             package main;
1356              
1357             $future->reject;
1358              
1359             my $is_rejected = $future->is_rejected;
1360              
1361             # true
1362              
1363             =back
1364              
1365             =cut
1366              
1367             =head2 issue
1368              
1369             issue() (any)
1370              
1371             The issue method returns the result of the L operation once the future
1372             has been rejected.
1373              
1374             I>
1375              
1376             =over 4
1377              
1378             =item issue example 1
1379              
1380             # given: synopsis
1381              
1382             package main;
1383              
1384             my $issue = $future->issue;
1385              
1386             # undef
1387              
1388             # $future->is_pending
1389              
1390             # true
1391              
1392             =back
1393              
1394             =over 4
1395              
1396             =item issue example 2
1397              
1398             # given: synopsis
1399              
1400             package main;
1401              
1402             $future->reject(0);
1403              
1404             my $issue = $future->issue;
1405              
1406             # 0
1407              
1408             # $future->is_rejected
1409              
1410             # true
1411              
1412             =back
1413              
1414             =over 4
1415              
1416             =item issue example 3
1417              
1418             # given: synopsis
1419              
1420             package main;
1421              
1422             $future->reject({fail => 1});
1423              
1424             my $issue = $future->issue;
1425              
1426             # {fail => 1}
1427              
1428             # $future->is_rejected
1429              
1430             # true
1431              
1432             =back
1433              
1434             =cut
1435              
1436             =head2 new
1437              
1438             new(any @args) (Venus::Future)
1439              
1440             The new method instantiates this package and returns a new instance.
1441              
1442             I>
1443              
1444             =over 4
1445              
1446             =item new example 1
1447              
1448             package main;
1449              
1450             my $future = Venus::Future->new;
1451              
1452             # bless(..., "Venus::Future")
1453              
1454             =back
1455              
1456             =over 4
1457              
1458             =item new example 2
1459              
1460             package main;
1461              
1462             my $future = Venus::Future->new(sub{
1463             my ($resolve, $reject) = @_;
1464             $resolve->result('okay');
1465             });
1466              
1467             # bless(..., "Venus::Future")
1468              
1469             # $future->is('fulfilled');
1470              
1471             # true
1472              
1473             # $future->value;
1474              
1475             # 'okay'
1476              
1477             =back
1478              
1479             =over 4
1480              
1481             =item new example 3
1482              
1483             package main;
1484              
1485             my $future = Venus::Future->new(promise => sub{
1486             my ($resolve, $reject) = @_;
1487             $reject->result('boom');
1488             });
1489              
1490             # bless(..., "Venus::Future")
1491              
1492             # $future->is('rejected');
1493              
1494             # true
1495              
1496             # $future->issue;
1497              
1498             # 'boom'
1499              
1500             =back
1501              
1502             =cut
1503              
1504             =head2 promise
1505              
1506             promise(coderef $code) (Venus::Future)
1507              
1508             The promise method registers a callback executed by the L method,
1509             which is provided two arguments; the first argument being a L
1510             instance representing a C operaiton; the second argument being a
1511             L instance representing a C operaiton; and returns the
1512             invocant.
1513              
1514             I>
1515              
1516             =over 4
1517              
1518             =item promise example 1
1519              
1520             # given: synopsis
1521              
1522             package main;
1523              
1524             $future = $future->promise(sub{
1525             my ($resolve, $reject) = @_;
1526              
1527             $resolve->result('pass');
1528             });
1529              
1530             # bless(..., "Venus::Future")
1531              
1532             # $future->fulfill;
1533              
1534             # true
1535              
1536             =back
1537              
1538             =over 4
1539              
1540             =item promise example 2
1541              
1542             # given: synopsis
1543              
1544             package main;
1545              
1546             $future = $future->promise(sub{
1547             my ($resolve, $reject) = @_;
1548              
1549             $reject->result('fail');
1550             });
1551              
1552             # bless(..., "Venus::Future")
1553              
1554             # $future->fulfill;
1555              
1556             # true
1557              
1558             =back
1559              
1560             =cut
1561              
1562             =head2 reject
1563              
1564             reject(any $issue) (Venus::Future)
1565              
1566             The reject method cascades a rejection operation causes the future to be
1567             rejected, and returns the invocant.
1568              
1569             I>
1570              
1571             =over 4
1572              
1573             =item reject example 1
1574              
1575             # given: synopsis
1576              
1577             package main;
1578              
1579             my $rejected = $future->reject;
1580              
1581             # bless(..., "Venus::Future")
1582              
1583             # $rejected->status
1584              
1585             # "rejected"
1586              
1587             # $rejected->issue
1588              
1589             # undef
1590              
1591             =back
1592              
1593             =over 4
1594              
1595             =item reject example 2
1596              
1597             # given: synopsis
1598              
1599             package main;
1600              
1601             my $rejected = $future->reject('Oops!');
1602              
1603             # bless(..., "Venus::Future")
1604              
1605             # $rejected->status
1606              
1607             # "rejected"
1608              
1609             # $rejected->issue
1610              
1611             # "Oops!"
1612              
1613             =back
1614              
1615             =cut
1616              
1617             =head2 resolve
1618              
1619             resolve(any $value) (Venus::Future)
1620              
1621             The resolve method cascades a rejection operation causes the future to be
1622             rejected, and returns the invocant.
1623              
1624             I>
1625              
1626             =over 4
1627              
1628             =item resolve example 1
1629              
1630             # given: synopsis
1631              
1632             package main;
1633              
1634             my $fulfilled = $future->resolve;
1635              
1636             # bless(..., "Venus::Future")
1637              
1638             # $fulfilled->status
1639              
1640             # "fulfilled"
1641              
1642             # $fulfilled->value
1643              
1644             # undef
1645              
1646             =back
1647              
1648             =over 4
1649              
1650             =item resolve example 2
1651              
1652             # given: synopsis
1653              
1654             package main;
1655              
1656             my $fulfilled = $future->resolve('Great!');
1657              
1658             # bless(..., "Venus::Future")
1659              
1660             # $fulfilled->status
1661              
1662             # "fulfilled"
1663              
1664             # $fulfilled->value
1665              
1666             # "Great!"
1667              
1668             =back
1669              
1670             =cut
1671              
1672             =head2 status
1673              
1674             status() (any)
1675              
1676             The status method returns the status of the future. Valid statuses are
1677             C, C, and C.
1678              
1679             I>
1680              
1681             =over 4
1682              
1683             =item status example 1
1684              
1685             # given: synopsis
1686              
1687             package main;
1688              
1689             my $status = $future->status;
1690              
1691             # "pending"
1692              
1693             =back
1694              
1695             =over 4
1696              
1697             =item status example 2
1698              
1699             # given: synopsis
1700              
1701             package main;
1702              
1703             $future->resolve(0);
1704              
1705             my $status = $future->status;
1706              
1707             # "fulfilled"
1708              
1709             =back
1710              
1711             =over 4
1712              
1713             =item status example 3
1714              
1715             # given: synopsis
1716              
1717             package main;
1718              
1719             $future->reject(0);
1720              
1721             my $status = $future->status;
1722              
1723             # "rejected"
1724              
1725             =back
1726              
1727             =cut
1728              
1729             =head2 then
1730              
1731             then(coderef $fulfill, coderef $reject) (Venus::Future)
1732              
1733             The then method registers fulfillment and rejection handlers and returns the
1734             future that invokes the handlers.
1735              
1736             I>
1737              
1738             =over 4
1739              
1740             =item then example 1
1741              
1742             # given: synopsis
1743              
1744             package main;
1745              
1746             my $new_future = $future->then(sub{
1747             # fulfillment handler
1748             $_
1749             });
1750              
1751             # "Venus::Future"
1752              
1753             # $new_future->is_pending;
1754              
1755             # true
1756              
1757             =back
1758              
1759             =over 4
1760              
1761             =item then example 2
1762              
1763             # given: synopsis
1764              
1765             package main;
1766              
1767             my $new_future = $future->then(sub{
1768             # fulfillment handler
1769             $_
1770             },
1771             sub{
1772             # rejection handler
1773             $_
1774             });
1775              
1776             # "Venus::Future"
1777              
1778             # $new_future->is_pending;
1779              
1780             # true
1781              
1782             =back
1783              
1784             =over 4
1785              
1786             =item then example 3
1787              
1788             # given: synopsis
1789              
1790             package main;
1791              
1792             my $new_future = $future->then(undef, sub{
1793             # rejection handler
1794             $_
1795             });
1796              
1797             # "Venus::Future"
1798              
1799             # $new_future->is_pending;
1800              
1801             # true
1802              
1803             =back
1804              
1805             =over 4
1806              
1807             =item then example 4
1808              
1809             # given: synopsis
1810              
1811             package main;
1812              
1813             my $new_future = $future->then(sub{
1814             # fulfillment handler
1815             $_
1816             });
1817              
1818             # "Venus::Future"
1819              
1820             # $new_future->is_pending;
1821              
1822             # true
1823              
1824             $future = $future;
1825              
1826             # "Venus::Future"
1827              
1828             # $new_future->is_pending;
1829              
1830             # true
1831              
1832             =back
1833              
1834             =over 4
1835              
1836             =item then example 5
1837              
1838             # given: synopsis
1839              
1840             package main;
1841              
1842             my $new_future = $future->then(sub{
1843             # fulfillment handler
1844             $_
1845             },
1846             sub{
1847             # rejection handler
1848             $_
1849             });
1850              
1851             # "Venus::Future"
1852              
1853             # $new_future->is_pending;
1854              
1855             # true
1856              
1857             $future = $future;
1858              
1859             # "Venus::Future"
1860              
1861             # $new_future->is_pending;
1862              
1863             # true
1864              
1865             =back
1866              
1867             =over 4
1868              
1869             =item then example 6
1870              
1871             # given: synopsis
1872              
1873             package main;
1874              
1875             my $new_future = $future->then(undef, sub{
1876             # rejection handler
1877             $_
1878             });
1879              
1880             # "Venus::Future"
1881              
1882             # $new_future->is_pending;
1883              
1884             # true
1885              
1886             $future = $future;
1887              
1888             # "Venus::Future"
1889              
1890             # $new_future->is_pending;
1891              
1892             # true
1893              
1894             =back
1895              
1896             =cut
1897              
1898             =head2 value
1899              
1900             value() (any)
1901              
1902             The value method returns the result of the L operation once the
1903             future has been fulfilled.
1904              
1905             I>
1906              
1907             =over 4
1908              
1909             =item value example 1
1910              
1911             # given: synopsis
1912              
1913             package main;
1914              
1915             my $value = $future->value;
1916              
1917             # undef
1918              
1919             # $future->is_pending
1920              
1921             # true
1922              
1923             =back
1924              
1925             =over 4
1926              
1927             =item value example 2
1928              
1929             # given: synopsis
1930              
1931             package main;
1932              
1933             $future->resolve(1);
1934              
1935             my $value = $future->value;
1936              
1937             # 1
1938              
1939             # $future->is_fulfilled
1940              
1941             # true
1942              
1943             =back
1944              
1945             =over 4
1946              
1947             =item value example 3
1948              
1949             # given: synopsis
1950              
1951             package main;
1952              
1953             $future->resolve({pass => 1});
1954              
1955             my $value = $future->value;
1956              
1957             # {pass => 1}
1958              
1959             # $future->is_fulfilled
1960              
1961             # true
1962              
1963             =back
1964              
1965             =cut
1966              
1967             =head2 wait
1968              
1969             wait(number $timeout) (Venus::Future)
1970              
1971             The wait method blocks the execution of the current process until a value is
1972             received. If a timeout is provided, execution will be blocked until a value is
1973             received or the wait time expires. If a timeout of C<0> is provided, execution
1974             will not be blocked. If no timeout is provided at all, execution will block
1975             indefinitely.
1976              
1977             I>
1978              
1979             =over 4
1980              
1981             =item wait example 1
1982              
1983             # given: synopsis
1984              
1985             package main;
1986              
1987             $future->promise(sub{
1988             # resolve
1989             $_[0]->result;
1990             });
1991              
1992             $future = $future->wait(0);
1993              
1994             # bless(..., "Venus::Future")
1995              
1996             # $future->is_fulfilled;
1997              
1998             # true
1999              
2000             =back
2001              
2002             =over 4
2003              
2004             =item wait example 2
2005              
2006             # given: synopsis
2007              
2008             package main;
2009              
2010             $future->promise(sub{
2011             # never fulfilled
2012             });
2013              
2014             $future->wait(1);
2015              
2016             # Exception! (isa Venus::Future::Error) (see error_on_timeout)
2017              
2018             =back
2019              
2020             =cut
2021              
2022             =head1 ERRORS
2023              
2024             This package may raise the following errors:
2025              
2026             =cut
2027              
2028             =over 4
2029              
2030             =item error: C
2031              
2032             This package may raise an error_on_timeout exception.
2033              
2034             B
2035              
2036             # given: synopsis;
2037              
2038             my $input = {
2039             throw => 'error_on_timeout',
2040             timeout => 10,
2041             };
2042              
2043             my $error = $future->try('error', $input)->error->result;
2044              
2045             # my $name = $error->name;
2046              
2047             # "on_timeout"
2048              
2049             # my $message = $error->render;
2050              
2051             # "Future timed-out after 10 seconds"
2052              
2053             # my $timeout = $error->stash('timeout');
2054              
2055             # 10
2056              
2057             =back
2058              
2059             =head1 AUTHORS
2060              
2061             Awncorp, C
2062              
2063             =cut
2064              
2065             =head1 LICENSE
2066              
2067             Copyright (C) 2000, Awncorp, C.
2068              
2069             This program is free software, you can redistribute it and/or modify it under
2070             the terms of the Apache license version 2.0.
2071              
2072             =cut