Example #1
0
 public function resume($params = null)
 {
     $this->generator->send($params);
     if (!$this->generator->valid()) {
         $this->closed = true;
     }
     return $this->generator->current();
 }
Example #2
0
 /**
  * {@inheritdoc}
  */
 public function tick()
 {
     if ($this->firstTick) {
         $this->firstTick = false;
         $this->deferred->notify(new MessageEvent($this, $this->generator->current()));
     } else {
         $this->deferred->notify(new MessageEvent($this, $this->generator->send(null)));
     }
     if (!$this->generator->valid()) {
         $this->deferred->resolve(new Event($this));
     }
 }
Example #3
0
 /**
  * When you need to return Result from your function, and it also depends on another
  * functions returning Results, you can make it a generator function and yield
  * values from dependant functions, this pattern makes code less bloated with
  * statements like this:
  * $res = something();
  * if ($res instanceof Ok) {
  *     $something = $res->unwrap();
  * } else {
  *     return $res;
  * }
  *
  * Instead you can write:
  * $something = (yield something());
  *
  * @see /example.php
  *
  * @param \Generator $resultsGenerator Generator that produces Result instances
  * @return Result
  */
 public static function reduce(\Generator $resultsGenerator)
 {
     /** @var Result $result */
     $result = $resultsGenerator->current();
     while ($resultsGenerator->valid()) {
         if ($result instanceof Err) {
             return $result;
         }
         $tmpResult = $resultsGenerator->send($result->unwrap());
         if ($resultsGenerator->valid()) {
             $result = $tmpResult;
         }
     }
     return $result;
 }
Example #4
0
 public function valid()
 {
     if ($this->_currentGen) {
         return $this->_currentGen->valid();
     }
     return !!$this->current();
 }
Example #5
0
 /**
  * Examines the value yielded from the generator and prepares the next step in interation.
  *
  * @param mixed $yielded
  */
 private function next($yielded)
 {
     if (!$this->generator->valid()) {
         $result = $this->generator->getReturn();
         if ($result instanceof Awaitable) {
             $this->reject(new AwaitableReturnedError($result));
             return;
         }
         if ($result instanceof Generator) {
             $this->reject(new GeneratorReturnedError($result));
             return;
         }
         $this->resolve($result);
         return;
     }
     $this->busy = true;
     if ($yielded instanceof Generator) {
         $yielded = new self($yielded);
     }
     $this->current = $yielded;
     if ($yielded instanceof Awaitable) {
         $yielded->done($this->send, $this->capture);
     } else {
         Loop\queue($this->send, $yielded);
     }
     $this->busy = false;
 }
Example #6
0
 /**
  * Return value that generator has returned or thrown.
  * @return mixed
  */
 public function getReturnOrThrown()
 {
     $this->validateInvalidity();
     if ($this->e === null && $this->g->valid() && !$this->valid()) {
         return $this->g->current();
     }
     if ($this->e) {
         return $this->e;
     }
     return method_exists($this->g, 'getReturn') ? $this->g->getReturn() : null;
 }
 private function checkResult(\Generator $generator, Channel $channel)
 {
     if (!$generator->valid()) {
         foreach ($this->actions as list(, $gen, , $undo)) {
             if ($gen && $gen !== $generator) {
                 $undo($gen->current());
             }
         }
         return [$generator->getReturn(), $channel];
     }
     return false;
 }
Example #8
0
 /**
  * @param \Generator $generator
  * @param string $prefix
  */
 public function __construct(\Generator $generator, string $prefix)
 {
     $yielded = $generator->current();
     $prefix .= \sprintf("; %s yielded at key %s", \is_object($yielded) ? \get_class($yielded) : \gettype($yielded), $generator->key());
     if (!$generator->valid()) {
         parent::__construct($prefix);
         return;
     }
     $reflGen = new \ReflectionGenerator($generator);
     $exeGen = $reflGen->getExecutingGenerator();
     if ($isSubgenerator = $exeGen !== $generator) {
         $reflGen = new \ReflectionGenerator($exeGen);
     }
     parent::__construct(\sprintf("%s on line %s in %s", $prefix, $reflGen->getExecutingLine(), $reflGen->getExecutingFile()));
 }
Example #9
0
 /**
  * Examines the value yielded from the generator and prepares the next step in interation.
  *
  * @param mixed $yielded
  */
 private function next($yielded)
 {
     if (!$this->generator->valid()) {
         $this->resolve($this->generator->getReturn());
         $this->close();
         return;
     }
     if ($yielded instanceof Generator) {
         $yielded = new self($yielded);
     }
     if ($yielded instanceof Awaitable) {
         $yielded->done($this->send, $this->capture);
     } else {
         Loop\queue($this->send, $yielded);
     }
 }
Example #10
0
 /**
  * {@inheritdoc}
  */
 public function read($length)
 {
     $this->initializeBeforeRead();
     if (!$this->generator->valid()) {
         return '';
     }
     if ($this->resource->eof()) {
         $this->generator->next();
         if (!$this->generator->valid()) {
             return '';
         }
         $this->resource = $this->generator->current();
         $this->resource->rewind();
     }
     return $this->resource->fread($length);
 }
Example #11
0
 /**
  * Runs the generator to completion then fails the coroutine with the given exception.
  *
  * @param \Throwable $exception
  */
 private function dispose(\Throwable $exception)
 {
     if ($this->generator->valid()) {
         try {
             try {
                 // Ensure generator has run to completion to avoid throws from finally blocks on destruction.
                 do {
                     $this->generator->throw($exception);
                 } while ($this->generator->valid());
             } finally {
                 // Throw from finally to attach any exception thrown from generator as previous exception.
                 throw $exception;
             }
         } catch (\Throwable $exception) {
             // $exception will be used to fail the coroutine.
         }
     }
     $this->fail($exception);
 }
Example #12
0
 /**
  * {@inheritdoc}
  */
 public function cancel(Throwable $reason = null)
 {
     if (null === $reason) {
         $reason = new TerminatedException();
     }
     if (null !== $this->generator) {
         try {
             do {
                 if ($this->current instanceof Awaitable) {
                     $this->current->cancel($reason);
                 }
                 $this->current = $this->generator->throw($reason);
             } while ($this->generator->valid());
         } catch (Throwable $exception) {
             $reason = $exception;
         }
     }
     parent::cancel($reason);
 }
/**
 *
 * @param int $n
 * @param \Generator $gen
 *
 * @return \Generator
 */
function take($n, Generator $gen)
{
    while ($n-- > 0 && $gen->valid()) {
        (yield $gen->current());
        $gen->next();
    }
}
Example #14
0
 private function responseCodec(\Generator $filter, InternalRequest $ireq) : \Generator
 {
     while ($filter->valid()) {
         $cur = $filter->send(yield);
         if ($cur !== null) {
             $ireq->responseWriter->send($cur);
         }
     }
     $cur = $filter->getReturn();
     if ($cur !== null) {
         $ireq->responseWriter->send($cur);
     }
     $ireq->responseWriter->send(null);
 }
Example #15
0
 /**
  * Returns true, if there are still tokens left to be generated.
  *
  * If the lexer-generator still has tokens to generate,
  * this returns true and false, if it doesn't
  *
  * @see \Generator->valid
  *
  * @return bool
  */
 protected function hasTokens()
 {
     return $this->tokens->valid();
 }
Example #16
0
 private function responseCodec(\Generator $filter, InternalRequest $ireq) : \Generator
 {
     while (($yield = yield) !== null) {
         $cur = $filter->send($yield);
         if ($yield === false) {
             if ($cur !== null) {
                 $ireq->responseWriter->send($cur);
                 if (\is_array($cur)) {
                     // in case of headers, to flush a maybe started body too, we need to send false twice
                     $cur = $filter->send(false);
                     if ($cur !== null) {
                         $ireq->responseWriter->send($cur);
                     }
                 }
             }
             $ireq->responseWriter->send(false);
         } elseif ($cur !== null) {
             $ireq->responseWriter->send($cur);
         }
     }
     $cur = $filter->send(null);
     if (\is_array($cur)) {
         $ireq->responseWriter->send($cur);
         $filter->send(null);
     }
     \assert($filter->valid() === false);
     $cur = $filter->getReturn();
     if ($cur !== null) {
         $ireq->responseWriter->send($cur);
     }
     $ireq->responseWriter->send(null);
 }
 /**
  * Checks if current position is valid
  * @see Iterator::rewind
  * @link http://php.net/manual/en/iterator.valid.php
  * @return boolean
  */
 public function valid()
 {
     return $this->generator->valid();
 }
Example #18
0
 /**
  * For a callable, it's always valid to iterate
  *
  * @return bool
  */
 public function valid()
 {
     return $this->generator ? $this->generator->valid() : true;
 }
Example #19
0
 /**
  * @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();
             }
         };
     });
 }
Example #20
0
/**
 * A general purpose function for creating error messages from generator yields
 *
 * @param \Generator $generator
 * @param string $prefix
 * @return string
 */
function makeGeneratorError(\Generator $generator, $prefix = "Generator error")
{
    if (PHP_MAJOR_VERSION < 7 || !$generator->valid()) {
        return $prefix;
    }
    $reflGen = new \ReflectionGenerator($generator);
    $exeGen = $reflGen->getExecutingGenerator();
    if ($isSubgenerator = $exeGen !== $generator) {
        $reflGen = new \ReflectionGenerator($exeGen);
    }
    return sprintf("{$prefix} on line %s in %s", $reflGen->getExecutingLine(), $reflGen->getExecutingFile());
}
Example #21
0
 /**
  * @param \Generator $logs
  *
  * @return int
  */
 protected function cntGeneratorLogs($logs)
 {
     $cnt = 0;
     while ($logs->valid()) {
         $cnt++;
         $logs->next();
     }
     return $cnt;
 }
Example #22
0
 /**
  * checks whether a coroutine is empty
  * @return bool
  */
 public function isFinished()
 {
     return !$this->coroutine->valid();
 }
Example #23
0
 /**
  * @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();
             }
         };
     });
 }
Example #24
0
 public function valid()
 {
     if (!$this->generator) {
         $this->rewind();
     }
     return $this->generator->valid();
 }
Example #25
0
/** @internal */
function __next_coroutine($yielded, \Generator $generator)
{
    return promise_for($yielded)->then(function ($value) use($generator) {
        $nextYield = $generator->send($value);
        return $generator->valid() ? __next_coroutine($nextYield, $generator) : $value;
    }, function ($reason) use($generator) {
        $nextYield = $generator->throw(exception_for($reason));
        // The throw was caught, so keep iterating on the coroutine
        return __next_coroutine($nextYield, $generator);
    });
}
Example #26
0
 /**
  * Returns true if the task is finished.
  *
  * @return boolean
  */
 public function isFinished()
 {
     return $this->started && !($this->generator && $this->generator->valid());
 }