1
0
mirror of https://github.com/danog/loop.git synced 2024-12-02 17:27:48 +01:00
loop/lib/Generic/GenericLoop.php

135 lines
3.5 KiB
PHP
Raw Normal View History

2022-12-23 20:44:07 +01:00
<?php declare(strict_types=1);
2020-07-21 18:06:19 +02:00
/**
* Generic loop.
*
* @author Daniil Gentili <daniil@daniil.it>
* @copyright 2016-2020 Daniil Gentili <daniil@daniil.it>
* @license https://opensource.org/licenses/MIT MIT
*/
namespace danog\Loop\Generic;
2020-07-21 21:45:22 +02:00
use danog\Loop\ResumableSignalLoop;
2020-07-21 18:06:19 +02:00
2022-12-23 20:44:07 +01:00
use function Amp\async;
2020-07-21 18:06:19 +02:00
/**
* Generic loop, runs single callable.
*
* The return value of the callable can be:
* * A number - the loop will be paused for the specified number of seconds
* * GenericLoop::STOP - The loop will stop
* * GenericLoop::PAUSE - The loop will pause forever (or until loop is `resumed()`
* from outside the loop)
* * GenericLoop::CONTINUE - Return this if you want to rerun the loop immediately
*
* If the callable does not return anything,
* the loop will behave is if GenericLoop::PAUSE was returned.
*
* The loop can be stopped from the outside by signaling `true`.
*
2020-07-22 18:18:57 +02:00
* @template T as int|null
2020-07-21 18:06:19 +02:00
* @template TGenerator as \Generator<mixed,Promise|array<array-key,Promise>,mixed,Promise<T>|T>
* @template TPromise as Promise<T>
*
* @template TCallable as T|TPromise|TGenerator
*
* @author Daniil Gentili <daniil@daniil.it>
*/
class GenericLoop extends ResumableSignalLoop
{
/**
* Stop the loop.
*/
const STOP = -1;
/**
* Pause the loop.
*/
const PAUSE = null;
/**
* Rerun the loop.
*/
const CONTINUE = 0;
/**
* Callable.
*
* @var callable
*
* @psalm-var callable():TCallable
*/
protected $callable;
/**
* Loop name.
*
* @var string
*/
protected $name;
/**
* Constructor.
*
2020-07-24 19:24:04 +02:00
* If possible, the callable will be bound to the current instance of the loop.
*
2020-07-21 18:06:19 +02:00
* @param callable $callable Callable to run
* @param string $name Loop name
*
* @psalm-param callable():TCallable $callable Callable to run
*/
public function __construct(callable $callable, string $name)
{
2020-07-24 19:24:04 +02:00
if ($callable instanceof \Closure) {
try {
$callable = $callable->bindTo($this);
} catch (\Throwable $e) {
// Might cause an error for wrapped object methods
}
}
2020-07-21 18:06:19 +02:00
$this->callable = $callable;
$this->name = $name;
}
/**
* Loop implementation.
*/
2022-12-23 20:44:07 +01:00
public function loop(): void
2020-07-21 18:06:19 +02:00
{
$callable = $this->callable;
while (true) {
2020-07-23 14:18:33 +02:00
/** @psalm-var ?int|TGenerator|TPromise */
2020-07-21 18:06:19 +02:00
$timeout = $callable();
if ($timeout instanceof \Generator) {
2020-07-23 14:18:33 +02:00
/** @psalm-var ?int */
2022-12-23 20:44:07 +01:00
$timeout = $timeout;
2020-07-21 18:06:19 +02:00
} elseif ($timeout instanceof Promise) {
2020-07-23 14:18:33 +02:00
/** @psalm-var ?int */
2022-12-23 20:44:07 +01:00
$timeout = $timeout;
2020-07-21 18:06:19 +02:00
}
if ($timeout === self::PAUSE) {
$this->reportPause(0);
} elseif ($timeout > 0) {
$this->reportPause($timeout);
}
/** @psalm-suppress MixedArgument */
2022-12-23 20:44:07 +01:00
if ($timeout === self::STOP || $this->waitSignal(async(fn () => $this->pause($timeout)))) {
2020-07-23 17:03:53 +02:00
break;
2020-07-21 18:06:19 +02:00
}
}
}
/**
* Report pause, can be overriden for logging.
*
* @param integer $timeout Pause duration, 0 = forever
*
*/
protected function reportPause(int $timeout): void
{
}
/**
2020-07-24 19:24:04 +02:00
* Get loop name, provided to constructor.
2020-07-21 18:06:19 +02:00
*
*/
public function __toString(): string
{
return $this->name;
}
}