1
0
mirror of https://github.com/danog/amp.git synced 2024-11-26 20:15:00 +01:00

Accept React promises in rethrow, wait, timeout, pipe, and capture

Fixes #75.
This commit is contained in:
Aaron Piotrowski 2017-03-12 23:27:43 -05:00 committed by Niklas Keller
parent 8b7fb9ece3
commit f187d4b31a
6 changed files with 176 additions and 11 deletions

View File

@ -91,9 +91,19 @@ function call(callable $functor, ...$args): Promise {
/**
* Registers a callback that will forward the failure reason to the Loop error handler if the promise fails.
*
* @param \Amp\Promise $promise
* @param \Amp\Promise|\React\Promise\PromiseInterface $promise
*
* @throws \TypeError If $promise is not an instance of \Amp\Promise or \React\Promise\PromiseInterface.
*/
function rethrow(Promise $promise) {
function rethrow($promise) {
if (!$promise instanceof Promise) {
if ($promise instanceof ReactPromise) {
$promise = adapt($promise);
} else {
throw new \TypeError("Must provide an instance of %s or %s", Promise::class, ReactPromise::class);
}
}
$promise->when(function ($exception) {
if ($exception) {
throw $exception;
@ -104,13 +114,22 @@ function rethrow(Promise $promise) {
/**
* Runs the event loop until the promise is resolved. Should not be called within a running event loop.
*
* @param \Amp\Promise $promise
* @param \Amp\Promise|\React\Promise\PromiseInterface $promise
*
* @return mixed Promise success value.
*
* @throws \TypeError If $promise is not an instance of \Amp\Promise or \React\Promise\PromiseInterface.
* @throws \Throwable Promise failure reason.
*/
function wait(Promise $promise) {
function wait($promise) {
if (!$promise instanceof Promise) {
if ($promise instanceof ReactPromise) {
$promise = adapt($promise);
} else {
throw new \TypeError("Must provide an instance of %s or %s", Promise::class, ReactPromise::class);
}
}
$resolved = false;
Loop::run(function () use (&$resolved, &$value, &$exception, $promise) {
$promise->when(function ($e, $v) use (&$resolved, &$value, &$exception) {
@ -135,12 +154,22 @@ function wait(Promise $promise) {
/**
* Pipe the promised value through the specified functor once it resolves.
*
* @param \Amp\Promise $promise
* @param \Amp\Promise|\React\Promise\PromiseInterface $promise
* @param callable(mixed $value): mixed $functor
*
* @return \Amp\Promise
*
* @throws \TypeError If $promise is not an instance of \Amp\Promise or \React\Promise\PromiseInterface.
*/
function pipe(Promise $promise, callable $functor): Promise {
function pipe($promise, callable $functor): Promise {
if (!$promise instanceof Promise) {
if ($promise instanceof ReactPromise) {
$promise = adapt($promise);
} else {
throw new \TypeError("Must provide an instance of %s or %s", Promise::class, ReactPromise::class);
}
}
$deferred = new Deferred;
$promise->when(function ($exception, $value) use ($deferred, $functor) {
@ -160,14 +189,24 @@ function pipe(Promise $promise, callable $functor): Promise {
}
/**
* @param \Amp\Promise $promise
* @param \Amp\Promise|\React\Promise\PromiseInterface $promise
* @param string $className Exception class name to capture. Given callback will only be invoked if the failure reason
* is an instance of the given exception class name.
* @param callable(\Throwable $exception): mixed $functor
*
* @return \Amp\Promise
*
* @throws \TypeError If $promise is not an instance of \Amp\Promise or \React\Promise\PromiseInterface.
*/
function capture(Promise $promise, string $className, callable $functor): Promise {
function capture($promise, string $className, callable $functor): Promise {
if (!$promise instanceof Promise) {
if ($promise instanceof ReactPromise) {
$promise = adapt($promise);
} else {
throw new \TypeError("Must provide an instance of %s or %s", Promise::class, ReactPromise::class);
}
}
$deferred = new Deferred;
$promise->when(function ($exception, $value) use ($deferred, $className, $functor) {
@ -197,12 +236,22 @@ function capture(Promise $promise, string $className, callable $functor): Promis
* If the timeout expires before the promise is resolved, the returned promise fails with an instance of
* \Amp\TimeoutException.
*
* @param \Amp\Promise $promise
* @param \Amp\Promise|\React\Promise\PromiseInterface $promise
* @param int $timeout Timeout in milliseconds.
*
* @return \Amp\Promise
*
* @throws \TypeError If $promise is not an instance of \Amp\Promise or \React\Promise\PromiseInterface.
*/
function timeout(Promise $promise, int $timeout): Promise {
function timeout($promise, int $timeout): Promise {
if (!$promise instanceof Promise) {
if ($promise instanceof ReactPromise) {
$promise = adapt($promise);
} else {
throw new \TypeError("Must provide an instance of %s or %s", Promise::class, ReactPromise::class);
}
}
$deferred = new Deferred;
$resolved = false;

View File

@ -6,6 +6,7 @@ use Amp;
use Amp\Failure;
use Amp\Success;
use Amp\Promise;
use function React\Promise\reject;
class CaptureTest extends \PHPUnit\Framework\TestCase {
public function testSuccessfulPromise() {
@ -110,4 +111,33 @@ class CaptureTest extends \PHPUnit\Framework\TestCase {
$this->assertFalse($invoked);
$this->assertSame($exception, $reason);
}
/**
* @depends testFailedPromise
*/
public function testReactPromise() {
$invoked = false;
$callback = function ($exception) use (&$invoked, &$reason) {
$invoked = true;
$reason = $exception;
return -1;
};
$exception = new \Exception;
$promise = reject($exception);
$promise = Amp\capture($promise, \Exception::class, $callback);
$this->assertInstanceOf(Promise::class, $promise);
$callback = function ($exception, $value) use (&$result) {
$result = $value;
};
$promise->when($callback);
$this->assertTrue($invoked);
$this->assertSame($exception, $reason);
$this->assertSame(-1, $result);
}
}

View File

@ -6,6 +6,7 @@ use Amp;
use Amp\Failure;
use Amp\Success;
use Amp\Promise;
use function React\Promise\resolve;
class PipeTest extends \PHPUnit\Framework\TestCase {
public function testSuccessfulPromise() {
@ -81,4 +82,31 @@ class PipeTest extends \PHPUnit\Framework\TestCase {
$this->assertTrue($invoked);
$this->assertSame($exception, $reason);
}
/**
* @depends testSuccessfulPromise
*/
public function testReactPromise() {
$invoked = false;
$callback = function ($value) use (&$invoked) {
$invoked = true;
return $value + 1;
};
$value = 1;
$promise = resolve($value);
$promise = Amp\pipe($promise, $callback);
$this->assertInstanceOf(Promise::class, $promise);
$callback = function ($exception, $value) use (&$result) {
$result = $value;
};
$promise->when($callback);
$this->assertTrue($invoked);
$this->assertSame($value + 1, $result);
}
}

View File

@ -6,9 +6,10 @@ use Amp;
use Amp\Failure;
use Amp\Loop;
use PHPUnit\Framework\TestCase;
use function React\Promise\reject;
class RethrowTest extends TestCase {
public function testWaitOnPendingPromise() {
public function testRethrow() {
$exception = new \Exception;
try {
@ -24,4 +25,24 @@ class RethrowTest extends TestCase {
$this->fail('Failed promise reason should be thrown from loop');
}
/**
* @depends testRethrow
*/
public function testReactPromise() {
$exception = new \Exception;
try {
Loop::run(function () use ($exception) {
$promise = reject($exception);
Amp\rethrow($promise);
});
} catch (\Exception $reason) {
$this->assertSame($exception, $reason);
return;
}
$this->fail('Failed promise reason should be thrown from loop');
}
}

View File

@ -8,6 +8,7 @@ use Amp\Loop;
use Amp\Pause;
use Amp\Success;
use Amp\Promise;
use function React\Promise\resolve;
class TimeoutTest extends \PHPUnit\Framework\TestCase {
public function testSuccessfulPromise() {
@ -89,4 +90,26 @@ class TimeoutTest extends \PHPUnit\Framework\TestCase {
$this->assertInstanceOf(Amp\TimeoutException::class, $reason);
}
/**
* @depends testSuccessfulPromise
*/
public function testReactPromise() {
Loop::run(function () {
$value = 1;
$promise = resolve($value);
$promise = Amp\timeout($promise, 100);
$this->assertInstanceOf(Promise::class, $promise);
$callback = function ($exception, $value) use (&$result) {
$result = $value;
};
$promise->when($callback);
$this->assertSame($value, $result);
});
}
}

View File

@ -8,6 +8,7 @@ use Amp\Failure;
use Amp\Pause;
use Amp\Success;
use Amp\Loop;
use function React\Promise\resolve;
class WaitTest extends \PHPUnit\Framework\TestCase {
public function testWaitOnSuccessfulPromise() {
@ -59,4 +60,17 @@ class WaitTest extends \PHPUnit\Framework\TestCase {
$result = Amp\wait($promise->promise());
}
/**
* @depends testWaitOnSuccessfulPromise
*/
public function testReactPromise() {
$value = 1;
$promise = resolve($value);
$result = Amp\wait($promise);
$this->assertSame($value, $result);
}
}