| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 | 
							- <?php
 
- declare(strict_types=1);
 
- namespace GuzzleHttp\Promise;
 
- use Generator;
 
- use Throwable;
 
- /**
 
-  * Creates a promise that is resolved using a generator that yields values or
 
-  * promises (somewhat similar to C#'s async keyword).
 
-  *
 
-  * When called, the Coroutine::of method will start an instance of the generator
 
-  * and returns a promise that is fulfilled with its final yielded value.
 
-  *
 
-  * Control is returned back to the generator when the yielded promise settles.
 
-  * This can lead to less verbose code when doing lots of sequential async calls
 
-  * with minimal processing in between.
 
-  *
 
-  *     use GuzzleHttp\Promise;
 
-  *
 
-  *     function createPromise($value) {
 
-  *         return new Promise\FulfilledPromise($value);
 
-  *     }
 
-  *
 
-  *     $promise = Promise\Coroutine::of(function () {
 
-  *         $value = (yield createPromise('a'));
 
-  *         try {
 
-  *             $value = (yield createPromise($value . 'b'));
 
-  *         } catch (\Throwable $e) {
 
-  *             // The promise was rejected.
 
-  *         }
 
-  *         yield $value . 'c';
 
-  *     });
 
-  *
 
-  *     // Outputs "abc"
 
-  *     $promise->then(function ($v) { echo $v; });
 
-  *
 
-  * @param callable $generatorFn Generator function to wrap into a promise.
 
-  *
 
-  * @return Promise
 
-  *
 
-  * @see https://github.com/petkaantonov/bluebird/blob/master/API.md#generators inspiration
 
-  */
 
- final class Coroutine implements PromiseInterface
 
- {
 
-     /**
 
-      * @var PromiseInterface|null
 
-      */
 
-     private $currentPromise;
 
-     /**
 
-      * @var Generator
 
-      */
 
-     private $generator;
 
-     /**
 
-      * @var Promise
 
-      */
 
-     private $result;
 
-     public function __construct(callable $generatorFn)
 
-     {
 
-         $this->generator = $generatorFn();
 
-         $this->result = new Promise(function (): void {
 
-             while (isset($this->currentPromise)) {
 
-                 $this->currentPromise->wait();
 
-             }
 
-         });
 
-         try {
 
-             $this->nextCoroutine($this->generator->current());
 
-         } catch (Throwable $throwable) {
 
-             $this->result->reject($throwable);
 
-         }
 
-     }
 
-     /**
 
-      * Create a new coroutine.
 
-      */
 
-     public static function of(callable $generatorFn): self
 
-     {
 
-         return new self($generatorFn);
 
-     }
 
-     public function then(
 
-         callable $onFulfilled = null,
 
-         callable $onRejected = null
 
-     ): PromiseInterface {
 
-         return $this->result->then($onFulfilled, $onRejected);
 
-     }
 
-     public function otherwise(callable $onRejected): PromiseInterface
 
-     {
 
-         return $this->result->otherwise($onRejected);
 
-     }
 
-     public function wait(bool $unwrap = true)
 
-     {
 
-         return $this->result->wait($unwrap);
 
-     }
 
-     public function getState(): string
 
-     {
 
-         return $this->result->getState();
 
-     }
 
-     public function resolve($value): void
 
-     {
 
-         $this->result->resolve($value);
 
-     }
 
-     public function reject($reason): void
 
-     {
 
-         $this->result->reject($reason);
 
-     }
 
-     public function cancel(): void
 
-     {
 
-         $this->currentPromise->cancel();
 
-         $this->result->cancel();
 
-     }
 
-     private function nextCoroutine($yielded): void
 
-     {
 
-         $this->currentPromise = Create::promiseFor($yielded)
 
-             ->then([$this, '_handleSuccess'], [$this, '_handleFailure']);
 
-     }
 
-     /**
 
-      * @internal
 
-      */
 
-     public function _handleSuccess($value): void
 
-     {
 
-         unset($this->currentPromise);
 
-         try {
 
-             $next = $this->generator->send($value);
 
-             if ($this->generator->valid()) {
 
-                 $this->nextCoroutine($next);
 
-             } else {
 
-                 $this->result->resolve($value);
 
-             }
 
-         } catch (Throwable $throwable) {
 
-             $this->result->reject($throwable);
 
-         }
 
-     }
 
-     /**
 
-      * @internal
 
-      */
 
-     public function _handleFailure($reason): void
 
-     {
 
-         unset($this->currentPromise);
 
-         try {
 
-             $nextYield = $this->generator->throw(Create::exceptionFor($reason));
 
-             // The throw was caught, so keep iterating on the coroutine
 
-             $this->nextCoroutine($nextYield);
 
-         } catch (Throwable $throwable) {
 
-             $this->result->reject($throwable);
 
-         }
 
-     }
 
- }
 
 
  |