JezK
Edit File: AmpFutureAdapter.php
<?php declare(strict_types=1); namespace Automattic\WooCommerce\Vendor\GraphQL\Executor\Promise\Adapter; use Amp\DeferredFuture; use Amp\Future; use Automattic\WooCommerce\Vendor\GraphQL\Error\InvariantViolation; use Automattic\WooCommerce\Vendor\GraphQL\Executor\Promise\Promise; use Automattic\WooCommerce\Vendor\GraphQL\Executor\Promise\PromiseAdapter; use function Amp\async; use function Amp\Future\await; /** * Allows integration with amphp/amp v3 (fiber-based futures). * * @see https://amphp.org/amp */ class AmpFutureAdapter implements PromiseAdapter { public function isThenable($value): bool { return $value instanceof Future; } /** @throws InvariantViolation */ public function convertThenable($thenable): Promise { return new Promise($thenable, $this); } /** @throws InvariantViolation */ public function then(Promise $promise, ?callable $onFulfilled = null, ?callable $onRejected = null): Promise { $future = $promise->adoptedPromise; assert($future instanceof Future); $next = async(static function () use ($future, $onFulfilled, $onRejected) { try { $value = $future->await(); } catch (\Throwable $reason) { if ($onRejected === null) { throw $reason; } return static::unwrapResult($onRejected($reason)); } if ($onFulfilled === null) { return $value; } return static::unwrapResult($onFulfilled($value)); }); return new Promise($next, $this); } /** @throws InvariantViolation */ public function create(callable $resolver): Promise { $deferred = new DeferredFuture(); try { $resolver( static function ($value) use ($deferred): void { static::resolveDeferred($deferred, $value); }, static function (\Throwable $exception) use ($deferred): void { $deferred->error($exception); } ); } catch (\Throwable $exception) { $deferred->error($exception); } return new Promise($deferred->getFuture(), $this); } /** * @throws \Error * @throws InvariantViolation */ public function createFulfilled($value = null): Promise { if ($value instanceof Promise) { return $value; } if ($value instanceof Future) { return new Promise($value, $this); } return new Promise(Future::complete($value), $this); } /** @throws InvariantViolation */ public function createRejected(\Throwable $reason): Promise { return new Promise(Future::error($reason), $this); } /** * @throws \Error * @throws InvariantViolation */ public function all(iterable $promisesOrValues): Promise { $items = is_array($promisesOrValues) ? $promisesOrValues : iterator_to_array($promisesOrValues); /** @var array<Future<mixed>> $futures */ $futures = []; foreach ($items as $key => $item) { if ($item instanceof Promise) { $item = $item->adoptedPromise; } if ($item instanceof Future) { $futures[$key] = $item; } } $combined = async(static function () use ($items, $futures): array { if ($futures === []) { return $items; } $resolved = await($futures); return array_replace($items, $resolved); }); return new Promise($combined, $this); } /** * @param DeferredFuture<mixed> $deferred * @param mixed $value */ protected static function resolveDeferred(DeferredFuture $deferred, $value): void { if ($value instanceof Promise) { $value = $value->adoptedPromise; } if ($value instanceof Future) { async(static function () use ($deferred, $value): void { try { $deferred->complete($value->await()); } catch (\Throwable $exception) { $deferred->error($exception); } }); return; } $deferred->complete($value); } /** * @param mixed $value * * @return mixed */ protected static function unwrapResult($value) { if ($value instanceof Promise) { $value = $value->adoptedPromise; } if ($value instanceof Future) { return $value->await(); } return $value; } }