diff --git a/src/Collection.php b/src/Collection.php index 13068a8f1..d65f0cc77 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -292,7 +292,7 @@ public static function empty(): CollectionInterface public function every(callable ...$callbacks): CollectionInterface { - return new self(Every::of()(...$callbacks), $this->getIterator()); + return new self(Every::of()(static fn (): bool => false)(...$callbacks), $this->getIterator()); } public function explode(...$explodes): CollectionInterface diff --git a/src/Operation/Every.php b/src/Operation/Every.php index 9dbcbf7ea..ae348d9fc 100644 --- a/src/Operation/Every.php +++ b/src/Operation/Every.php @@ -18,64 +18,80 @@ final class Every extends AbstractOperation { /** - * @psalm-return Closure(callable(T, TKey, Iterator): bool ...): Closure(Iterator): Generator + * @psalm-return Closure(callable(T, TKey, Iterator...): bool): Closure(callable(T, TKey, Iterator...): bool): Closure(Iterator): Generator */ public function __invoke(): Closure { return /** - * @psalm-param callable(T, TKey, Iterator): bool ...$callbacks + * @psalm-param callable(T, TKey, Iterator): bool ...$matchers + * + * @psalm-return Closure(...callable(T, TKey, Iterator): bool): Closure(Iterator): Generator */ - static function (callable ...$callbacks): Closure { - $reducerCallback = + static function (callable ...$matchers): Closure { + return /** - * @param mixed $key - * @psalm-param TKey $key + * @psalm-param callable(T, TKey, Iterator): bool ...$callbacks * - * @psalm-return Closure(T): Closure(Iterator): Closure(bool, callable(T, TKey, Iterator): bool): bool + * @psalm-return Closure(Iterator): Generator */ - static fn ($key): Closure => - /** - * @param mixed $current - * @psalm-param T $current - * - * @psalm-return Closure(Iterator): Closure(bool, callable(T, TKey, Iterator): bool): bool - */ - static fn ($current): Closure => + static function (callable ...$callbacks) use ($matchers): Closure { + $callbackReducer = /** - * @psalm-param Iterator $iterator + * @psalm-param list): bool> $callbacks * - * @psalm-return Closure(bool, callable(T, TKey, Iterator): bool): bool + * @psalm-return Closure(T, TKey, Iterator): bool */ - static fn (Iterator $iterator): Closure => + static fn (array $callbacks): Closure => /** - * @psalm-param bool $carry - * @psalm-param callable(T, TKey, Iterator): bool $callable + * @param mixed $value + * @psalm-param T $value + * + * @param mixed $key + * @psalm-param TKey $key + * + * @psalm-param Iterator $iterator */ - static fn (bool $carry, callable $callable): bool => $carry || $callable($current, $key, $iterator); + static fn ($value, $key, Iterator $iterator): bool => array_reduce( + $callbacks, + static fn (bool $carry, callable $callback): bool => $carry || $callback($value, $key, $iterator), + false + ); - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator - */ - static function (Iterator $iterator) use ($callbacks, $reducerCallback): Generator { - // We could use FoldLeft but there is no need to go through all the items, - // we just need to return false as soon as the callbacks returns false. - foreach ($iterator as $key => $value) { - $result = array_reduce( - $callbacks, - $reducerCallback($key)($value)($iterator), - false - ); + $mapCallback = + /** + * @psalm-param callable(T, TKey, Iterator) $reducer1 + * + * @psalm-return Closure(callable(T, TKey, Iterator)): Closure(T, TKey, Iterator): bool + */ + static fn (callable $reducer1): Closure => + /** + * @psalm-param callable(T, TKey, Iterator) $reducer2 + * + * @psalm-return Closure(T, TKey, Iterator): bool + */ + static fn (callable $reducer2): Closure => + /** + * @param mixed $value + * @psalm-param T $value + * + * @param mixed $key + * @psalm-param TKey $key + * + * @psalm-param Iterator $iterator + */ + static fn ($value, $key, Iterator $iterator): bool => $reducer1($value, $key, $iterator) !== $reducer2($value, $key, $iterator); - if (false === $result) { - return yield $key => false; - } - } + /** @psalm-var Closure(Iterator): Generator $pipe */ + $pipe = Pipe::of()( + Map::of()($mapCallback($callbackReducer($callbacks))($callbackReducer($matchers))), + DropWhile::of()(static fn (bool $value): bool => true === $value), + Append::of()(true), + Head::of(), + ); - return yield true; + // Point free style. + return $pipe; }; }; }