diff --git a/composer.json b/composer.json index 0b2b879..b8f959d 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "require": { "php": "^8.2", "react/event-loop": "^1.4", - "react/promise": "^2.10" + "react/promise": "^2.10 || ^3.0" }, "require-dev": { "wyrihaximus/async-test-utilities": "^7.2.0" diff --git a/composer.lock b/composer.lock index d936764..0c21e54 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "1e823742f5e565460c6395ed3cb7ac6b", + "content-hash": "4294ec29777cbc96c06276fe2ac489a0", "packages": [ { "name": "react/event-loop", @@ -80,23 +80,24 @@ }, { "name": "react/promise", - "version": "v2.10.0", + "version": "v3.0.0", "source": { "type": "git", "url": "https://github.com/reactphp/promise.git", - "reference": "f913fb8cceba1e6644b7b90c4bfb678ed8a3ef38" + "reference": "c86753c76fd3be465d93b308f18d189f01a22be4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise/zipball/f913fb8cceba1e6644b7b90c4bfb678ed8a3ef38", - "reference": "f913fb8cceba1e6644b7b90c4bfb678ed8a3ef38", + "url": "https://api.github.com/repos/reactphp/promise/zipball/c86753c76fd3be465d93b308f18d189f01a22be4", + "reference": "c86753c76fd3be465d93b308f18d189f01a22be4", "shasum": "" }, "require": { - "php": ">=5.4.0" + "php": ">=7.1.0" }, "require-dev": { - "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.36" + "phpstan/phpstan": "1.10.20 || 1.4.10", + "phpunit/phpunit": "^9.5 || ^7.5" }, "type": "library", "autoload": { @@ -140,7 +141,7 @@ ], "support": { "issues": "https://github.com/reactphp/promise/issues", - "source": "https://github.com/reactphp/promise/tree/v2.10.0" + "source": "https://github.com/reactphp/promise/tree/v3.0.0" }, "funding": [ { @@ -148,7 +149,7 @@ "type": "open_collective" } ], - "time": "2023-05-02T15:15:43+00:00" + "time": "2023-07-11T16:12:49+00:00" } ], "packages-dev": [ @@ -10206,5 +10207,5 @@ "platform-overrides": { "php": "8.2.13" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/src/functions.php b/src/functions.php index ee2d61e..c081f84 100644 --- a/src/functions.php +++ b/src/functions.php @@ -7,18 +7,20 @@ use React\EventLoop\Loop; use React\EventLoop\TimerInterface; use React\Promise\Deferred; -use React\Promise\Promise; use React\Promise\PromiseInterface; /** - * Promise that resolves once future tick is called. + * @param T $value Value to return on resolve. * - * @param mixed $value Value to return on resolve. + * @return PromiseInterface * + * @template T + * Promise that resolves once future tick is called. * @phpstan-ignore-next-line */ function futurePromise(mixed $value = null): PromiseInterface { + /** @var Deferred $deferred */ $deferred = new Deferred(); Loop::futureTick(static function () use ($deferred, $value): void { $deferred->resolve($value); @@ -31,12 +33,16 @@ function futurePromise(mixed $value = null): PromiseInterface * Promise that resolves after $interval has passed. * * @param float $interval The number of seconds to wait before execution. - * @param mixed $value Value to return on resolve. + * @param T $value Value to return on resolve. * + * @return PromiseInterface + * + * @template T * @phpstan-ignore-next-line */ function timedPromise(float $interval, mixed $value = null): PromiseInterface { + /** @var Deferred $deferred */ $deferred = new Deferred(); Loop::addTimer($interval, static function () use ($deferred, $value): void { $deferred->resolve($value); @@ -50,12 +56,16 @@ function timedPromise(float $interval, mixed $value = null): PromiseInterface * * @param float $interval The number of seconds between each interval to run $check. * @param callable(mixed): (false|mixed) $check Callable to run at the specified $interval. - * @param mixed $value Value to pass into $check on tick. + * @param T $value Value to pass into $check on tick. + * + * @return PromiseInterface * + * @template T * @phpstan-ignore-next-line */ function tickingPromise(float $interval, callable $check, mixed $value = null): PromiseInterface { + /** @var Deferred $deferred */ $deferred = new Deferred(); Loop::addPeriodicTimer($interval, static function (TimerInterface $timer) use ($deferred, $check, $value): void { /** @psalm-suppress MixedAssignment */ @@ -75,38 +85,47 @@ function tickingPromise(float $interval, callable $check, mixed $value = null): * Promise that resolves once $check returns something other then false. Runs at future tick interval. * * @param callable $check Callable to run at tick. - * @param mixed $value Value to pass into $check on tick. + * @param T $value Value to pass into $check on tick. * @param int $iterations Number of iterations to call $check in one tick. * + * @return PromiseInterface + * + * @template T * @phpstan-ignore-next-line */ function tickingFuturePromise(callable $check, mixed $value = null, int $iterations = 1): PromiseInterface { - return new Promise(static function (callable $resolve) use ($check, $iterations, $value): void { - $runCheck = static function () use ($check, &$runCheck, $resolve, $iterations, $value): void { - for ($i = 0; $i <= $iterations; $i++) { - $result = $check($value); - if ($result !== false) { - $runCheck = null; - $resolve($result); - - return; - } - } + /** @var Deferred $deferred */ + $deferred = new Deferred(); + $runCheck = static function () use ($check, &$runCheck, $deferred, $iterations, $value): void { + for ($i = 0; $i <= $iterations; $i++) { + $result = $check($value); + if ($result !== false) { + $runCheck = null; + $deferred->resolve($result); - /** @psalm-suppress MixedArgument */ - futurePromise()->then($runCheck); - }; + return; + } + } + /** @psalm-suppress MixedArgument */ futurePromise()->then($runCheck); - }); + }; + + futurePromise()->then($runCheck); + + return $deferred->promise(); } /** * Sandwich a $function call within two futureTicks. * - * @param mixed $value Value to pass into $function. + * @param T $value Value to pass into $function. * @param callable $function Function to wrap. + * + * @return PromiseInterface + * + * @template T */ function futureFunctionPromise(mixed $value, callable $function): PromiseInterface { diff --git a/tests/Types.php b/tests/Types.php new file mode 100644 index 0000000..4109742 --- /dev/null +++ b/tests/Types.php @@ -0,0 +1,29 @@ +', futurePromise(true)); +assertType('React\Promise\PromiseInterface', futurePromise()); + +assertType('React\Promise\PromiseInterface', timedPromise(1, true)); +assertType('React\Promise\PromiseInterface', timedPromise(1)); + +assertType('React\Promise\PromiseInterface', tickingPromise(1, static function (): void { +}, true)); +assertType('React\Promise\PromiseInterface', tickingPromise(1, static function (): void { +})); + +assertType('React\Promise\PromiseInterface', tickingFuturePromise(static function (): void { +}, true)); +assertType('React\Promise\PromiseInterface', tickingFuturePromise(static function (): void { +})); + +assertType('React\Promise\PromiseInterface', futureFunctionPromise(true, static function (): void { +}));