/** * Executes the emitter coroutine. */ private function start() { Loop\queue(function () { // Asynchronously start the observable. if (null === $this->emitter) { return; } /** * Emits a value from the observable. * * @coroutine * * @param mixed $value If $value is an instance of \Icicle\Awaitable\Awaitable, the fulfillment value is * used as the value to emit or the rejection reason is thrown from this coroutine. If $value is an * instance of \Generator, it is used to create a coroutine which is then used as an awaitable. * * @return \Generator * * @resolve mixed The emitted value (the resolution value of $value) * * @throws \Icicle\Observable\Exception\CompletedError If the observable has been completed. * @throws \Icicle\Observable\Exception\BusyError If the observable is still busy emitting a value. */ $emit = function ($value = null) : \Generator { return $this->queue->push($value); }; try { $generator = ($this->emitter)($emit); if (!$generator instanceof Generator) { throw new UnexpectedTypeError('Generator', $generator); } $this->coroutine = new Coroutine($generator); $this->coroutine->done(function ($value) { $this->queue->complete($value); }, function (Throwable $exception) { $this->queue->fail($exception); }); } catch (Throwable $exception) { $this->queue->fail(new InvalidEmitterError($this->emitter, $exception)); } $this->emitter = null; }); }