await_all shouldn't short circuit on an exception
[scpubgit/Object-Remote.git] / lib / Object / Remote / Future.pm
index 2fe171b..609799a 100644 (file)
@@ -6,7 +6,7 @@ use base qw(Exporter);
 
 use CPS::Future;
 
-our @EXPORT = qw(future await_future);
+our @EXPORT = qw(future await_future await_all);
 
 sub future (&) {
   my $f = $_[0]->(CPS::Future->new);
@@ -24,14 +24,16 @@ sub await_future {
   return wantarray ? $f->get : ($f->get)[0];
 }
 
+sub await_all {
+  await_future(CPS::Future->wait_all(@_));
+  map $_->get, @_;
+}
+
 package start;
 
 sub AUTOLOAD {
   my $invocant = shift;
-  my ($method) = our $AUTOLOAD =~ /([^:]+)$/;
-  if (ref($invocant) eq 'ARRAY') {
-    return [ map $_->${\"start::${method}"}, @$invocant ];
-  }
+  my ($method) = our $AUTOLOAD =~ /^start::(.+)$/;
   my $res;
   unless (eval { $res = $invocant->$method(@_); 1 }) {
     my $f = CPS::Future->new;
@@ -46,15 +48,42 @@ sub AUTOLOAD {
   return $res;
 }
 
-package await;
+package maybe::start;
 
 sub AUTOLOAD {
   my $invocant = shift;
-  my ($method) = our $AUTOLOAD =~ /([^:]+)$/;
-  my @invocants = (ref($invocant) eq 'ARRAY' ? @$invocant : $invocant);
-  my @futures = map $_->${\"start::${method}"}, @$invocant;
-  Object::Remote::Future::await_future(CPS::Future->needs_all(@futures));
-  return map $_->get, @futures;
+  my ($method) = our $AUTOLOAD =~ /^maybe::start::(.+)$/;
+  $method = "start::${method}" if ((caller(1)||'') eq 'start');
+  $invocant->$method(@_);
+}
+
+package then;
+
+sub AUTOLOAD {
+  my $invocant = shift;
+  my ($method) = our $AUTOLOAD =~ /^then::(.+)$/;
+  my @args = @_;
+  # Need two copies since if we're called on an already complete future
+  # $f will be freed immediately
+  my $ret = my $f = CPS::Future->new;
+  $invocant->on_fail(sub { $f->fail(@_); undef($f); });
+  $invocant->on_done(sub {
+    my ($obj) = @_;
+    my $next = $obj->${\"start::${method}"}(@args);
+    $next->on_done(sub { $f->done(@_); undef($f); });
+    $next->on_fail(sub { $f->fail(@_); undef($f); });
+  });
+  return $ret;
 }
 
 1;
+
+=head1 NAME
+
+Object::Remote::Future - Asynchronous calling for L<Object::Remote>
+
+=head1 LAME
+
+Shipping prioritised over writing this part up. Blame mst.
+
+=cut