From 580c3f4ffe9608d2beb56d418c68b3b112420e76 Mon Sep 17 00:00:00 2001 From: Mario Date: Sun, 10 Nov 2019 12:49:51 +0000 Subject: another bulk of composer updates (cherry picked from commit 6685381fd8db507493c3d7c1793f8c05c681bbce) --- vendor/sabre/event/lib/Emitter.php | 18 ++ vendor/sabre/event/lib/EmitterInterface.php | 83 +++++++ vendor/sabre/event/lib/EmitterTrait.php | 195 +++++++++++++++ vendor/sabre/event/lib/EventEmitter.php | 13 +- vendor/sabre/event/lib/EventEmitterInterface.php | 100 -------- vendor/sabre/event/lib/EventEmitterTrait.php | 211 ---------------- vendor/sabre/event/lib/Loop/Loop.php | 40 ++-- vendor/sabre/event/lib/Loop/functions.php | 29 +-- vendor/sabre/event/lib/Promise.php | 67 +----- vendor/sabre/event/lib/Promise/functions.php | 26 +- .../event/lib/PromiseAlreadyResolvedException.php | 4 +- vendor/sabre/event/lib/Version.php | 6 +- vendor/sabre/event/lib/WildcardEmitter.php | 37 +++ vendor/sabre/event/lib/WildcardEmitterTrait.php | 264 +++++++++++++++++++++ vendor/sabre/event/lib/coroutine.php | 53 +++-- 15 files changed, 681 insertions(+), 465 deletions(-) create mode 100644 vendor/sabre/event/lib/Emitter.php create mode 100644 vendor/sabre/event/lib/EmitterInterface.php create mode 100644 vendor/sabre/event/lib/EmitterTrait.php delete mode 100644 vendor/sabre/event/lib/EventEmitterInterface.php delete mode 100644 vendor/sabre/event/lib/EventEmitterTrait.php create mode 100644 vendor/sabre/event/lib/WildcardEmitter.php create mode 100644 vendor/sabre/event/lib/WildcardEmitterTrait.php (limited to 'vendor/sabre/event/lib') diff --git a/vendor/sabre/event/lib/Emitter.php b/vendor/sabre/event/lib/Emitter.php new file mode 100644 index 000000000..ab5e8c90e --- /dev/null +++ b/vendor/sabre/event/lib/Emitter.php @@ -0,0 +1,18 @@ +listeners[$eventName])) { + $this->listeners[$eventName] = [ + true, // If there's only one item, it's sorted + [$priority], + [$callBack] + ]; + } else { + $this->listeners[$eventName][0] = false; // marked as unsorted + $this->listeners[$eventName][1][] = $priority; + $this->listeners[$eventName][2][] = $callBack; + } + + } + + /** + * Subscribe to an event exactly once. + * + * @return void + */ + function once(string $eventName, callable $callBack, int $priority = 100) { + + $wrapper = null; + $wrapper = function() use ($eventName, $callBack, &$wrapper) { + + $this->removeListener($eventName, $wrapper); + return \call_user_func_array($callBack, \func_get_args()); + + }; + + $this->on($eventName, $wrapper, $priority); + + } + + /** + * Emits an event. + * + * This method will return true if 0 or more listeners were succesfully + * handled. false is returned if one of the events broke the event chain. + * + * If the continueCallBack is specified, this callback will be called every + * time before the next event handler is called. + * + * If the continueCallback returns false, event propagation stops. This + * allows you to use the eventEmitter as a means for listeners to implement + * functionality in your application, and break the event loop as soon as + * some condition is fulfilled. + * + * Note that returning false from an event subscriber breaks propagation + * and returns false, but if the continue-callback stops propagation, this + * is still considered a 'successful' operation and returns true. + * + * Lastly, if there are 5 event handlers for an event. The continueCallback + * will be called at most 4 times. + */ + function emit(string $eventName, array $arguments = [], callable $continueCallBack = null) : bool { + + if (\is_null($continueCallBack)) { + + foreach ($this->listeners($eventName) as $listener) { + + $result = \call_user_func_array($listener, $arguments); + if ($result === false) { + return false; + } + } + + } else { + + $listeners = $this->listeners($eventName); + $counter = \count($listeners); + + foreach ($listeners as $listener) { + + $counter--; + $result = \call_user_func_array($listener, $arguments); + if ($result === false) { + return false; + } + + if ($counter > 0) { + if (!$continueCallBack()) break; + } + + } + + } + + return true; + + } + + /** + * Returns the list of listeners for an event. + * + * The list is returned as an array, and the list of events are sorted by + * their priority. + * + * @return callable[] + */ + function listeners(string $eventName) : array { + + if (!isset($this->listeners[$eventName])) { + return []; + } + + // The list is not sorted + if (!$this->listeners[$eventName][0]) { + + // Sorting + \array_multisort($this->listeners[$eventName][1], SORT_NUMERIC, $this->listeners[$eventName][2]); + + // Marking the listeners as sorted + $this->listeners[$eventName][0] = true; + } + + return $this->listeners[$eventName][2]; + + } + + /** + * Removes a specific listener from an event. + * + * If the listener could not be found, this method will return false. If it + * was removed it will return true. + */ + function removeListener(string $eventName, callable $listener) : bool { + + if (!isset($this->listeners[$eventName])) { + return false; + } + foreach ($this->listeners[$eventName][2] as $index => $check) { + if ($check === $listener) { + unset($this->listeners[$eventName][1][$index]); + unset($this->listeners[$eventName][2][$index]); + return true; + } + } + return false; + + } + + /** + * Removes all listeners. + * + * If the eventName argument is specified, all listeners for that event are + * removed. If it is not specified, every listener for every event is + * removed. + * + * @return void + */ + function removeAllListeners(string $eventName = null) { + + if (!\is_null($eventName)) { + unset($this->listeners[$eventName]); + } else { + $this->listeners = []; + } + + } + + /** + * The list of listeners + * + * @var array + */ + protected $listeners = []; + +} diff --git a/vendor/sabre/event/lib/EventEmitter.php b/vendor/sabre/event/lib/EventEmitter.php index 1bb1c3cf9..cae6ac2a6 100644 --- a/vendor/sabre/event/lib/EventEmitter.php +++ b/vendor/sabre/event/lib/EventEmitter.php @@ -1,18 +1,19 @@ -listeners[$eventName])) { - $this->listeners[$eventName] = [ - true, // If there's only one item, it's sorted - [$priority], - [$callBack] - ]; - } else { - $this->listeners[$eventName][0] = false; // marked as unsorted - $this->listeners[$eventName][1][] = $priority; - $this->listeners[$eventName][2][] = $callBack; - } - - } - - /** - * Subscribe to an event exactly once. - * - * @param string $eventName - * @param callable $callBack - * @param int $priority - * @return void - */ - function once($eventName, callable $callBack, $priority = 100) { - - $wrapper = null; - $wrapper = function() use ($eventName, $callBack, &$wrapper) { - - $this->removeListener($eventName, $wrapper); - return call_user_func_array($callBack, func_get_args()); - - }; - - $this->on($eventName, $wrapper, $priority); - - } - - /** - * Emits an event. - * - * This method will return true if 0 or more listeners were succesfully - * handled. false is returned if one of the events broke the event chain. - * - * If the continueCallBack is specified, this callback will be called every - * time before the next event handler is called. - * - * If the continueCallback returns false, event propagation stops. This - * allows you to use the eventEmitter as a means for listeners to implement - * functionality in your application, and break the event loop as soon as - * some condition is fulfilled. - * - * Note that returning false from an event subscriber breaks propagation - * and returns false, but if the continue-callback stops propagation, this - * is still considered a 'successful' operation and returns true. - * - * Lastly, if there are 5 event handlers for an event. The continueCallback - * will be called at most 4 times. - * - * @param string $eventName - * @param array $arguments - * @param callback $continueCallBack - * @return bool - */ - function emit($eventName, array $arguments = [], callable $continueCallBack = null) { - - if (is_null($continueCallBack)) { - - foreach ($this->listeners($eventName) as $listener) { - - $result = call_user_func_array($listener, $arguments); - if ($result === false) { - return false; - } - } - - } else { - - $listeners = $this->listeners($eventName); - $counter = count($listeners); - - foreach ($listeners as $listener) { - - $counter--; - $result = call_user_func_array($listener, $arguments); - if ($result === false) { - return false; - } - - if ($counter > 0) { - if (!$continueCallBack()) break; - } - - } - - } - - return true; - - } - - /** - * Returns the list of listeners for an event. - * - * The list is returned as an array, and the list of events are sorted by - * their priority. - * - * @param string $eventName - * @return callable[] - */ - function listeners($eventName) { - - if (!isset($this->listeners[$eventName])) { - return []; - } - - // The list is not sorted - if (!$this->listeners[$eventName][0]) { - - // Sorting - array_multisort($this->listeners[$eventName][1], SORT_NUMERIC, $this->listeners[$eventName][2]); - - // Marking the listeners as sorted - $this->listeners[$eventName][0] = true; - } - - return $this->listeners[$eventName][2]; - - } - - /** - * Removes a specific listener from an event. - * - * If the listener could not be found, this method will return false. If it - * was removed it will return true. - * - * @param string $eventName - * @param callable $listener - * @return bool - */ - function removeListener($eventName, callable $listener) { - - if (!isset($this->listeners[$eventName])) { - return false; - } - foreach ($this->listeners[$eventName][2] as $index => $check) { - if ($check === $listener) { - unset($this->listeners[$eventName][1][$index]); - unset($this->listeners[$eventName][2][$index]); - return true; - } - } - return false; - - } - - /** - * Removes all listeners. - * - * If the eventName argument is specified, all listeners for that event are - * removed. If it is not specified, every listener for every event is - * removed. - * - * @param string $eventName - * @return void - */ - function removeAllListeners($eventName = null) { - - if (!is_null($eventName)) { - unset($this->listeners[$eventName]); - } else { - $this->listeners = []; - } - - } - -} diff --git a/vendor/sabre/event/lib/Loop/Loop.php b/vendor/sabre/event/lib/Loop/Loop.php index 86ee7c8b0..301fe8920 100644 --- a/vendor/sabre/event/lib/Loop/Loop.php +++ b/vendor/sabre/event/lib/Loop/Loop.php @@ -1,4 +1,4 @@ -runNextTicks(); $nextTimeout = $this->runTimers(); @@ -284,7 +271,7 @@ class Loop { * * If there's no more pending timers, this function returns null. * - * @return float + * @return float|null */ protected function runTimers() { @@ -295,7 +282,7 @@ class Loop { // Add the last timer back to the array. if ($timer) { $this->timers[] = $timer; - return $timer[0] - microtime(true); + return max(0, $timer[0] - microtime(true)); } } @@ -303,7 +290,10 @@ class Loop { /** * Runs all pending stream events. * - * @param float $timeout + * If $timeout is 0, it will return immediately. If $timeout is null, it + * will wait indefinitely. + * + * @param float|null timeout */ protected function runStreams($timeout) { @@ -312,7 +302,7 @@ class Loop { $read = $this->readStreams; $write = $this->writeStreams; $except = null; - if (stream_select($read, $write, $except, null, $timeout)) { + if (stream_select($read, $write, $except, ($timeout === null) ? null : 0, $timeout ? (int)($timeout * 1000000) : 0)) { // See PHP Bug https://bugs.php.net/bug.php?id=62452 // Fixed in PHP7 @@ -328,7 +318,7 @@ class Loop { } } elseif ($this->running && ($this->nextTick || $this->timers)) { - usleep($timeout !== null ? $timeout * 1000000 : 200000); + usleep($timeout !== null ? intval($timeout * 1000000) : 200000); } } diff --git a/vendor/sabre/event/lib/Loop/functions.php b/vendor/sabre/event/lib/Loop/functions.php index 56c5bc8c7..b5884b2b6 100644 --- a/vendor/sabre/event/lib/Loop/functions.php +++ b/vendor/sabre/event/lib/Loop/functions.php @@ -1,15 +1,13 @@ -setTimeout($cb, $timeout); @@ -20,24 +18,19 @@ function setTimeout(callable $cb, $timeout) { * * The value this function returns can be used to stop the interval with * clearInterval. - * - * @param callable $cb - * @param float $timeout - * @return array */ -function setInterval(callable $cb, $timeout) { +function setInterval(callable $cb, float $timeout) : array { return instance()->setInterval($cb, $timeout); } /** - * Stops a running internval. + * Stops a running interval. * - * @param array $intervalId * @return void */ -function clearInterval($intervalId) { +function clearInterval(array $intervalId) { instance()->clearInterval($intervalId); @@ -46,7 +39,6 @@ function clearInterval($intervalId) { /** * Runs a function immediately at the next iteration of the loop. * - * @param callable $cb * @return void */ function nextTick(callable $cb) { @@ -66,7 +58,6 @@ function nextTick(callable $cb) { * prevent the eventloop from never stopping. * * @param resource $stream - * @param callable $cb * @return void */ function addReadStream($stream, callable $cb) { @@ -85,7 +76,6 @@ function addReadStream($stream, callable $cb) { * prevent the eventloop from never stopping. * * @param resource $stream - * @param callable $cb * @return void */ function addWriteStream($stream, callable $cb) { @@ -144,11 +134,8 @@ function run() { * * This function will return true if there are _any_ events left in the * loop after the tick. - * - * @param bool $block - * @return bool */ -function tick($block = false) { +function tick(bool $block = false) : bool { return instance()->tick($block); @@ -167,10 +154,8 @@ function stop() { /** * Retrieves or sets the global Loop object. - * - * @param Loop $newLoop */ -function instance(Loop $newLoop = null) { +function instance(Loop $newLoop = null) : Loop { static $loop; if ($newLoop) { diff --git a/vendor/sabre/event/lib/Promise.php b/vendor/sabre/event/lib/Promise.php index 1c874c1bd..1d04bd4d4 100644 --- a/vendor/sabre/event/lib/Promise.php +++ b/vendor/sabre/event/lib/Promise.php @@ -1,8 +1,9 @@ -fulfill and $this->reject. * Using the executor is optional. - * - * @param callable $executor */ function __construct(callable $executor = null) { @@ -84,12 +83,8 @@ class Promise { * * If either of the callbacks throw an exception, the returned promise will * be rejected and the exception will be passed back. - * - * @param callable $onFulfilled - * @param callable $onRejected - * @return Promise */ - function then(callable $onFulfilled = null, callable $onRejected = null) { + function then(callable $onFulfilled = null, callable $onRejected = null) : Promise { // This new subPromise will be returned from this function, and will // be fulfilled with the result of the onFulfilled or onRejected event @@ -122,11 +117,8 @@ class Promise { * * Its usage is identical to then(). However, the otherwise() function is * preferred. - * - * @param callable $onRejected - * @return Promise */ - function otherwise(callable $onRejected) { + function otherwise(callable $onRejected) : Promise { return $this->then(null, $onRejected); @@ -152,13 +144,9 @@ class Promise { /** * Marks this promise as rejected, and set it's rejection reason. * - * While it's possible to use any PHP value as the reason, it's highly - * recommended to use an Exception for this. - * - * @param mixed $reason * @return void */ - function reject($reason = null) { + function reject(Throwable $reason) { if ($this->state !== self::PENDING) { throw new PromiseAlreadyResolvedException('This promise is already resolved, and you\'re not allowed to resolve a promise more than once'); } @@ -181,7 +169,6 @@ class Promise { * one. In PHP it might be useful to call this on the last promise in a * chain. * - * @throws Exception * @return mixed */ function wait() { @@ -205,15 +192,7 @@ class Promise { } else { // If we got here, it means that the asynchronous operation // errored. Therefore we need to throw an exception. - $reason = $this->value; - if ($reason instanceof Exception) { - throw $reason; - } elseif (is_scalar($reason)) { - throw new Exception($reason); - } else { - $type = is_object($reason) ? get_class($reason) : gettype($reason); - throw new Exception('Promise was rejected with reason of type: ' . $type); - } + throw $this->value; } @@ -272,7 +251,7 @@ class Promise { // immediately fulfill the chained promise. $subPromise->fulfill($result); } - } catch (Exception $e) { + } catch (Throwable $e) { // If the event handler threw an exception, we need to make sure that // the chained promise is rejected as well. $subPromise->reject($e); @@ -287,34 +266,4 @@ class Promise { }); } - /** - * Alias for 'otherwise'. - * - * This function is now deprecated and will be removed in a future version. - * - * @param callable $onRejected - * @deprecated - * @return Promise - */ - function error(callable $onRejected) { - - return $this->otherwise($onRejected); - - } - - /** - * Deprecated. - * - * Please use Sabre\Event\Promise::all - * - * @param Promise[] $promises - * @deprecated - * @return Promise - */ - static function all(array $promises) { - - return Promise\all($promises); - - } - } diff --git a/vendor/sabre/event/lib/Promise/functions.php b/vendor/sabre/event/lib/Promise/functions.php index 3604b8aaa..275492cbc 100644 --- a/vendor/sabre/event/lib/Promise/functions.php +++ b/vendor/sabre/event/lib/Promise/functions.php @@ -1,14 +1,15 @@ -error( + )->otherwise( function($reason) use ($fail) { $fail($reason); } @@ -66,9 +71,8 @@ function all(array $promises) { * that first promise. * * @param Promise[] $promises - * @return Promise */ -function race(array $promises) { +function race(array $promises) : Promise { return new Promise(function($success, $fail) use ($promises) { @@ -106,9 +110,8 @@ function race(array $promises) { * promise and eventually get the same state as the followed promise. * * @param mixed $value - * @return Promise */ -function resolve($value) { +function resolve($value) : Promise { if ($value instanceof Promise) { return $value->then(); @@ -122,11 +125,8 @@ function resolve($value) { /** * Returns a Promise that will reject with the given reason. - * - * @param mixed $reason - * @return Promise */ -function reject($reason) { +function reject(Throwable $reason) : Promise { $promise = new Promise(); $promise->reject($reason); diff --git a/vendor/sabre/event/lib/PromiseAlreadyResolvedException.php b/vendor/sabre/event/lib/PromiseAlreadyResolvedException.php index 86a6c5b3f..534a3d494 100644 --- a/vendor/sabre/event/lib/PromiseAlreadyResolvedException.php +++ b/vendor/sabre/event/lib/PromiseAlreadyResolvedException.php @@ -1,4 +1,4 @@ -wildcardListeners; + } else { + $listeners = & $this->listeners; + } + + // Always fully reset the listener index. This is fairly sane for most + // applications, because there's a clear "event registering" and "event + // emitting" phase, but can be slow if there's a lot adding and removing + // of listeners during emitting of events. + $this->listenerIndex = []; + + if (!isset($listeners[$eventName])) { + $listeners[$eventName] = []; + } + $listeners[$eventName][] = [$priority, $callBack]; + + } + + /** + * Subscribe to an event exactly once. + * + * @return void + */ + function once(string $eventName, callable $callBack, int $priority = 100) { + + $wrapper = null; + $wrapper = function() use ($eventName, $callBack, &$wrapper) { + + $this->removeListener($eventName, $wrapper); + return \call_user_func_array($callBack, \func_get_args()); + + }; + + $this->on($eventName, $wrapper, $priority); + + } + + /** + * Emits an event. + * + * This method will return true if 0 or more listeners were succesfully + * handled. false is returned if one of the events broke the event chain. + * + * If the continueCallBack is specified, this callback will be called every + * time before the next event handler is called. + * + * If the continueCallback returns false, event propagation stops. This + * allows you to use the eventEmitter as a means for listeners to implement + * functionality in your application, and break the event loop as soon as + * some condition is fulfilled. + * + * Note that returning false from an event subscriber breaks propagation + * and returns false, but if the continue-callback stops propagation, this + * is still considered a 'successful' operation and returns true. + * + * Lastly, if there are 5 event handlers for an event. The continueCallback + * will be called at most 4 times. + */ + function emit(string $eventName, array $arguments = [], callable $continueCallBack = null) : bool { + + if (\is_null($continueCallBack)) { + + foreach ($this->listeners($eventName) as $listener) { + + $result = \call_user_func_array($listener, $arguments); + if ($result === false) { + return false; + } + } + + } else { + + $listeners = $this->listeners($eventName); + $counter = \count($listeners); + + foreach ($listeners as $listener) { + + $counter--; + $result = \call_user_func_array($listener, $arguments); + if ($result === false) { + return false; + } + + if ($counter > 0) { + if (!$continueCallBack()) break; + } + + } + + } + + return true; + + + } + + /** + * Returns the list of listeners for an event. + * + * The list is returned as an array, and the list of events are sorted by + * their priority. + * + * @return callable[] + */ + function listeners(string $eventName) : array { + + if (!\array_key_exists($eventName, $this->listenerIndex)) { + + // Create a new index. + $listeners = []; + $listenersPriority = []; + if (isset($this->listeners[$eventName])) foreach ($this->listeners[$eventName] as $listener) { + + $listenersPriority[] = $listener[0]; + $listeners[] = $listener[1]; + + } + + foreach ($this->wildcardListeners as $wcEvent => $wcListeners) { + + // Wildcard match + if (\substr($eventName, 0, \strlen($wcEvent)) === $wcEvent) { + + foreach ($wcListeners as $listener) { + + $listenersPriority[] = $listener[0]; + $listeners[] = $listener[1]; + + } + + } + + } + + // Sorting by priority + \array_multisort($listenersPriority, SORT_NUMERIC, $listeners); + + // Creating index + $this->listenerIndex[$eventName] = $listeners; + + } + + return $this->listenerIndex[$eventName]; + + } + + /** + * Removes a specific listener from an event. + * + * If the listener could not be found, this method will return false. If it + * was removed it will return true. + */ + function removeListener(string $eventName, callable $listener) : bool { + + // If it ends with a wildcard, we use the wildcardListeners array + if ($eventName[\strlen($eventName) - 1] === '*') { + $eventName = \substr($eventName, 0, -1); + $listeners = & $this->wildcardListeners; + } else { + $listeners = & $this->listeners; + } + + if (!isset($listeners[$eventName])) { + return false; + } + + foreach ($listeners[$eventName] as $index => $check) { + + if ($check[1] === $listener) { + + // Remove listener + unset($listeners[$eventName][$index]); + // Reset index + $this->listenerIndex = []; + return true; + + } + + } + + return false; + + } + + /** + * Removes all listeners. + * + * If the eventName argument is specified, all listeners for that event are + * removed. If it is not specified, every listener for every event is + * removed. + * + * @return void + */ + function removeAllListeners(string $eventName = null) { + + if (\is_null($eventName)) { + $this->listeners = []; + $this->wildcardListeners = []; + + } else { + + if ($eventName[\strlen($eventName) - 1] === '*') { + // Wildcard event + unset($this->wildcardListeners[\substr($eventName, 0, -1)]); + } else { + unset($this->listeners[$eventName]); + } + + } + + // Reset index + $this->listenerIndex = []; + + } + + /** + * The list of listeners + */ + protected $listeners = []; + + /** + * The list of "wildcard listeners". + */ + protected $wildcardListeners = []; + + /** + * An index of listeners for a specific event name. This helps speeding + * up emitting events after all listeners have been set. + * + * If the list of listeners changes though, the index clears. + */ + protected $listenerIndex = []; +} diff --git a/vendor/sabre/event/lib/coroutine.php b/vendor/sabre/event/lib/coroutine.php index 19c0ba8a7..750e8ab52 100644 --- a/vendor/sabre/event/lib/coroutine.php +++ b/vendor/sabre/event/lib/coroutine.php @@ -1,9 +1,9 @@ -request('GET', '/foo'); * yield $httpClient->request('DELETE', /foo'); * yield $httpClient->request('PUT', '/foo'); - * } catch(\Exception $reason) { + * } catch(\Throwable $reason) { * echo "Failed because: $reason\n"; * } * * }); * - * @copyright Copyright (C) 2013-2015 fruux GmbH. All rights reserved. + * @return \Sabre\Event\Promise + * @copyright Copyright (C) fruux GmbH (https://fruux.com/) * @author Evert Pot (http://evertpot.com/) * @license http://sabre.io/license/ Modified BSD License */ -function coroutine(callable $gen) { +function coroutine(callable $gen) : Promise { $generator = $gen(); if (!$generator instanceof Generator) { @@ -54,8 +55,6 @@ function coroutine(callable $gen) { // This is the value we're returning. $promise = new Promise(); - $lastYieldResult = null; - /** * So tempted to use the mythical y-combinator here, but it's not needed in * PHP. @@ -68,22 +67,14 @@ function coroutine(callable $gen) { if ($yieldedValue instanceof Promise) { $yieldedValue->then( function($value) use ($generator, &$advanceGenerator, &$lastYieldResult) { - $lastYieldResult = $value; $generator->send($value); $advanceGenerator(); }, - function($reason) use ($generator, $advanceGenerator) { - if ($reason instanceof Exception) { - $generator->throw($reason); - } elseif (is_scalar($reason)) { - $generator->throw(new Exception($reason)); - } else { - $type = is_object($reason) ? get_class($reason) : gettype($reason); - $generator->throw(new Exception('Promise was rejected with reason of type: ' . $type)); - } + function(Throwable $reason) use ($generator, $advanceGenerator) { + $generator->throw($reason); $advanceGenerator(); } - )->error(function($reason) use ($promise) { + )->otherwise(function(Throwable $reason) use ($promise) { // This error handler would be called, if something in the // generator throws an exception, and it's not caught // locally. @@ -94,24 +85,38 @@ function coroutine(callable $gen) { break; } else { // If the value was not a promise, we'll just let it pass through. - $lastYieldResult = $yieldedValue; $generator->send($yieldedValue); } } // If the generator is at the end, and we didn't run into an exception, - // we can fullfill the promise with the last thing that was yielded to - // us. - if (!$generator->valid() && $promise->state === Promise::PENDING) { - $promise->fulfill($lastYieldResult); + // We're grabbing the "return" value and fulfilling our top-level + // promise with its value. + if (!$generator->valid() && $promise->state === Promise::PENDING) { + $returnValue = $generator->getReturn(); + + // The return value is a promise. + if ($returnValue instanceof Promise) { + $returnValue->then(function($value) use ($promise) { + $promise->fulfill($value); + }, function(Throwable $reason) { + $promise->reject($reason); + }); + } else { + + $promise->fulfill($returnValue); + + } + + } }; try { $advanceGenerator(); - } catch (Exception $e) { + } catch (Throwable $e) { $promise->reject($e); } -- cgit v1.2.3