appwrite/src/Appwrite/Promises/Promise.php

195 lines
4.4 KiB
PHP
Raw Normal View History

2022-04-05 13:48:51 +00:00
<?php
2022-10-12 00:55:43 +00:00
namespace Appwrite\Promises;
abstract class Promise
2022-04-05 13:48:51 +00:00
{
2022-07-11 21:52:00 +00:00
protected const STATE_PENDING = 1;
protected const STATE_FULFILLED = 0;
protected const STATE_REJECTED = -1;
2022-04-05 13:48:51 +00:00
protected int $state = self::STATE_PENDING;
private mixed $result;
2024-10-01 14:30:47 +00:00
final public function __construct(?callable $executor = null)
2022-04-05 13:48:51 +00:00
{
if (\is_null($executor)) {
return;
}
$resolve = function ($value) {
$this->setResult($value);
$this->setState(self::STATE_FULFILLED);
};
$reject = function ($value) {
$this->setResult($value);
$this->setState(self::STATE_REJECTED);
2022-04-05 13:48:51 +00:00
};
2022-10-12 00:55:43 +00:00
$this->execute($executor, $resolve, $reject);
2022-04-05 13:48:51 +00:00
}
2022-10-12 00:55:43 +00:00
abstract protected function execute(
callable $executor,
callable $resolve,
callable $reject
): void;
2022-04-05 13:48:51 +00:00
/**
* Create a new promise from the given callable.
*
* @param callable $promise
2022-10-12 00:55:43 +00:00
* @return self
2022-04-05 13:48:51 +00:00
*/
2022-10-12 00:55:43 +00:00
public static function create(callable $promise): self
2022-04-05 13:48:51 +00:00
{
return new static($promise);
}
/**
* Resolve promise with given value.
*
* @param mixed $value
2022-10-12 00:55:43 +00:00
* @return self
2022-04-05 13:48:51 +00:00
*/
2022-10-12 00:55:43 +00:00
public static function resolve(mixed $value): self
2022-04-05 13:48:51 +00:00
{
return new static(function (callable $resolve) use ($value) {
$resolve($value);
});
}
/**
* Rejects the promise with the given reason.
*
* @param mixed $value
2022-10-12 00:55:43 +00:00
* @return self
2022-04-05 13:48:51 +00:00
*/
2022-10-12 00:55:43 +00:00
public static function reject(mixed $value): self
2022-04-05 13:48:51 +00:00
{
return new static(function (callable $resolve, callable $reject) use ($value) {
$reject($value);
});
}
/**
* Catch any exception thrown by the executor.
*
* @param callable $onRejected
2022-10-12 00:55:43 +00:00
* @return self
2022-04-05 13:48:51 +00:00
*/
2022-10-12 00:55:43 +00:00
public function catch(callable $onRejected): self
2022-04-05 13:48:51 +00:00
{
return $this->then(null, $onRejected);
}
/**
* Execute the promise.
*
* @param callable|null $onFulfilled
* @param callable|null $onRejected
2022-10-12 00:55:43 +00:00
* @return self
2022-04-05 13:48:51 +00:00
*/
2022-10-12 00:55:43 +00:00
public function then(
?callable $onFulfilled = null,
?callable $onRejected = null
): self {
if ($this->isRejected() && $onRejected === null) {
return $this;
}
if ($this->isFulfilled() && $onFulfilled === null) {
return $this;
}
2022-04-05 13:48:51 +00:00
return self::create(function (callable $resolve, callable $reject) use ($onFulfilled, $onRejected) {
while ($this->isPending()) {
usleep(25000);
}
$callable = $this->isFulfilled() ? $onFulfilled : $onRejected;
2022-07-18 06:47:08 +00:00
if (!\is_callable($callable)) {
2022-04-05 13:48:51 +00:00
$resolve($this->result);
return;
}
try {
$resolve($callable($this->result));
} catch (\Throwable $error) {
$reject($error);
}
});
}
/**
* Returns a promise that completes when all passed in promises complete.
*
2022-10-12 00:55:43 +00:00
* @param iterable|self[] $promises
* @return self
2022-04-05 13:48:51 +00:00
*/
2022-10-12 00:55:43 +00:00
abstract public static function all(iterable $promises): self;
2022-04-05 13:48:51 +00:00
/**
* Set resolved result
*
* @param mixed $value
* @return void
*/
2022-10-12 00:55:43 +00:00
protected function setResult(mixed $value): void
2022-04-05 13:48:51 +00:00
{
if (!\is_callable([$value, 'then'])) {
2022-04-07 12:23:45 +00:00
$this->result = $value;
return;
2022-04-05 13:48:51 +00:00
}
2022-04-07 12:23:45 +00:00
2022-04-05 13:48:51 +00:00
$resolved = false;
2022-10-12 00:55:43 +00:00
2022-04-05 13:48:51 +00:00
$callable = function ($value) use (&$resolved) {
$this->setResult($value);
$resolved = true;
};
2022-10-12 00:55:43 +00:00
2022-04-05 13:48:51 +00:00
$value->then($callable, $callable);
while (!$resolved) {
usleep(25000);
}
}
/**
* Change promise state
*
* @param integer $state
* @return void
*/
2022-10-12 00:55:43 +00:00
protected function setState(int $state): void
2022-04-05 13:48:51 +00:00
{
$this->state = $state;
}
/**
* Promise is pending
*
* @return boolean
*/
2022-10-12 00:55:43 +00:00
protected function isPending(): bool
2022-04-05 13:48:51 +00:00
{
return $this->state == self::STATE_PENDING;
}
/**
* Promise is fulfilled
*
* @return boolean
*/
2022-10-12 00:55:43 +00:00
protected function isFulfilled(): bool
2022-04-05 13:48:51 +00:00
{
return $this->state == self::STATE_FULFILLED;
}
/**
* Promise is rejected
*
* @return boolean
*/
2022-10-12 00:55:43 +00:00
protected function isRejected(): bool
{
return $this->state == self::STATE_REJECTED;
}
2022-07-11 21:52:00 +00:00
}