From 4ce65d59ca91871cfd126497158200a818720bce Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 13 Apr 2024 13:30:08 +0200 Subject: Adding upstream version 0.13.1. Signed-off-by: Daniel Baumann --- vendor/react/promise/LICENSE | 24 ++ vendor/react/promise/composer.json | 48 +++ .../promise/src/CancellablePromiseInterface.php | 17 + vendor/react/promise/src/CancellationQueue.php | 55 +++ vendor/react/promise/src/Deferred.php | 65 ++++ .../promise/src/Exception/LengthException.php | 7 + .../react/promise/src/ExtendedPromiseInterface.php | 98 +++++ vendor/react/promise/src/FulfilledPromise.php | 71 ++++ vendor/react/promise/src/LazyPromise.php | 66 ++++ vendor/react/promise/src/Promise.php | 256 +++++++++++++ vendor/react/promise/src/PromiseInterface.php | 41 ++ vendor/react/promise/src/PromisorInterface.php | 13 + vendor/react/promise/src/RejectedPromise.php | 79 ++++ .../promise/src/UnhandledRejectionException.php | 31 ++ vendor/react/promise/src/functions.php | 411 +++++++++++++++++++++ vendor/react/promise/src/functions_include.php | 5 + 16 files changed, 1287 insertions(+) create mode 100644 vendor/react/promise/LICENSE create mode 100644 vendor/react/promise/composer.json create mode 100644 vendor/react/promise/src/CancellablePromiseInterface.php create mode 100644 vendor/react/promise/src/CancellationQueue.php create mode 100644 vendor/react/promise/src/Deferred.php create mode 100644 vendor/react/promise/src/Exception/LengthException.php create mode 100644 vendor/react/promise/src/ExtendedPromiseInterface.php create mode 100644 vendor/react/promise/src/FulfilledPromise.php create mode 100644 vendor/react/promise/src/LazyPromise.php create mode 100644 vendor/react/promise/src/Promise.php create mode 100644 vendor/react/promise/src/PromiseInterface.php create mode 100644 vendor/react/promise/src/PromisorInterface.php create mode 100644 vendor/react/promise/src/RejectedPromise.php create mode 100644 vendor/react/promise/src/UnhandledRejectionException.php create mode 100644 vendor/react/promise/src/functions.php create mode 100644 vendor/react/promise/src/functions_include.php (limited to 'vendor/react/promise') diff --git a/vendor/react/promise/LICENSE b/vendor/react/promise/LICENSE new file mode 100644 index 0000000..21c1357 --- /dev/null +++ b/vendor/react/promise/LICENSE @@ -0,0 +1,24 @@ +The MIT License (MIT) + +Copyright (c) 2012 Jan Sorgalla, Christian Lück, Cees-Jan Kiewiet, Chris Boden + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/react/promise/composer.json b/vendor/react/promise/composer.json new file mode 100644 index 0000000..2a48ed1 --- /dev/null +++ b/vendor/react/promise/composer.json @@ -0,0 +1,48 @@ +{ + "name": "react/promise", + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "license": "MIT", + "authors": [ + { + "name": "Jan Sorgalla", + "homepage": "https://sorgalla.com/", + "email": "jsorgalla@gmail.com" + }, + { + "name": "Christian Lück", + "homepage": "https://clue.engineering/", + "email": "christian@clue.engineering" + }, + { + "name": "Cees-Jan Kiewiet", + "homepage": "https://wyrihaximus.net/", + "email": "reactphp@ceesjankiewiet.nl" + }, + { + "name": "Chris Boden", + "homepage": "https://cboden.dev/", + "email": "cboden@gmail.com" + } + ], + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.36" + }, + "autoload": { + "psr-4": { + "React\\Promise\\": "src/" + }, + "files": ["src/functions_include.php"] + }, + "autoload-dev": { + "psr-4": { + "React\\Promise\\": ["tests", "tests/fixtures"] + } + }, + "keywords": [ + "promise", + "promises" + ] +} diff --git a/vendor/react/promise/src/CancellablePromiseInterface.php b/vendor/react/promise/src/CancellablePromiseInterface.php new file mode 100644 index 0000000..6b3a8c6 --- /dev/null +++ b/vendor/react/promise/src/CancellablePromiseInterface.php @@ -0,0 +1,17 @@ +started) { + return; + } + + $this->started = true; + $this->drain(); + } + + public function enqueue($cancellable) + { + if (!\is_object($cancellable) || !\method_exists($cancellable, 'then') || !\method_exists($cancellable, 'cancel')) { + return; + } + + $length = \array_push($this->queue, $cancellable); + + if ($this->started && 1 === $length) { + $this->drain(); + } + } + + private function drain() + { + for ($i = key($this->queue); isset($this->queue[$i]); $i++) { + $cancellable = $this->queue[$i]; + + $exception = null; + + try { + $cancellable->cancel(); + } catch (\Throwable $exception) { + } catch (\Exception $exception) { + } + + unset($this->queue[$i]); + + if ($exception) { + throw $exception; + } + } + + $this->queue = []; + } +} diff --git a/vendor/react/promise/src/Deferred.php b/vendor/react/promise/src/Deferred.php new file mode 100644 index 0000000..3ca034b --- /dev/null +++ b/vendor/react/promise/src/Deferred.php @@ -0,0 +1,65 @@ +canceller = $canceller; + } + + public function promise() + { + if (null === $this->promise) { + $this->promise = new Promise(function ($resolve, $reject, $notify) { + $this->resolveCallback = $resolve; + $this->rejectCallback = $reject; + $this->notifyCallback = $notify; + }, $this->canceller); + $this->canceller = null; + } + + return $this->promise; + } + + public function resolve($value = null) + { + $this->promise(); + + \call_user_func($this->resolveCallback, $value); + } + + public function reject($reason = null) + { + $this->promise(); + + \call_user_func($this->rejectCallback, $reason); + } + + /** + * @deprecated 2.6.0 Progress support is deprecated and should not be used anymore. + * @param mixed $update + */ + public function notify($update = null) + { + $this->promise(); + + \call_user_func($this->notifyCallback, $update); + } + + /** + * @deprecated 2.2.0 + * @see Deferred::notify() + */ + public function progress($update = null) + { + $this->notify($update); + } +} diff --git a/vendor/react/promise/src/Exception/LengthException.php b/vendor/react/promise/src/Exception/LengthException.php new file mode 100644 index 0000000..775c48d --- /dev/null +++ b/vendor/react/promise/src/Exception/LengthException.php @@ -0,0 +1,7 @@ +then(null, $onRejected); + * ``` + * + * Additionally, you can type hint the `$reason` argument of `$onRejected` to catch + * only specific errors. + * + * @param callable $onRejected + * @return ExtendedPromiseInterface + */ + public function otherwise(callable $onRejected); + + /** + * Allows you to execute "cleanup" type tasks in a promise chain. + * + * It arranges for `$onFulfilledOrRejected` to be called, with no arguments, + * when the promise is either fulfilled or rejected. + * + * * If `$promise` fulfills, and `$onFulfilledOrRejected` returns successfully, + * `$newPromise` will fulfill with the same value as `$promise`. + * * If `$promise` fulfills, and `$onFulfilledOrRejected` throws or returns a + * rejected promise, `$newPromise` will reject with the thrown exception or + * rejected promise's reason. + * * If `$promise` rejects, and `$onFulfilledOrRejected` returns successfully, + * `$newPromise` will reject with the same reason as `$promise`. + * * If `$promise` rejects, and `$onFulfilledOrRejected` throws or returns a + * rejected promise, `$newPromise` will reject with the thrown exception or + * rejected promise's reason. + * + * `always()` behaves similarly to the synchronous finally statement. When combined + * with `otherwise()`, `always()` allows you to write code that is similar to the familiar + * synchronous catch/finally pair. + * + * Consider the following synchronous code: + * + * ```php + * try { + * return doSomething(); + * } catch(\Exception $e) { + * return handleError($e); + * } finally { + * cleanup(); + * } + * ``` + * + * Similar asynchronous code (with `doSomething()` that returns a promise) can be + * written: + * + * ```php + * return doSomething() + * ->otherwise('handleError') + * ->always('cleanup'); + * ``` + * + * @param callable $onFulfilledOrRejected + * @return ExtendedPromiseInterface + */ + public function always(callable $onFulfilledOrRejected); + + /** + * Registers a handler for progress updates from promise. It is a shortcut for: + * + * ```php + * $promise->then(null, null, $onProgress); + * ``` + * + * @param callable $onProgress + * @return ExtendedPromiseInterface + * @deprecated 2.6.0 Progress support is deprecated and should not be used anymore. + */ + public function progress(callable $onProgress); +} diff --git a/vendor/react/promise/src/FulfilledPromise.php b/vendor/react/promise/src/FulfilledPromise.php new file mode 100644 index 0000000..1472752 --- /dev/null +++ b/vendor/react/promise/src/FulfilledPromise.php @@ -0,0 +1,71 @@ +value = $value; + } + + public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) + { + if (null === $onFulfilled) { + return $this; + } + + try { + return resolve($onFulfilled($this->value)); + } catch (\Throwable $exception) { + return new RejectedPromise($exception); + } catch (\Exception $exception) { + return new RejectedPromise($exception); + } + } + + public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) + { + if (null === $onFulfilled) { + return; + } + + $result = $onFulfilled($this->value); + + if ($result instanceof ExtendedPromiseInterface) { + $result->done(); + } + } + + public function otherwise(callable $onRejected) + { + return $this; + } + + public function always(callable $onFulfilledOrRejected) + { + return $this->then(function ($value) use ($onFulfilledOrRejected) { + return resolve($onFulfilledOrRejected())->then(function () use ($value) { + return $value; + }); + }); + } + + public function progress(callable $onProgress) + { + return $this; + } + + public function cancel() + { + } +} diff --git a/vendor/react/promise/src/LazyPromise.php b/vendor/react/promise/src/LazyPromise.php new file mode 100644 index 0000000..bbe9293 --- /dev/null +++ b/vendor/react/promise/src/LazyPromise.php @@ -0,0 +1,66 @@ +factory = $factory; + } + + public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) + { + return $this->promise()->then($onFulfilled, $onRejected, $onProgress); + } + + public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) + { + return $this->promise()->done($onFulfilled, $onRejected, $onProgress); + } + + public function otherwise(callable $onRejected) + { + return $this->promise()->otherwise($onRejected); + } + + public function always(callable $onFulfilledOrRejected) + { + return $this->promise()->always($onFulfilledOrRejected); + } + + public function progress(callable $onProgress) + { + return $this->promise()->progress($onProgress); + } + + public function cancel() + { + return $this->promise()->cancel(); + } + + /** + * @internal + * @see Promise::settle() + */ + public function promise() + { + if (null === $this->promise) { + try { + $this->promise = resolve(\call_user_func($this->factory)); + } catch (\Throwable $exception) { + $this->promise = new RejectedPromise($exception); + } catch (\Exception $exception) { + $this->promise = new RejectedPromise($exception); + } + } + + return $this->promise; + } +} diff --git a/vendor/react/promise/src/Promise.php b/vendor/react/promise/src/Promise.php new file mode 100644 index 0000000..33759e6 --- /dev/null +++ b/vendor/react/promise/src/Promise.php @@ -0,0 +1,256 @@ +canceller = $canceller; + + // Explicitly overwrite arguments with null values before invoking + // resolver function. This ensure that these arguments do not show up + // in the stack trace in PHP 7+ only. + $cb = $resolver; + $resolver = $canceller = null; + $this->call($cb); + } + + public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) + { + if (null !== $this->result) { + return $this->result->then($onFulfilled, $onRejected, $onProgress); + } + + if (null === $this->canceller) { + return new static($this->resolver($onFulfilled, $onRejected, $onProgress)); + } + + // This promise has a canceller, so we create a new child promise which + // has a canceller that invokes the parent canceller if all other + // followers are also cancelled. We keep a reference to this promise + // instance for the static canceller function and clear this to avoid + // keeping a cyclic reference between parent and follower. + $parent = $this; + ++$parent->requiredCancelRequests; + + return new static( + $this->resolver($onFulfilled, $onRejected, $onProgress), + static function () use (&$parent) { + if (++$parent->cancelRequests >= $parent->requiredCancelRequests) { + $parent->cancel(); + } + + $parent = null; + } + ); + } + + public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) + { + if (null !== $this->result) { + return $this->result->done($onFulfilled, $onRejected, $onProgress); + } + + $this->handlers[] = static function (ExtendedPromiseInterface $promise) use ($onFulfilled, $onRejected) { + $promise + ->done($onFulfilled, $onRejected); + }; + + if ($onProgress) { + $this->progressHandlers[] = $onProgress; + } + } + + public function otherwise(callable $onRejected) + { + return $this->then(null, static function ($reason) use ($onRejected) { + if (!_checkTypehint($onRejected, $reason)) { + return new RejectedPromise($reason); + } + + return $onRejected($reason); + }); + } + + public function always(callable $onFulfilledOrRejected) + { + return $this->then(static function ($value) use ($onFulfilledOrRejected) { + return resolve($onFulfilledOrRejected())->then(function () use ($value) { + return $value; + }); + }, static function ($reason) use ($onFulfilledOrRejected) { + return resolve($onFulfilledOrRejected())->then(function () use ($reason) { + return new RejectedPromise($reason); + }); + }); + } + + public function progress(callable $onProgress) + { + return $this->then(null, null, $onProgress); + } + + public function cancel() + { + if (null === $this->canceller || null !== $this->result) { + return; + } + + $canceller = $this->canceller; + $this->canceller = null; + + $this->call($canceller); + } + + private function resolver(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) + { + return function ($resolve, $reject, $notify) use ($onFulfilled, $onRejected, $onProgress) { + if ($onProgress) { + $progressHandler = static function ($update) use ($notify, $onProgress) { + try { + $notify($onProgress($update)); + } catch (\Throwable $e) { + $notify($e); + } catch (\Exception $e) { + $notify($e); + } + }; + } else { + $progressHandler = $notify; + } + + $this->handlers[] = static function (ExtendedPromiseInterface $promise) use ($onFulfilled, $onRejected, $resolve, $reject, $progressHandler) { + $promise + ->then($onFulfilled, $onRejected) + ->done($resolve, $reject, $progressHandler); + }; + + $this->progressHandlers[] = $progressHandler; + }; + } + + private function reject($reason = null) + { + if (null !== $this->result) { + return; + } + + $this->settle(reject($reason)); + } + + private function settle(ExtendedPromiseInterface $promise) + { + $promise = $this->unwrap($promise); + + if ($promise === $this) { + $promise = new RejectedPromise( + new \LogicException('Cannot resolve a promise with itself.') + ); + } + + $handlers = $this->handlers; + + $this->progressHandlers = $this->handlers = []; + $this->result = $promise; + $this->canceller = null; + + foreach ($handlers as $handler) { + $handler($promise); + } + } + + private function unwrap($promise) + { + $promise = $this->extract($promise); + + while ($promise instanceof self && null !== $promise->result) { + $promise = $this->extract($promise->result); + } + + return $promise; + } + + private function extract($promise) + { + if ($promise instanceof LazyPromise) { + $promise = $promise->promise(); + } + + return $promise; + } + + private function call(callable $cb) + { + // Explicitly overwrite argument with null value. This ensure that this + // argument does not show up in the stack trace in PHP 7+ only. + $callback = $cb; + $cb = null; + + // Use reflection to inspect number of arguments expected by this callback. + // We did some careful benchmarking here: Using reflection to avoid unneeded + // function arguments is actually faster than blindly passing them. + // Also, this helps avoiding unnecessary function arguments in the call stack + // if the callback creates an Exception (creating garbage cycles). + if (\is_array($callback)) { + $ref = new \ReflectionMethod($callback[0], $callback[1]); + } elseif (\is_object($callback) && !$callback instanceof \Closure) { + $ref = new \ReflectionMethod($callback, '__invoke'); + } else { + $ref = new \ReflectionFunction($callback); + } + $args = $ref->getNumberOfParameters(); + + try { + if ($args === 0) { + $callback(); + } else { + // Keep references to this promise instance for the static resolve/reject functions. + // By using static callbacks that are not bound to this instance + // and passing the target promise instance by reference, we can + // still execute its resolving logic and still clear this + // reference when settling the promise. This helps avoiding + // garbage cycles if any callback creates an Exception. + // These assumptions are covered by the test suite, so if you ever feel like + // refactoring this, go ahead, any alternative suggestions are welcome! + $target =& $this; + $progressHandlers =& $this->progressHandlers; + + $callback( + static function ($value = null) use (&$target) { + if ($target !== null) { + $target->settle(resolve($value)); + $target = null; + } + }, + static function ($reason = null) use (&$target) { + if ($target !== null) { + $target->reject($reason); + $target = null; + } + }, + static function ($update = null) use (&$progressHandlers) { + foreach ($progressHandlers as $handler) { + $handler($update); + } + } + ); + } + } catch (\Throwable $e) { + $target = null; + $this->reject($e); + } catch (\Exception $e) { + $target = null; + $this->reject($e); + } + } +} diff --git a/vendor/react/promise/src/PromiseInterface.php b/vendor/react/promise/src/PromiseInterface.php new file mode 100644 index 0000000..edcb007 --- /dev/null +++ b/vendor/react/promise/src/PromiseInterface.php @@ -0,0 +1,41 @@ +reason = $reason; + } + + public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) + { + if (null === $onRejected) { + return $this; + } + + try { + return resolve($onRejected($this->reason)); + } catch (\Throwable $exception) { + return new RejectedPromise($exception); + } catch (\Exception $exception) { + return new RejectedPromise($exception); + } + } + + public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) + { + if (null === $onRejected) { + throw UnhandledRejectionException::resolve($this->reason); + } + + $result = $onRejected($this->reason); + + if ($result instanceof self) { + throw UnhandledRejectionException::resolve($result->reason); + } + + if ($result instanceof ExtendedPromiseInterface) { + $result->done(); + } + } + + public function otherwise(callable $onRejected) + { + if (!_checkTypehint($onRejected, $this->reason)) { + return $this; + } + + return $this->then(null, $onRejected); + } + + public function always(callable $onFulfilledOrRejected) + { + return $this->then(null, function ($reason) use ($onFulfilledOrRejected) { + return resolve($onFulfilledOrRejected())->then(function () use ($reason) { + return new RejectedPromise($reason); + }); + }); + } + + public function progress(callable $onProgress) + { + return $this; + } + + public function cancel() + { + } +} diff --git a/vendor/react/promise/src/UnhandledRejectionException.php b/vendor/react/promise/src/UnhandledRejectionException.php new file mode 100644 index 0000000..e7fe2f7 --- /dev/null +++ b/vendor/react/promise/src/UnhandledRejectionException.php @@ -0,0 +1,31 @@ +reason = $reason; + + $message = \sprintf('Unhandled Rejection: %s', \json_encode($reason)); + + parent::__construct($message, 0); + } + + public function getReason() + { + return $this->reason; + } +} diff --git a/vendor/react/promise/src/functions.php b/vendor/react/promise/src/functions.php new file mode 100644 index 0000000..2177dc2 --- /dev/null +++ b/vendor/react/promise/src/functions.php @@ -0,0 +1,411 @@ +then($resolve, $reject, $notify); + }, $canceller); + } + + return new FulfilledPromise($promiseOrValue); +} + +/** + * Creates a rejected promise for the supplied `$promiseOrValue`. + * + * If `$promiseOrValue` is a value, it will be the rejection value of the + * returned promise. + * + * If `$promiseOrValue` is a promise, its completion value will be the rejected + * value of the returned promise. + * + * This can be useful in situations where you need to reject a promise without + * throwing an exception. For example, it allows you to propagate a rejection with + * the value of another promise. + * + * @param mixed $promiseOrValue + * @return PromiseInterface + */ +function reject($promiseOrValue = null) +{ + if ($promiseOrValue instanceof PromiseInterface) { + return resolve($promiseOrValue)->then(function ($value) { + return new RejectedPromise($value); + }); + } + + return new RejectedPromise($promiseOrValue); +} + +/** + * Returns a promise that will resolve only once all the items in + * `$promisesOrValues` have resolved. The resolution value of the returned promise + * will be an array containing the resolution values of each of the items in + * `$promisesOrValues`. + * + * @param array $promisesOrValues + * @return PromiseInterface + */ +function all($promisesOrValues) +{ + return map($promisesOrValues, function ($val) { + return $val; + }); +} + +/** + * Initiates a competitive race that allows one winner. Returns a promise which is + * resolved in the same way the first settled promise resolves. + * + * The returned promise will become **infinitely pending** if `$promisesOrValues` + * contains 0 items. + * + * @param array $promisesOrValues + * @return PromiseInterface + */ +function race($promisesOrValues) +{ + $cancellationQueue = new CancellationQueue(); + $cancellationQueue->enqueue($promisesOrValues); + + return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $cancellationQueue) { + resolve($promisesOrValues) + ->done(function ($array) use ($cancellationQueue, $resolve, $reject, $notify) { + if (!is_array($array) || !$array) { + $resolve(); + return; + } + + foreach ($array as $promiseOrValue) { + $cancellationQueue->enqueue($promiseOrValue); + + resolve($promiseOrValue) + ->done($resolve, $reject, $notify); + } + }, $reject, $notify); + }, $cancellationQueue); +} + +/** + * Returns a promise that will resolve when any one of the items in + * `$promisesOrValues` resolves. The resolution value of the returned promise + * will be the resolution value of the triggering item. + * + * The returned promise will only reject if *all* items in `$promisesOrValues` are + * rejected. The rejection value will be an array of all rejection reasons. + * + * The returned promise will also reject with a `React\Promise\Exception\LengthException` + * if `$promisesOrValues` contains 0 items. + * + * @param array $promisesOrValues + * @return PromiseInterface + */ +function any($promisesOrValues) +{ + return some($promisesOrValues, 1) + ->then(function ($val) { + return \array_shift($val); + }); +} + +/** + * Returns a promise that will resolve when `$howMany` of the supplied items in + * `$promisesOrValues` resolve. The resolution value of the returned promise + * will be an array of length `$howMany` containing the resolution values of the + * triggering items. + * + * The returned promise will reject if it becomes impossible for `$howMany` items + * to resolve (that is, when `(count($promisesOrValues) - $howMany) + 1` items + * reject). The rejection value will be an array of + * `(count($promisesOrValues) - $howMany) + 1` rejection reasons. + * + * The returned promise will also reject with a `React\Promise\Exception\LengthException` + * if `$promisesOrValues` contains less items than `$howMany`. + * + * @param array $promisesOrValues + * @param int $howMany + * @return PromiseInterface + */ +function some($promisesOrValues, $howMany) +{ + $cancellationQueue = new CancellationQueue(); + $cancellationQueue->enqueue($promisesOrValues); + + return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $howMany, $cancellationQueue) { + resolve($promisesOrValues) + ->done(function ($array) use ($howMany, $cancellationQueue, $resolve, $reject, $notify) { + if (!\is_array($array) || $howMany < 1) { + $resolve([]); + return; + } + + $len = \count($array); + + if ($len < $howMany) { + throw new Exception\LengthException( + \sprintf( + 'Input array must contain at least %d item%s but contains only %s item%s.', + $howMany, + 1 === $howMany ? '' : 's', + $len, + 1 === $len ? '' : 's' + ) + ); + } + + $toResolve = $howMany; + $toReject = ($len - $toResolve) + 1; + $values = []; + $reasons = []; + + foreach ($array as $i => $promiseOrValue) { + $fulfiller = function ($val) use ($i, &$values, &$toResolve, $toReject, $resolve) { + if ($toResolve < 1 || $toReject < 1) { + return; + } + + $values[$i] = $val; + + if (0 === --$toResolve) { + $resolve($values); + } + }; + + $rejecter = function ($reason) use ($i, &$reasons, &$toReject, $toResolve, $reject) { + if ($toResolve < 1 || $toReject < 1) { + return; + } + + $reasons[$i] = $reason; + + if (0 === --$toReject) { + $reject($reasons); + } + }; + + $cancellationQueue->enqueue($promiseOrValue); + + resolve($promiseOrValue) + ->done($fulfiller, $rejecter, $notify); + } + }, $reject, $notify); + }, $cancellationQueue); +} + +/** + * Traditional map function, similar to `array_map()`, but allows input to contain + * promises and/or values, and `$mapFunc` may return either a value or a promise. + * + * The map function receives each item as argument, where item is a fully resolved + * value of a promise or value in `$promisesOrValues`. + * + * @param array $promisesOrValues + * @param callable $mapFunc + * @return PromiseInterface + */ +function map($promisesOrValues, callable $mapFunc) +{ + $cancellationQueue = new CancellationQueue(); + $cancellationQueue->enqueue($promisesOrValues); + + return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $mapFunc, $cancellationQueue) { + resolve($promisesOrValues) + ->done(function ($array) use ($mapFunc, $cancellationQueue, $resolve, $reject, $notify) { + if (!\is_array($array) || !$array) { + $resolve([]); + return; + } + + $toResolve = \count($array); + $values = []; + + foreach ($array as $i => $promiseOrValue) { + $cancellationQueue->enqueue($promiseOrValue); + $values[$i] = null; + + resolve($promiseOrValue) + ->then($mapFunc) + ->done( + function ($mapped) use ($i, &$values, &$toResolve, $resolve) { + $values[$i] = $mapped; + + if (0 === --$toResolve) { + $resolve($values); + } + }, + $reject, + $notify + ); + } + }, $reject, $notify); + }, $cancellationQueue); +} + +/** + * Traditional reduce function, similar to `array_reduce()`, but input may contain + * promises and/or values, and `$reduceFunc` may return either a value or a + * promise, *and* `$initialValue` may be a promise or a value for the starting + * value. + * + * @param array $promisesOrValues + * @param callable $reduceFunc + * @param mixed $initialValue + * @return PromiseInterface + */ +function reduce($promisesOrValues, callable $reduceFunc, $initialValue = null) +{ + $cancellationQueue = new CancellationQueue(); + $cancellationQueue->enqueue($promisesOrValues); + + return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $reduceFunc, $initialValue, $cancellationQueue) { + resolve($promisesOrValues) + ->done(function ($array) use ($reduceFunc, $initialValue, $cancellationQueue, $resolve, $reject, $notify) { + if (!\is_array($array)) { + $array = []; + } + + $total = \count($array); + $i = 0; + + // Wrap the supplied $reduceFunc with one that handles promises and then + // delegates to the supplied. + $wrappedReduceFunc = function ($current, $val) use ($reduceFunc, $cancellationQueue, $total, &$i) { + $cancellationQueue->enqueue($val); + + return $current + ->then(function ($c) use ($reduceFunc, $total, &$i, $val) { + return resolve($val) + ->then(function ($value) use ($reduceFunc, $total, &$i, $c) { + return $reduceFunc($c, $value, $i++, $total); + }); + }); + }; + + $cancellationQueue->enqueue($initialValue); + + \array_reduce($array, $wrappedReduceFunc, resolve($initialValue)) + ->done($resolve, $reject, $notify); + }, $reject, $notify); + }, $cancellationQueue); +} + +/** + * @internal + */ +function _checkTypehint(callable $callback, $object) +{ + if (!\is_object($object)) { + return true; + } + + if (\is_array($callback)) { + $callbackReflection = new \ReflectionMethod($callback[0], $callback[1]); + } elseif (\is_object($callback) && !$callback instanceof \Closure) { + $callbackReflection = new \ReflectionMethod($callback, '__invoke'); + } else { + $callbackReflection = new \ReflectionFunction($callback); + } + + $parameters = $callbackReflection->getParameters(); + + if (!isset($parameters[0])) { + return true; + } + + $expectedException = $parameters[0]; + + // PHP before v8 used an easy API: + if (\PHP_VERSION_ID < 70100 || \defined('HHVM_VERSION')) { + if (!$expectedException->getClass()) { + return true; + } + + return $expectedException->getClass()->isInstance($object); + } + + // Extract the type of the argument and handle different possibilities + $type = $expectedException->getType(); + + $isTypeUnion = true; + $types = []; + + switch (true) { + case $type === null: + break; + case $type instanceof \ReflectionNamedType: + $types = [$type]; + break; + case $type instanceof \ReflectionIntersectionType: + $isTypeUnion = false; + case $type instanceof \ReflectionUnionType; + $types = $type->getTypes(); + break; + default: + throw new \LogicException('Unexpected return value of ReflectionParameter::getType'); + } + + // If there is no type restriction, it matches + if (empty($types)) { + return true; + } + + foreach ($types as $type) { + + if ($type instanceof \ReflectionIntersectionType) { + foreach ($type->getTypes() as $typeToMatch) { + if (!($matches = ($typeToMatch->isBuiltin() && \gettype($object) === $typeToMatch->getName()) + || (new \ReflectionClass($typeToMatch->getName()))->isInstance($object))) { + break; + } + } + } else { + $matches = ($type->isBuiltin() && \gettype($object) === $type->getName()) + || (new \ReflectionClass($type->getName()))->isInstance($object); + } + + // If we look for a single match (union), we can return early on match + // If we look for a full match (intersection), we can return early on mismatch + if ($matches) { + if ($isTypeUnion) { + return true; + } + } else { + if (!$isTypeUnion) { + return false; + } + } + } + + // If we look for a single match (union) and did not return early, we matched no type and are false + // If we look for a full match (intersection) and did not return early, we matched all types and are true + return $isTypeUnion ? false : true; +} diff --git a/vendor/react/promise/src/functions_include.php b/vendor/react/promise/src/functions_include.php new file mode 100644 index 0000000..bd0c54f --- /dev/null +++ b/vendor/react/promise/src/functions_include.php @@ -0,0 +1,5 @@ +