/** * @param \Generator $generator */ public function __construct(Generator $generator) { $this->generator = $generator; parent::__construct(function (callable $resolve, callable $reject) { /** * @param mixed $value The value to send to the generator. * @param \Throwable|null $exception Exception object to be thrown into the generator if not null. */ $this->worker = function ($value = null, Throwable $exception = null) use($resolve, $reject) { if ($this->paused) { // If paused, mark coroutine as ready to resume. $this->ready = true; return; } try { if ($this->initial) { // Get result of first yield statement. $this->initial = false; $this->current = $this->generator->current(); } elseif (null !== $exception) { // Throw exception at current execution point. $this->current = $this->generator->throw($exception); } else { // Send the new value and execute to next yield statement. $this->current = $this->generator->send($value); } if (!$this->generator->valid()) { $resolve($this->generator->getReturn()); $this->close(); return; } if ($this->current instanceof Generator) { $this->current = new self($this->current); } if ($this->current instanceof PromiseInterface) { $this->current->done($this->worker, $this->capture); } else { Loop\queue($this->worker, $this->current); } } catch (Throwable $exception) { $reject($exception); $this->close(); } }; /** * @param \Throwable $exception Exception to be thrown into the generator. */ $this->capture = function (Throwable $exception) { if (null !== $this->worker) { // Coroutine may have been closed. ($this->worker)(null, $exception); } }; Loop\queue($this->worker); return function (Throwable $exception) { try { $current = $this->generator->current(); // Get last yielded value. while ($this->generator->valid()) { if ($current instanceof PromiseInterface) { $current->cancel($exception); } $current = $this->generator->throw($exception); } } finally { $this->close(); } }; }); }
/** * @param \Generator $generator */ public function __construct(Generator $generator) { $this->generator = $generator; parent::__construct(function (callable $resolve, callable $reject) { $yielded = $this->generator->current(); if (!$this->generator->valid()) { $resolve($this->generator->getReturn()); $this->close(); return; } /** * @param mixed $value The value to send to the generator. */ $this->send = function ($value = null) use($resolve, $reject) { if ($this->paused) { // If paused, save callable and value for resuming. $this->next = [$this->send, $value]; return; } try { // Send the new value and execute to next yield statement. $yielded = $this->generator->send($value); if (!$this->generator->valid()) { $resolve($this->generator->getReturn()); $this->close(); return; } $this->next($yielded); } catch (Throwable $exception) { $reject($exception); $this->close(); } }; /** * @param \Throwable $exception Exception to be thrown into the generator. */ $this->capture = function (Throwable $exception) use($resolve, $reject) { if ($this->paused) { // If paused, save callable and exception for resuming. $this->next = [$this->capture, $exception]; return; } try { // Throw exception at current execution point. $yielded = $this->generator->throw($exception); if (!$this->generator->valid()) { $resolve($this->generator->getReturn()); $this->close(); return; } $this->next($yielded); } catch (Throwable $exception) { $reject($exception); $this->close(); } }; $this->next($yielded); return function (Throwable $exception) { try { $current = $this->generator->current(); // Get last yielded value. if ($current instanceof PromiseInterface) { $current->cancel($exception); } } finally { $this->close(); } }; }); }