From 8b848bb515a10f49520f2ef175aae533347ed5a8 Mon Sep 17 00:00:00 2001 From: Pol Dellaiera Date: Fri, 6 Nov 2020 21:23:47 +0100 Subject: [PATCH] refactor: Update asyncMap operation, make it variadic. Signed-off-by: Pol Dellaiera --- docs/pages/api.rst | 12 ++++++++---- spec/loophp/collection/CollectionSpec.php | 10 +++++++--- src/Collection.php | 4 ++-- src/Contract/Operation/AsyncMapable.php | 4 ++-- src/Operation/AsyncMap.php | 23 +++++++++++++++++++++-- 5 files changed, 40 insertions(+), 13 deletions(-) diff --git a/docs/pages/api.rst b/docs/pages/api.rst index 28f2cd61f..8d49e4a3d 100644 --- a/docs/pages/api.rst +++ b/docs/pages/api.rst @@ -254,24 +254,28 @@ asyncMap Apply one callback to every item of a collection and use the return value. -.. warning:: Operation are asynchronous and the result is then, non deterministic. +.. warning:: Asynchronously apply callbacks to a collection. This operation is deterministic, we cannot ensure the elements order at the end. .. warning:: Keys are preserved, use the "normalize" operation if you want to re-index the keys. Interface: `AsyncMapable`_ -Signature: ``Collection::asyncMap(callable $callback);`` +Signature: ``Collection::asyncMap(callable ...$callbacks);`` .. code-block:: php - $mapper = static function(int $value): int { + $mapper1 = static function(int $value): int { sleep($value); return $value; }; + $mapper2 = static function(int $value): int { + return $value * 2; + }; + $collection = Collection::fromIterable(['c' => 3, 'b' => 2, 'a' => 1]) - ->asyncMap($mapper); // ['a' => 1, 'b' => 2, 'c' => 3] + ->asyncMap($mapper1, $mapper2); // ['a' => 2, 'b' => 4, 'c' => 6] cache ~~~~~ diff --git a/spec/loophp/collection/CollectionSpec.php b/spec/loophp/collection/CollectionSpec.php index 00af47b9f..f3656199b 100644 --- a/spec/loophp/collection/CollectionSpec.php +++ b/spec/loophp/collection/CollectionSpec.php @@ -179,15 +179,19 @@ static function ($carry, $key, $value) { public function it_can_asyncMap(): void { - $callback = static function (int $v): int { + $callback1 = static function (int $v): int { sleep($v); return $v; }; + $callback2 = static function (int $v): int { + return $v * 2; + }; + $this::fromIterable(['c' => 3, 'b' => 2, 'a' => 1]) - ->asyncMap($callback) - ->shouldIterateAs(['a' => 1, 'b' => 2, 'c' => 3]); + ->asyncMap($callback1, $callback2) + ->shouldIterateAs(['a' => 2, 'b' => 4, 'c' => 6]); } public function it_can_be_constructed_from_a_file(): void diff --git a/src/Collection.php b/src/Collection.php index c03cd3212..03a400306 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -191,9 +191,9 @@ public function associate( return $this->pipe(Associate::of()($callbackForKeys)($callbackForValues)); } - public function asyncMap(callable $callback): CollectionInterface + public function asyncMap(callable ...$callbacks): CollectionInterface { - return $this->pipe(AsyncMap::of()($callback)); + return $this->pipe(AsyncMap::of()(...$callbacks)); } public function cache(?CacheItemPoolInterface $cache = null): CollectionInterface diff --git a/src/Contract/Operation/AsyncMapable.php b/src/Contract/Operation/AsyncMapable.php index dc2935d48..b75994ac5 100644 --- a/src/Contract/Operation/AsyncMapable.php +++ b/src/Contract/Operation/AsyncMapable.php @@ -14,9 +14,9 @@ interface AsyncMapable { /** - * Apply one asynchronous callback to a collection and use the return value. + * Asynchronously apply callbacks to a collection. * * @psalm-return \loophp\collection\Contract\Collection */ - public function asyncMap(callable $callback): Collection; + public function asyncMap(callable ...$callbacks): Collection; } diff --git a/src/Operation/AsyncMap.php b/src/Operation/AsyncMap.php index 2dbeb1c89..23d5ecca8 100644 --- a/src/Operation/AsyncMap.php +++ b/src/Operation/AsyncMap.php @@ -44,13 +44,32 @@ public function __invoke(): Closure * * @psalm-return Closure(Iterator): Generator */ - static fn (callable $callback): Closure => + static fn (callable ...$callbacks): Closure => /** * @psalm-param Iterator $iterator * * @psalm-return Generator */ - static function (Iterator $iterator) use ($callback): Generator { + static function (Iterator $iterator) use ($callbacks): Generator { + $callbackFactory = + /** + * @param mixed $key + * @psalm-param TKey $key + * + * @psalm-return Closure(T, callable(T, TKey): T): T + */ + static fn ($key): Closure => + /** + * @param mixed $carry + * @psalm-param T $carry + * @psalm-param callable(T, TKey): T $callback + * + * @psalm-return T + */ + static fn ($carry, callable $callback) => $callback($carry, $key); + + $callback = static fn ($value, $key) => array_reduce($callbacks, $callbackFactory($key), $value); + $emitter = new Emitter(); $iter = $emitter->iterate(); $callback = parallel($callback);