Skip to content

Commit

Permalink
Merge pull request #49 from e-zannelli/feat/typing
Browse files Browse the repository at this point in the history
Generic promise
  • Loading branch information
e-zannelli authored Dec 6, 2021
2 parents 03b5ede + e77743c commit 2c207f6
Show file tree
Hide file tree
Showing 7 changed files with 41 additions and 7 deletions.
2 changes: 2 additions & 0 deletions src/Adapter/Tornado/EventLoop.php
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,8 @@ public function delay(int $milliseconds): Promise
while (microtime(true) < $endTime) {
yield $this->idle();
}

return null;
})());
}

Expand Down
33 changes: 29 additions & 4 deletions src/EventLoop.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,23 @@ interface EventLoop
* Waits the resolution of a promise, and returns its value.
* You should use this function once for your global result.
*
* @return mixed
* @template T
*
* @param Promise<T> $promise
*
* @return T
*/
public function wait(Promise $promise);

/**
* Registers a generator in the event loop to execute it asynchronously.
* The returned promise will be resolved with the value returned by the generator.
*
* @template T
*
* @param \Generator<int, Promise, mixed, T> $generator
*
* @return Promise<T>
*/
public function async(\Generator $generator): Promise;

Expand All @@ -28,8 +38,11 @@ public function promiseAll(Promise ...$promises): Promise;
* $function applied to each elements of input traversable.
* You should use this function each time that you use yield in a foreach loop.
*
* @param \Traversable|array $traversable Input elements
* @param callable $function must return a generator from an input value, and an optional key
* @template TKey of array-key
* @template TValue
*
* @param \Traversable<TKey, TValue>|array<TKey, TValue> $traversable Input elements
* @param callable(TValue, TKey): \Generator<int, Promise, mixed, mixed> $function
*/
public function promiseForeach($traversable, callable $function): Promise;

Expand All @@ -41,7 +54,11 @@ public function promiseRace(Promise ...$promises): Promise;
/**
* Creates a promise already resolved with $value.
*
* @param mixed $value
* @template T
*
* @param T $value
*
* @return Promise<T>
*/
public function promiseFulfilled($value): Promise;

Expand All @@ -52,13 +69,17 @@ public function promiseRejected(\Throwable $throwable): Promise;

/**
* Creates a promise that will be resolved to null in a future tick of the event loop.
*
* @return Promise<null>
*/
public function idle(): Promise;

/**
* Creates a promise that will be resolved to null after a fixed time.
* ⚠️ The actual measured delay can be greater if your event loop is busy!
* It also can be a little smaller, depending on your event loop (or system clock) accuracy.
*
* @return Promise<null>
*/
public function delay(int $milliseconds): Promise;

Expand All @@ -72,6 +93,8 @@ public function deferred(): Deferred;
* ⚠️ Error handling (stream connection closed for example) might differ between implementations.
*
* @param resource $stream
*
* @return Promise<resource>
*/
public function readable($stream): Promise;

Expand All @@ -80,6 +103,8 @@ public function readable($stream): Promise;
* ⚠️ Error handling (stream connection closed for example) might differ between implementations.
*
* @param resource $stream
*
* @return Promise<resource>
*/
public function writable($stream): Promise;
}
3 changes: 3 additions & 0 deletions src/HttpClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
namespace M6Web\Tornado;

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

interface HttpClient
{
/**
* Sends a http request and returns a promise that will be resolved with a
* Psr\Http\Message\ResponseInterface
*
* @return Promise<ResponseInterface>
*/
public function sendRequest(RequestInterface $request): Promise;
}
3 changes: 3 additions & 0 deletions src/Promise.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

/**
* To resolve the value of a promise, you have to yield it from a generator registered in the event loop.
*
* @template-covariant TValue
* @psalm-yield TValue
*/
interface Promise
{
Expand Down
3 changes: 0 additions & 3 deletions tests/Adapter/Guzzle/GuzzleMockWrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ final class GuzzleMockWrapper implements GuzzleClientWrapper
/** @var \GuzzleHttp\Client */
private $guzzleClient;

/** @var array */
private $transactions = [];

/** @var int */
public $ticks;

Expand Down
3 changes: 3 additions & 0 deletions tests/EventLoopTest/AsyncTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public function testYieldingInvalidValueMayThrowAnError(): void
};

$eventLoop = $this->createEventLoop();
/** @phpstan-ignore-next-line phpstan detects the generator yields a non-promise */
$promise = $eventLoop->async($createGenerator());

$this->expectException(\Error::class);
Expand Down Expand Up @@ -245,6 +246,8 @@ public function testEventLoopShouldNotThrowInCaseOfExplicitlyRejectedPromise():
$generatorWaitALittle = function () use ($eventLoop) {
yield $eventLoop->idle();
yield $eventLoop->idle();

return null;
};

$unwatchedRejectedPromise = $eventLoop->promiseRejected(new \Exception('Rejected Promise'));
Expand Down
1 change: 1 addition & 0 deletions tests/EventLoopTest/PromiseForeachTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public function testPromiseForeachShouldThrowIfCallbackDoesNotReturnGenerator():

$this->expectException(\TypeError::class);
$eventLoop->wait(
/* @phpstan-ignore-next-line phpstan detects the callback is invalid */
$eventLoop->promiseForeach([1], $callback)
);
}
Expand Down

0 comments on commit 2c207f6

Please sign in to comment.