mirror of
https://github.com/danog/amp.git
synced 2025-01-23 05:41:25 +01:00
7e30ee0c2c
Co-authored-by: Niklas Keller <me@kelunik.com>
104 lines
2.2 KiB
PHP
104 lines
2.2 KiB
PHP
<?php
|
|
|
|
namespace Amp\Future;
|
|
|
|
use Amp\CompositeException;
|
|
use Amp\Future;
|
|
use Amp\Internal;
|
|
use Revolt\EventLoop\Loop;
|
|
|
|
/**
|
|
* Spawns a new fiber asynchronously using the given callable and argument list.
|
|
*
|
|
* @template T
|
|
*
|
|
* @param callable():T $callback
|
|
*
|
|
* @return Future<T>
|
|
*/
|
|
function spawn(callable $callback): Future
|
|
{
|
|
$state = new Internal\FutureState;
|
|
|
|
$fiber = new \Fiber('Amp\\Internal\\run');
|
|
Loop::queue([$fiber, 'start'], $state, $callback);
|
|
|
|
return new Future($state);
|
|
}
|
|
|
|
/**
|
|
* Unwraps the first completed future.
|
|
*
|
|
* If you want the first future completed without an error, use {@see any()} instead.
|
|
*
|
|
* @template T
|
|
*
|
|
* @param iterable<Future<T>> $futures
|
|
*
|
|
* @return T
|
|
*
|
|
* @throws \Error If $futures is empty.
|
|
*/
|
|
function first(iterable $futures): mixed
|
|
{
|
|
foreach (Future::iterate($futures) as $first) {
|
|
return $first->join();
|
|
}
|
|
|
|
throw new \Error('No future provided');
|
|
}
|
|
|
|
/**
|
|
* Unwraps the first successfully completed future.
|
|
*
|
|
* If you want the first future completed, successful or not, use {@see first()} instead.
|
|
*
|
|
* @template Tk of array-key
|
|
* @template Tv
|
|
*
|
|
* @param iterable<Tk, Future<Tv>> $futures
|
|
*
|
|
* @return Tv
|
|
*
|
|
* @throws CompositeException If all futures errored.
|
|
*/
|
|
function any(iterable $futures): mixed
|
|
{
|
|
$errors = [];
|
|
foreach (Future::iterate($futures) as $index => $first) {
|
|
try {
|
|
return $first->join();
|
|
} catch (\Throwable $throwable) {
|
|
$errors[$index] = $throwable;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @var non-empty-array<Tk, \Throwable> $errors
|
|
*/
|
|
throw new CompositeException($errors);
|
|
}
|
|
|
|
/**
|
|
* Awaits all futures to complete or aborts if any errors.
|
|
*
|
|
* @template Tk of array-key
|
|
* @template Tv
|
|
*
|
|
* @param iterable<Tk, Future<Tv>> $futures
|
|
*
|
|
* @return array<Tk, Tv> Unwrapped values with the order preserved.
|
|
*/
|
|
function all(iterable $futures): array
|
|
{
|
|
$futures = \is_array($futures) ? $futures : \iterator_to_array($futures);
|
|
|
|
// Future::iterate() to throw the first error based on completion order instead of argument order
|
|
foreach (Future::iterate($futures) as $k => $future) {
|
|
$futures[$k] = $future->join();
|
|
}
|
|
|
|
/** @var array<Tk, Tv> */
|
|
return $futures;
|
|
}
|