Initial commit

This commit is contained in:
2020-10-07 10:37:15 +02:00
commit ce5f440392
28157 changed files with 4429172 additions and 0 deletions

View File

@@ -0,0 +1,125 @@
<?php
namespace GuzzleHttp\Ring\Future;
use GuzzleHttp\Ring\Exception\CancelledFutureAccessException;
use GuzzleHttp\Ring\Exception\RingException;
use React\Promise\PromiseInterface;
/**
* Implements common future functionality built on top of promises.
*/
trait BaseFutureTrait
{
/** @var callable */
private $waitfn;
/** @var callable */
private $cancelfn;
/** @var PromiseInterface */
private $wrappedPromise;
/** @var \Exception Error encountered. */
private $error;
/** @var mixed Result of the future */
private $result;
private $isRealized = false;
/**
* @param PromiseInterface $promise Promise to shadow with the future.
* @param callable $wait Function that blocks until the deferred
* computation has been resolved. This
* function MUST resolve the deferred value
* associated with the supplied promise.
* @param callable $cancel If possible and reasonable, provide a
* function that can be used to cancel the
* future from completing.
*/
public function __construct(
PromiseInterface $promise,
callable $wait = null,
callable $cancel = null
) {
$this->wrappedPromise = $promise;
$this->waitfn = $wait;
$this->cancelfn = $cancel;
}
public function wait()
{
if (!$this->isRealized) {
$this->addShadow();
if (!$this->isRealized && $this->waitfn) {
$this->invokeWait();
}
if (!$this->isRealized) {
$this->error = new RingException('Waiting did not resolve future');
}
}
if ($this->error) {
throw $this->error;
}
return $this->result;
}
public function promise()
{
return $this->wrappedPromise;
}
public function then(
callable $onFulfilled = null,
callable $onRejected = null,
callable $onProgress = null
) {
return $this->wrappedPromise->then($onFulfilled, $onRejected, $onProgress);
}
public function cancel()
{
if (!$this->isRealized) {
$cancelfn = $this->cancelfn;
$this->waitfn = $this->cancelfn = null;
$this->isRealized = true;
$this->error = new CancelledFutureAccessException();
if ($cancelfn) {
$cancelfn($this);
}
}
}
private function addShadow()
{
// Get the result and error when the promise is resolved. Note that
// calling this function might trigger the resolution immediately.
$this->wrappedPromise->then(
function ($value) {
$this->isRealized = true;
$this->result = $value;
$this->waitfn = $this->cancelfn = null;
},
function ($error) {
$this->isRealized = true;
$this->error = $error;
$this->waitfn = $this->cancelfn = null;
}
);
}
private function invokeWait()
{
try {
$wait = $this->waitfn;
$this->waitfn = null;
$wait();
} catch (\Exception $e) {
// Defer can throw to reject.
$this->error = $e;
$this->isRealized = true;
}
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace GuzzleHttp\Ring\Future;
/**
* Represents a future array that has been completed successfully.
*/
class CompletedFutureArray extends CompletedFutureValue implements FutureArrayInterface
{
public function __construct(array $result)
{
parent::__construct($result);
}
public function offsetExists($offset)
{
return isset($this->result[$offset]);
}
public function offsetGet($offset)
{
return $this->result[$offset];
}
public function offsetSet($offset, $value)
{
$this->result[$offset] = $value;
}
public function offsetUnset($offset)
{
unset($this->result[$offset]);
}
public function count()
{
return count($this->result);
}
public function getIterator()
{
return new \ArrayIterator($this->result);
}
}

View File

@@ -0,0 +1,57 @@
<?php
namespace GuzzleHttp\Ring\Future;
use React\Promise\FulfilledPromise;
use React\Promise\RejectedPromise;
/**
* Represents a future value that has been resolved or rejected.
*/
class CompletedFutureValue implements FutureInterface
{
protected $result;
protected $error;
private $cachedPromise;
/**
* @param mixed $result Resolved result
* @param \Exception $e Error. Pass a GuzzleHttp\Ring\Exception\CancelledFutureAccessException
* to mark the future as cancelled.
*/
public function __construct($result, \Exception $e = null)
{
$this->result = $result;
$this->error = $e;
}
public function wait()
{
if ($this->error) {
throw $this->error;
}
return $this->result;
}
public function cancel() {}
public function promise()
{
if (!$this->cachedPromise) {
$this->cachedPromise = $this->error
? new RejectedPromise($this->error)
: new FulfilledPromise($this->result);
}
return $this->cachedPromise;
}
public function then(
callable $onFulfilled = null,
callable $onRejected = null,
callable $onProgress = null
) {
return $this->promise()->then($onFulfilled, $onRejected, $onProgress);
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace GuzzleHttp\Ring\Future;
/**
* Represents a future array value that when dereferenced returns an array.
*/
class FutureArray implements FutureArrayInterface
{
use MagicFutureTrait;
public function offsetExists($offset)
{
return isset($this->_value[$offset]);
}
public function offsetGet($offset)
{
return $this->_value[$offset];
}
public function offsetSet($offset, $value)
{
$this->_value[$offset] = $value;
}
public function offsetUnset($offset)
{
unset($this->_value[$offset]);
}
public function count()
{
return count($this->_value);
}
public function getIterator()
{
return new \ArrayIterator($this->_value);
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace GuzzleHttp\Ring\Future;
/**
* Future that provides array-like access.
*/
interface FutureArrayInterface extends
FutureInterface,
\ArrayAccess,
\Countable,
\IteratorAggregate {};

View File

@@ -0,0 +1,40 @@
<?php
namespace GuzzleHttp\Ring\Future;
use React\Promise\PromiseInterface;
use React\Promise\PromisorInterface;
/**
* Represents the result of a computation that may not have completed yet.
*
* You can use the future in a blocking manner using the wait() function, or
* you can use a promise from the future to receive the result when the future
* has been resolved.
*
* When the future is dereferenced using wait(), the result of the computation
* is cached and returned for subsequent calls to wait(). If the result of the
* computation has not yet completed when wait() is called, the call to wait()
* will block until the future has completed.
*/
interface FutureInterface extends PromiseInterface, PromisorInterface
{
/**
* Returns the result of the future either from cache or by blocking until
* it is complete.
*
* This method must block until the future has a result or is cancelled.
* Throwing an exception in the wait() method will mark the future as
* realized and will throw the exception each time wait() is called.
* Throwing an instance of GuzzleHttp\Ring\CancelledException will mark
* the future as realized, will not throw immediately, but will throw the
* exception if the future's wait() method is called again.
*
* @return mixed
*/
public function wait();
/**
* Cancels the future, if possible.
*/
public function cancel();
}

View File

@@ -0,0 +1,12 @@
<?php
namespace GuzzleHttp\Ring\Future;
/**
* Represents a future value that responds to wait() to retrieve the promised
* value, but can also return promises that are delivered the value when it is
* available.
*/
class FutureValue implements FutureInterface
{
use BaseFutureTrait;
}

View File

@@ -0,0 +1,32 @@
<?php
namespace GuzzleHttp\Ring\Future;
/**
* Implements common future functionality that is triggered when the result
* property is accessed via a magic __get method.
*
* @property mixed $_value Actual data used by the future. Accessing this
* property will cause the future to block if needed.
*/
trait MagicFutureTrait
{
use BaseFutureTrait;
/**
* This function handles retrieving the dereferenced result when requested.
*
* @param string $name Should always be "data" or an exception is thrown.
*
* @return mixed Returns the dereferenced data.
* @throws \RuntimeException
* @throws \GuzzleHttp\Ring\Exception\CancelledException
*/
public function __get($name)
{
if ($name !== '_value') {
throw new \RuntimeException("Class has no {$name} property");
}
return $this->_value = $this->wait();
}
}