diff --git a/README.md b/README.md index 725c84c50..f07d1faf2 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ On top of this, this library: * uses [S.O.L.I.D. principles][solid on wikipedia], * does not have any external dependency, * fully tested, - * type safe (_type safe @ > 98%_), + * type safe (_type safe @ > 93%_), * framework agnostic. Except a few methods, most methods are [pure][pure function on wikipedia] and return a @@ -111,6 +111,12 @@ If you can't contribute to the code, you can also sponsor me on [Github][github * [Reddit release 2.0.0 thread][reddit release 2.0.0] * [Featured in PHPStorm Annotated August 2020][phpstorm annotated august 2020] +## Changelog + +See [CHANGELOG.md][changelog-md] for a changelog based on [git commits][git-commits]. + +For more detailed changelogs, please read the per release changelogs. + [packagist collection]: https://packagist.org/packages/loophp/collection [latest stable version]: https://img.shields.io/packagist/v/loophp/collection.svg?style=flat-square [github stars]: https://img.shields.io/github/stars/loophp/collection.svg?style=flat-square @@ -160,4 +166,6 @@ If you can't contribute to the code, you can also sponsor me on [Github][github [paypal sponsor]: https://www.paypal.me/drupol [reddit announcement]: https://www.reddit.com/r/PHP/comments/csxw23/a_stateless_and_modular_collection_class/ [reddit release 2.0.0]: https://www.reddit.com/r/PHP/comments/i2u2le/release_of_version_200_of_loophpcollection/ -[phpstorm annotated august 2020]: https://blog.jetbrains.com/phpstorm/2020/08/php-annotated-august-2020/ \ No newline at end of file +[phpstorm annotated august 2020]: https://blog.jetbrains.com/phpstorm/2020/08/php-annotated-august-2020/ +[changelog-md]: https://github.com/loophp/collection/blob/master/CHANGELOG.md +[git-commits]: https://github.com/loophp/collection/commits/master \ No newline at end of file diff --git a/docs/pages/api.rst b/docs/pages/api.rst index 4112f9fd0..9bf8fd4c7 100644 --- a/docs/pages/api.rst +++ b/docs/pages/api.rst @@ -159,6 +159,11 @@ Methods (operations) Operations always returns a new collection object. +all +~~~ + +Interface: `Allable`_ + append ~~~~~~ @@ -366,6 +371,11 @@ Signature: ``Collection::compact(...$values);`` $collection = Collection::with(['a', 1 => 'b', null, false, 0, 'c'];) ->compact(null, 0); // ['a', 1 => 'b', 3 => false, 5 => 'c'] +contains +~~~~~~~~ + +Interface: `Containsable`_ + cycle ~~~~~ @@ -440,6 +450,11 @@ Signature: ``Collection::explode(...$items);`` $collection = Collection::with($string) ->explode('o'); +falsy +~~~~~ + +Interface: `Falsyable`_ + filter ~~~~~~ @@ -547,6 +562,16 @@ However, when using a collection: This example will return ``['a', 'b', 'c', 'd', 'a']``. +foldLeft +~~~~~~~~ + +Interface: `FoldLeftable`_ + +foldRight +~~~~~~~~~ + +Interface: `FoldRightable`_ + forget ~~~~~~ @@ -578,6 +603,12 @@ Signature: ``Collection::frequency();`` ->frequency() ->all(); // [1 => 'a', 2 => 'b', 3 => 'c']; +get +~~~ + +Interface: `Getable`_ + + group ~~~~~ @@ -607,6 +638,11 @@ Signature: ``Collection::group(callable $callable = null);`` $collection = Collection::with($callback) ->group(); +has +~~~ + +Interface: `Hasable`_ + head ~~~~ @@ -659,6 +695,11 @@ Signature: ``Collection::ifThenElse(callable $condition, callable $then, ?callab Collection::fromIterable($input) ->ifThenElse($condition, $then, $else) // [3, 4, 5, 16, 7] +implode +~~~~~~~ + +Interface: `Implodeable`_ + intersect ~~~~~~~~~ @@ -849,6 +890,11 @@ Signature: ``Collection::nth(int $step, int $offset = 0);`` $collection = Collection::with(range(10, 100)) ->nth(3); +nullsy +~~~~~~ + +Interface: `Nullsyable`_ + only ~~~~ @@ -1026,6 +1072,11 @@ Signature: ``Collection::random(int $size = 1);`` $collection = Collection::with(['4', '5', '6']) ->random(); // ['6'] +reduce +~~~~~~ + +Interface: `Reduceable`_ + reduction ~~~~~~~~~ @@ -1081,7 +1132,6 @@ rsample Work in progress... sorry. - scale ~~~~~ @@ -1235,7 +1285,6 @@ Signature: ``Collection::sort(?callable $callback = null);`` ->sort() // Sort the values (which are now the keys) ->flip(); // Flip again to put back the keys and values, sorted by keys. - split ~~~~~ @@ -1305,6 +1354,11 @@ Signature: ``Collection::transpose();`` $result = Collection::with($records) ->transpose(); +truthy +~~~~~~ + +Interface: `Truthyable`_ + unpack ~~~~~~ @@ -1447,77 +1501,7 @@ Signature: ``Collection::zip(iterable ...$iterables);`` ->limit(100) ->flatten(); -Methods (transformations) -------------------------- - -Transformations might returns something different from a collection. - -all -~~~ - -Interface: `Allable`_ - -contains -~~~~~~~~ - -Interface: `Containsable`_ - -falsy -~~~~~ - -Interface: `Falsyable`_ - -foldLeft -~~~~~~~~ - -Interface: `FoldLeftable`_ - -foldRight -~~~~~~~~~ - -Interface: `FoldRightable`_ - -get -~~~ - -Interface: `Getable`_ - -has -~~~ - -Interface: `Hasable`_ - -implode -~~~~~~~ - -Interface: `Implodeable`_ - -nullsy -~~~~~~ - -Interface: `Nullsyable`_ - -reduce -~~~~~~ - -Interface: `Reduceable`_ - -run -~~~ - -Interface: `Runable`_ - -transform -~~~~~~~~~ - -Interface: `Transformable`_ - -truthy -~~~~~~ - -Interface: `Truthyable`_ - -.. _Allable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/Allable.php +.. _Allable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Allable.php .. _Appendable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Appendable.php .. _Applyable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Applyable.php .. _Associateable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Associateable.php @@ -1528,28 +1512,28 @@ Interface: `Truthyable`_ .. _Combinateable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Combinateable.php .. _Combineable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Combineable.php .. _Compactable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Compactable.php -.. _Containsable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/Containsable.php +.. _Containsable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Containsable.php .. _Cycleable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Cycleable.php .. _Diffable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Diffable.php .. _Diffkeysable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Diffkeysable.php .. _Distinctable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Distinctable.php .. _Explodeable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Explodeable.php -.. _Falsyable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/Falsyable.php +.. _Falsyable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Falsyable.php .. _Filterable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Filterable.php .. _Firstable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Firstable.php .. _Flattenable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Flattenable.php .. _Flipable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Flipable.php .. _array_flip(): https://php.net/array_flip -.. _FoldLeftable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/FoldLeftable.php -.. _FoldRightable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/FoldRightable.php +.. _FoldLeftable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/FoldLeftable.php +.. _FoldRightable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/FoldRightable.php .. _Forgetable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Forgetable.php .. _Frequencyable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Frequencyable.php -.. _Getable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/Getable.php +.. _Getable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Getable.php .. _Groupable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Groupable.php -.. _Hasable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/Hasable.php +.. _Hasable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Hasable.php .. _Headable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Headable.php .. _IfThenElseable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/IfThenElseable.php -.. _Implodeable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/Implodeable.php +.. _Implodeable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Implodeable.php .. _Intersectable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Intersectable.php .. _Intersectkeysable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Intersectkeysable.php .. _Intersperseable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Intersperseable.php @@ -1561,7 +1545,7 @@ Interface: `Truthyable`_ .. _Mergeable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Mergeable.php .. _Normalizeable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Normalizeable.php .. _Nthable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Nthable.php -.. _Nullsyable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/Nullsyable.php +.. _Nullsyable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Nullsyable.php .. _Onlyable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Onlyable.php .. _Packable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Packable.php .. _Padable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Padable.php @@ -1571,10 +1555,9 @@ Interface: `Truthyable`_ .. _Prependable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Prependable.php .. _Productable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Productable.php .. _Randomable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Randomable.php -.. _Reduceable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/Reduceable.php +.. _Reduceable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Reduceable.php .. _Reductionable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Reductionable.php .. _Reverseable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Reverseable.php -.. _Runable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/Runable.php .. _Scaleable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Scaleable.php .. _Skipable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Skipable.php .. _Sinceable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Sinceable.php @@ -1582,9 +1565,8 @@ Interface: `Truthyable`_ .. _Sortable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Sortable.php .. _Splitable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Splitable.php .. _Tailable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Tailable.php -.. _Transformable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/Transformable.php .. _Transposeable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Transposeable.php -.. _Truthyable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/Truthyable.php +.. _Truthyable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Truthyable.php .. _Unpackable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Unpackagle.php .. _Unpairable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Unpairable.php .. _Untilable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Untilable.php diff --git a/spec/loophp/collection/CollectionSpec.php b/spec/loophp/collection/CollectionSpec.php index c38a1883a..259385eac 100644 --- a/spec/loophp/collection/CollectionSpec.php +++ b/spec/loophp/collection/CollectionSpec.php @@ -13,7 +13,6 @@ use JsonSerializable; use loophp\collection\Collection; use loophp\collection\Contract\Operation; -use loophp\collection\Contract\Transformation; use loophp\collection\Operation\AbstractOperation; use PhpSpec\ObjectBehavior; use stdClass; @@ -238,17 +237,6 @@ public function it_can_be_json_encoded() $this ->shouldImplement(JsonSerializable::class); - - $this - ->transform( - new class() implements Transformation { - public function __invoke(Iterator $collection) - { - return '{"a":"A","b":"B","c":"C"}'; - } - } - ) - ->shouldReturn(json_encode($this->getWrappedObject())); } public function it_can_be_returned_as_an_array(): void @@ -1212,12 +1200,14 @@ public function it_can_intersperse(): void ->shouldIterateAs($generator()); $this::fromIterable(range('A', 'F')) + ->intersperse('foo', -1, 1) ->shouldThrow(Exception::class) - ->during('intersperse', ['foo', -1, 1]); + ->during('all'); $this::fromIterable(range('A', 'F')) + ->intersperse('foo', 1, -1) ->shouldThrow(Exception::class) - ->during('intersperse', ['foo', 1, -1]); + ->during('all'); } public function it_can_iterate(): void @@ -1673,7 +1663,7 @@ public function __invoke(): Closure }; $this::fromIterable(range(1, 5)) - ->run($square, $sqrt, $map) + ->run($square(), $sqrt(), $map()) ->shouldIterateAs(range(1, 5)); } @@ -2087,6 +2077,10 @@ public function it_can_use_times_with_a_callback(): void return range(1, 5); }) ->shouldIterateAs($a); + + $this::times(-1, 'count') + ->shouldThrow(InvalidArgumentException::class) + ->during('all'); } public function it_can_use_times_without_a_callback(): void @@ -2094,9 +2088,9 @@ public function it_can_use_times_without_a_callback(): void $this::times(10) ->shouldIterateAs(range(1, 10)); - $this::times(10) + $this::times(-5) ->shouldThrow(InvalidArgumentException::class) - ->during('times', [-5]); + ->during('all'); $this::times(1) ->shouldIterateAs([1]); diff --git a/src/Collection.php b/src/Collection.php index 36f3b20ae..2dbdc5b48 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -8,7 +8,6 @@ use Generator; use loophp\collection\Contract\Collection as CollectionInterface; use loophp\collection\Contract\Operation; -use loophp\collection\Contract\Transformation; use loophp\collection\Iterator\ClosureIterator; use loophp\collection\Iterator\IterableIterator; use loophp\collection\Iterator\ResourceIterator; @@ -23,20 +22,28 @@ use loophp\collection\Operation\Combinate; use loophp\collection\Operation\Combine; use loophp\collection\Operation\Compact; +use loophp\collection\Operation\Compose; +use loophp\collection\Operation\Contains; use loophp\collection\Operation\Cycle; use loophp\collection\Operation\Diff; use loophp\collection\Operation\DiffKeys; use loophp\collection\Operation\Distinct; use loophp\collection\Operation\Explode; +use loophp\collection\Operation\Falsy; use loophp\collection\Operation\Filter; use loophp\collection\Operation\First; use loophp\collection\Operation\Flatten; use loophp\collection\Operation\Flip; +use loophp\collection\Operation\FoldLeft; +use loophp\collection\Operation\FoldRight; use loophp\collection\Operation\Forget; use loophp\collection\Operation\Frequency; +use loophp\collection\Operation\Get; use loophp\collection\Operation\Group; +use loophp\collection\Operation\Has; use loophp\collection\Operation\Head; use loophp\collection\Operation\IfThenElse; +use loophp\collection\Operation\Implode; use loophp\collection\Operation\Intersect; use loophp\collection\Operation\IntersectKeys; use loophp\collection\Operation\Intersperse; @@ -49,6 +56,7 @@ use loophp\collection\Operation\Merge; use loophp\collection\Operation\Normalize; use loophp\collection\Operation\Nth; +use loophp\collection\Operation\Nullsy; use loophp\collection\Operation\Only; use loophp\collection\Operation\Pack; use loophp\collection\Operation\Pad; @@ -59,9 +67,11 @@ use loophp\collection\Operation\Product; use loophp\collection\Operation\Random; use loophp\collection\Operation\Range; +use loophp\collection\Operation\Reduce; use loophp\collection\Operation\Reduction; use loophp\collection\Operation\Reverse; use loophp\collection\Operation\RSample; +use loophp\collection\Operation\Run; use loophp\collection\Operation\Scale; use loophp\collection\Operation\Shuffle; use loophp\collection\Operation\Since; @@ -72,6 +82,7 @@ use loophp\collection\Operation\Tail; use loophp\collection\Operation\Times; use loophp\collection\Operation\Transpose; +use loophp\collection\Operation\Truthy; use loophp\collection\Operation\Unpack; use loophp\collection\Operation\Unpair; use loophp\collection\Operation\Until; @@ -79,20 +90,6 @@ use loophp\collection\Operation\Window; use loophp\collection\Operation\Wrap; use loophp\collection\Operation\Zip; -use loophp\collection\Transformation\All; -use loophp\collection\Transformation\Contains; -use loophp\collection\Transformation\Count; -use loophp\collection\Transformation\Falsy; -use loophp\collection\Transformation\FoldLeft; -use loophp\collection\Transformation\FoldRight; -use loophp\collection\Transformation\Get; -use loophp\collection\Transformation\Has; -use loophp\collection\Transformation\Implode; -use loophp\collection\Transformation\Nullsy; -use loophp\collection\Transformation\Reduce; -use loophp\collection\Transformation\Run; -use loophp\collection\Transformation\Transform; -use loophp\collection\Transformation\Truthy; use Psr\Cache\CacheItemPoolInterface; use Symfony\Component\Cache\Adapter\ArrayAdapter; @@ -120,7 +117,7 @@ final class Collection implements CollectionInterface /** * @var Closure - * @psalm-var Closure(Closure|callable|iterable|mixed|resource|scalar|T):(T) + * @psalm-var Closure((Closure|callable|iterable|mixed|resource|scalar|T)...):Generator */ private $source; @@ -226,89 +223,89 @@ static function ($data): Generator { public function all(): array { - return $this->transform(new All()); + return iterator_to_array($this); } public function append(...$items): CollectionInterface { - return $this->run(new Append(...$items)); + return $this->run(Append::of()(...$items)); } public function apply(callable ...$callables): CollectionInterface { - return $this->run(new Apply(...$callables)); + return $this->run(Apply::of()(...$callables)); } public function associate( ?callable $callbackForKeys = null, ?callable $callbackForValues = null ): CollectionInterface { - return $this->run(new Associate($callbackForKeys, $callbackForValues)); + return $this->run(Associate::of()($callbackForKeys)($callbackForValues)); } public function cache(?CacheItemPoolInterface $cache = null): CollectionInterface { - return $this->run(new Cache($cache ?? new ArrayAdapter())); + return $this->run(Cache::of()($cache ?? new ArrayAdapter())); } public function chunk(int ...$sizes): CollectionInterface { - return $this->run(new Chunk(...$sizes)); + return $this->run(Chunk::of()(...$sizes)); } public function collapse(): CollectionInterface { - return $this->run(new Collapse()); + return $this->run(Collapse::of()); } public function column($column): CollectionInterface { - return $this->run(new Column($column)); + return $this->run(Column::of()($column)); } public function combinate(?int $length = null): CollectionInterface { - return $this->run(new Combinate($length)); + return $this->run(Combinate::of()($length)); } public function combine(...$keys): CollectionInterface { - return $this->run(new Combine(...$keys)); + return $this->run(Combine::of()(...$keys)); } public function compact(...$values): CollectionInterface { - return $this->run(new Compact(...$values)); + return $this->run(Compact::of()(...$values)); } public function contains(...$value): bool { - return $this->transform(new Contains(...$value)); + return $this->run(Contains::of()(...$value))->getIterator()->current(); } public function count(): int { - return $this->transform(new Count()); + return iterator_count($this); } public function cycle(int $length = 0): CollectionInterface { - return $this->run(new Cycle($length)); + return $this->run(Cycle::of()($length)); } public function diff(...$values): CollectionInterface { - return $this->run(new Diff(...$values)); + return $this->run(Diff::of()(...$values)); } public function diffKeys(...$values): CollectionInterface { - return $this->run(new DiffKeys(...$values)); + return $this->run(DiffKeys::of()(...$values)); } public function distinct(): CollectionInterface { - return $this->run(new Distinct()); + return $this->run(Distinct::of()); } public static function empty(): Collection @@ -318,52 +315,52 @@ public static function empty(): Collection public function explode(...$explodes): CollectionInterface { - return $this->run(new Explode(...$explodes)); + return $this->run(Explode::of()(...$explodes)); } public function falsy(): bool { - return $this->transform(new Falsy()); + return $this->run(Falsy::of())->getIterator()->current(); } public function filter(callable ...$callbacks): CollectionInterface { - return $this->run(new Filter(...$callbacks)); + return $this->run(Filter::of()(...$callbacks)); } public function first(?callable $callback = null, int $size = 1): CollectionInterface { - return $this->run(new First($callback, $size)); + return $this->run(First::of()($callback)($size)); } public function flatten(int $depth = PHP_INT_MAX): CollectionInterface { - return $this->run(new Flatten($depth)); + return $this->run(Flatten::of()($depth)); } public function flip(): CollectionInterface { - return $this->run(new Flip()); + return $this->run(Flip::of()); } public function foldLeft(callable $callback, $initial = null) { - return $this->transform(new FoldLeft($callback, $initial)); + return $this->run(FoldLeft::of()($callback)($initial))->getIterator()->current(); } public function foldRight(callable $callback, $initial = null) { - return $this->transform(new FoldRight($callback, $initial)); + return $this->run(Foldright::of()($callback)($initial))->getIterator()->current(); } public function forget(...$keys): CollectionInterface { - return $this->run(new Forget(...$keys)); + return $this->run(Forget::of()(...$keys)); } public function frequency(): CollectionInterface { - return $this->run(new Frequency()); + return $this->run(Frequency::of()); } public static function fromCallable(callable $callable, ...$parameters): Collection @@ -390,6 +387,11 @@ static function (iterable $iterable): Generator { public static function fromResource($resource): Collection { return new self( + /** + * @psalm-param resource $resource + * + * @param mixed $resource + */ static function ($resource): Generator { return yield from new ResourceIterator($resource); }, @@ -400,6 +402,9 @@ static function ($resource): Generator { public static function fromString(string $string, string $delimiter = ''): Collection { return new self( + /** + * @psalm-return Generator + */ static function (string $string, string $delimiter): Generator { return yield from new StringIterator($string, $delimiter); }, @@ -410,7 +415,7 @@ static function (string $string, string $delimiter): Generator { public function get($key, $default = null) { - return $this->transform(new Get($key, $default)); + return $this->run(Get::of()($key)($default))->getIterator()->current(); } public function getIterator(): ClosureIterator @@ -420,51 +425,61 @@ public function getIterator(): ClosureIterator public function group(?callable $callable = null): CollectionInterface { - return $this->run(new Group($callable)); + return $this->run(Group::of()($callable)); } public function has(callable $callback): bool { - return $this->transform(new Has($callback)); + return $this->run(Has::of()($callback))->getIterator()->current(); } public function head(): CollectionInterface { - return $this->run(new Head()); + return $this->run(Head::of()); } public function ifThenElse(callable $condition, callable $then, ?callable $else = null): CollectionInterface { - $else = $else ?? static function ($value, $key) { - return $value; - }; + $else = $else ?? + /** + * @psalm-param T $value + * @psalm-param TKey $key + * + * @psalm-return T + * + * @param mixed $value + * @param mixed $key + */ + static function ($value, $key) { + return $value; + }; - return $this->run(new IfThenElse($condition, $then, $else)); + return $this->run(IfThenElse::of()($condition)($then)($else)); } public function implode(string $glue = ''): string { - return $this->transform(new Implode($glue)); + return $this->run(Implode::of()($glue))->getIterator()->current(); } public function intersect(...$values): CollectionInterface { - return $this->run(new Intersect(...$values)); + return $this->run(Intersect::of()(...$values)); } public function intersectKeys(...$values): CollectionInterface { - return $this->run(new IntersectKeys(...$values)); + return $this->run(IntersectKeys::of()(...$values)); } public function intersperse($element, int $every = 1, int $startAt = 0): CollectionInterface { - return $this->run(new Intersperse($element, $every, $startAt)); + return $this->run(Intersperse::of()($element)($every)($startAt)); } public static function iterate(callable $callback, ...$parameters): CollectionInterface { - return (new self())->run(new Iterate($callback, $parameters)); + return (new self())->run(Iterate::of()($callback)(...$parameters)); } /** @@ -477,122 +492,125 @@ public function jsonSerialize(): array public function keys(): CollectionInterface { - return $this->run(new Keys()); + return $this->run(Keys::of()); } public function last(?callable $callback = null, int $size = 1): CollectionInterface { - return $this->run(new Last($callback, $size)); + return $this->run(Last::of()($callback)($size)); } public function limit(int $limit = -1, int $offset = 0): CollectionInterface { - return $this->run(new Limit($limit, $offset)); + return $this->run(Limit::of()($limit)($offset)); } public function loop(): CollectionInterface { - return $this->run(new Loop()); + return $this->run(Loop::of()); } public function map(callable ...$callbacks): CollectionInterface { - return $this->run(new Map(...$callbacks)); + return $this->run(Map::of()(...$callbacks)); } public function merge(iterable ...$sources): CollectionInterface { - return $this->run(new Merge(...$sources)); + return $this->run(Merge::of()(...$sources)); } public function normalize(): CollectionInterface { - return $this->run(new Normalize()); + return $this->run(Normalize::of()); } public function nth(int $step, int $offset = 0): CollectionInterface { - return $this->run(new Nth($step, $offset)); + return $this->run(Nth::of()($step)($offset)); } public function nullsy(): bool { - return $this->transform(new Nullsy()); + return $this->run(Nullsy::of())->getIterator()->current(); } public function only(...$keys): CollectionInterface { - return $this->run(new Only(...$keys)); + return $this->run(Only::of()(...$keys)); } public function pack(): CollectionInterface { - return $this->run(new Pack()); + return $this->run(Pack::of()); } public function pad(int $size, $value): CollectionInterface { - return $this->run(new Pad($size, $value)); + return $this->run(Pad::of()($size)($value)); } public function pair(): CollectionInterface { - return $this->run(new Pair()); + return $this->run(Pair::of()); } public function permutate(): CollectionInterface { - return $this->run(new Permutate()); + return $this->run(Permutate::of()); } public function pluck($pluck, $default = null): CollectionInterface { - return $this->run(new Pluck($pluck, $default)); + return $this->run(Pluck::of()($pluck)($default)); } public function prepend(...$items): CollectionInterface { - return $this->run(new Prepend(...$items)); + return $this->run(Prepend::of()(...$items)); } public function product(iterable ...$iterables): CollectionInterface { - return $this->run(new Product(...$iterables)); + return $this->run(Product::of()(...$iterables)); } public function random(int $size = 1): CollectionInterface { - return $this->run(new Random($size)); + return $this->run(Random::of()($size)); } public static function range(float $start = 0.0, float $end = INF, float $step = 1.0): CollectionInterface { - return (new self())->run(new Range($start, $end, $step)); + return (new self())->run(Range::of()($start)($end)($step)); } public function reduce(callable $callback, $initial = null) { - return $this->transform(new Reduce($callback, $initial)); + return $this->run(Reduce::of()($callback)($initial))->getIterator()->current(); } public function reduction(callable $callback, $initial = null): CollectionInterface { - return $this->run(new Reduction($callback, $initial)); + return $this->run(Reduction::of()($callback)($initial)); } public function reverse(): CollectionInterface { - return $this->run(new Reverse()); + return $this->run(Reverse::of()); } public function rsample(float $probability): CollectionInterface { - return $this->run(new RSample($probability)); + return $this->run(RSample::of()($probability)); } - public function run(Operation ...$operations) + public function run(callable ...$operations): CollectionInterface { - return self::fromIterable((new Run(...$operations))($this->getIterator())); + return self::fromCallable( + Compose::of()(...$operations), + $this->getIterator() + ); } public function scale( @@ -602,87 +620,82 @@ public function scale( float $wantedUpperBound = 1.0, float $base = 0.0 ): CollectionInterface { - return $this->run(new Scale($lowerBound, $upperBound, $wantedLowerBound, $wantedUpperBound, $base)); + return $this->run(Scale::of()($lowerBound)($upperBound)($wantedLowerBound)($wantedUpperBound)($base)); } public function shuffle(): CollectionInterface { - return $this->run(new Shuffle()); + return $this->run(Shuffle::of()); } public function since(callable ...$callbacks): CollectionInterface { - return $this->run(new Since(...$callbacks)); + return $this->run(Since::of()(...$callbacks)); } public function skip(int ...$counts): CollectionInterface { - return $this->run(new Skip(...$counts)); + return $this->run(Skip::of()(...$counts)); } public function slice(int $offset, int $length = -1): CollectionInterface { - return $this->run(new Slice($offset, $length)); + return $this->run(Slice::of()($offset)($length)); } public function sort(int $type = Operation\Sortable::BY_VALUES, ?callable $callback = null): CollectionInterface { - return $this->run(new Sort($type, $callback)); + return $this->run(Sort::of()($type)($callback)); } public function split(callable ...$callbacks): CollectionInterface { - return $this->run(new Split(...$callbacks)); + return $this->run(Split::of()(...$callbacks)); } public function tail(): CollectionInterface { - return $this->run(new Tail()); + return $this->run(Tail::of()); } public static function times(int $number = 0, ?callable $callback = null): CollectionInterface { - return (new self())->run(new Times($number, $callback)); - } - - public function transform(Transformation ...$transformers) - { - return (new Transform(...$transformers))($this->getIterator()); + return (new self())->run(Times::of()($number)($callback)); } public function transpose(): CollectionInterface { - return $this->run(new Transpose()); + return $this->run(Transpose::of()); } public function truthy(): bool { - return $this->transform(new Truthy()); + return $this->run(Truthy::of())->getIterator()->current(); } public function unpack(): CollectionInterface { - return $this->run(new Unpack()); + return $this->run(Unpack::of()); } public function unpair(): CollectionInterface { - return $this->run(new Unpair()); + return $this->run(Unpair::of()); } public function until(callable ...$callbacks): CollectionInterface { - return $this->run(new Until(...$callbacks)); + return $this->run(Until::of()(...$callbacks)); } public function unwrap(): CollectionInterface { - return $this->run(new Unwrap()); + return $this->run(Unwrap::of()); } public function window(int ...$length): CollectionInterface { - return $this->run(new Window(...$length)); + return $this->run(Window::of()(...$length)); } public static function with($data = [], ...$parameters): Collection @@ -692,11 +705,11 @@ public static function with($data = [], ...$parameters): Collection public function wrap(): CollectionInterface { - return $this->run(new Wrap()); + return $this->run(Wrap::of()); } public function zip(iterable ...$iterables): CollectionInterface { - return $this->run(new Zip(...$iterables)); + return $this->run(Zip::of()(...$iterables)); } } diff --git a/src/Contract/Collection.php b/src/Contract/Collection.php index b8f59047f..ce4f11a4a 100644 --- a/src/Contract/Collection.php +++ b/src/Contract/Collection.php @@ -6,6 +6,7 @@ use IteratorAggregate; use JsonSerializable; +use loophp\collection\Contract\Operation\Allable; use loophp\collection\Contract\Operation\Appendable; use loophp\collection\Contract\Operation\Applyable; use loophp\collection\Contract\Operation\Associateable; @@ -16,20 +17,27 @@ use loophp\collection\Contract\Operation\Combinateable; use loophp\collection\Contract\Operation\Combineable; use loophp\collection\Contract\Operation\Compactable; +use loophp\collection\Contract\Operation\Containsable; use loophp\collection\Contract\Operation\Cycleable; use loophp\collection\Contract\Operation\Diffable; use loophp\collection\Contract\Operation\Diffkeysable; use loophp\collection\Contract\Operation\Distinctable; use loophp\collection\Contract\Operation\Explodeable; +use loophp\collection\Contract\Operation\Falsyable; use loophp\collection\Contract\Operation\Filterable; use loophp\collection\Contract\Operation\Firstable; use loophp\collection\Contract\Operation\Flattenable; use loophp\collection\Contract\Operation\Flipable; +use loophp\collection\Contract\Operation\FoldLeftable; +use loophp\collection\Contract\Operation\FoldRightable; use loophp\collection\Contract\Operation\Forgetable; use loophp\collection\Contract\Operation\Frequencyable; +use loophp\collection\Contract\Operation\Getable; use loophp\collection\Contract\Operation\Groupable; +use loophp\collection\Contract\Operation\Hasable; use loophp\collection\Contract\Operation\Headable; use loophp\collection\Contract\Operation\IfThenElseable; +use loophp\collection\Contract\Operation\Implodeable; use loophp\collection\Contract\Operation\Intersectable; use loophp\collection\Contract\Operation\Intersectkeysable; use loophp\collection\Contract\Operation\Intersperseable; @@ -42,6 +50,7 @@ use loophp\collection\Contract\Operation\Mergeable; use loophp\collection\Contract\Operation\Normalizeable; use loophp\collection\Contract\Operation\Nthable; +use loophp\collection\Contract\Operation\Nullsyable; use loophp\collection\Contract\Operation\Onlyable; use loophp\collection\Contract\Operation\Padable; use loophp\collection\Contract\Operation\Pairable; @@ -51,9 +60,11 @@ use loophp\collection\Contract\Operation\Productable; use loophp\collection\Contract\Operation\Randomable; use loophp\collection\Contract\Operation\Rangeable; +use loophp\collection\Contract\Operation\Reduceable; use loophp\collection\Contract\Operation\Reductionable; use loophp\collection\Contract\Operation\Reverseable; use loophp\collection\Contract\Operation\RSampleable; +use loophp\collection\Contract\Operation\Runable; use loophp\collection\Contract\Operation\Scaleable; use loophp\collection\Contract\Operation\Shuffleable; use loophp\collection\Contract\Operation\Sinceable; @@ -64,25 +75,14 @@ use loophp\collection\Contract\Operation\Tailable; use loophp\collection\Contract\Operation\Timesable; use loophp\collection\Contract\Operation\Transposeable; +use loophp\collection\Contract\Operation\Truthyable; use loophp\collection\Contract\Operation\Unpairable; use loophp\collection\Contract\Operation\Untilable; use loophp\collection\Contract\Operation\Unwrapable; use loophp\collection\Contract\Operation\Windowable; use loophp\collection\Contract\Operation\Wrapable; use loophp\collection\Contract\Operation\Zipable; -use loophp\collection\Contract\Transformation\Allable; -use loophp\collection\Contract\Transformation\Containsable; -use loophp\collection\Contract\Transformation\Falsyable; -use loophp\collection\Contract\Transformation\FoldLeftable; -use loophp\collection\Contract\Transformation\FoldRightable; -use loophp\collection\Contract\Transformation\Getable; -use loophp\collection\Contract\Transformation\Hasable; -use loophp\collection\Contract\Transformation\Implodeable; -use loophp\collection\Contract\Transformation\Nullsyable; -use loophp\collection\Contract\Transformation\Reduceable; -use loophp\collection\Contract\Transformation\Runable; -use loophp\collection\Contract\Transformation\Transformable; -use loophp\collection\Contract\Transformation\Truthyable; +use loophp\collection\Iterator\ClosureIterator; /** * @psalm-template TKey @@ -159,7 +159,6 @@ * @template-extends Zipable * @template-extends \IteratorAggregate * @template-extends Runable - * @template-extends Transformable */ interface Collection extends Allable, @@ -222,7 +221,6 @@ interface Collection extends Reductionable, Reverseable, RSampleable, - Runable, Scaleable, Shuffleable, Sinceable, @@ -232,7 +230,6 @@ interface Collection extends Splitable, Tailable, Timesable, - Transformable, Transposeable, Truthyable, Unpairable, @@ -277,25 +274,22 @@ public static function fromCallable(callable $callable, ...$parameters): \loophp public static function fromIterable(iterable $iterable): \loophp\collection\Collection; /** - * @psalm-template NewTKey - * @psalm-template NewTKey of array-key - * @psalm-template NewT - * * @param resource $resource * - * @psalm-return \loophp\collection\Collection + * @psalm-return \loophp\collection\Collection */ public static function fromResource($resource): \loophp\collection\Collection; /** - * @psalm-template NewTKey - * @psalm-template NewTKey of array-key - * @psalm-template NewT - * - * @psalm-return \loophp\collection\Collection + * @psalm-return \loophp\collection\Collection */ public static function fromString(string $string, string $delimiter = ''): \loophp\collection\Collection; + /** + * @psalm-return \loophp\collection\Iterator\ClosureIterator + */ + public function getIterator(): ClosureIterator; + /** * @psalm-template NewTKey * @psalm-template NewTKey of array-key diff --git a/src/Contract/Operation.php b/src/Contract/Operation.php index 102c419d7..5646618a3 100644 --- a/src/Contract/Operation.php +++ b/src/Contract/Operation.php @@ -10,8 +10,5 @@ interface Operation { public function __invoke(): Closure; - /** - * @return array - */ - public function getArguments(): array; + public static function of(): Closure; } diff --git a/src/Contract/Transformation/Allable.php b/src/Contract/Operation/Allable.php similarity index 86% rename from src/Contract/Transformation/Allable.php rename to src/Contract/Operation/Allable.php index e1db99e93..7b8a40c4b 100644 --- a/src/Contract/Transformation/Allable.php +++ b/src/Contract/Operation/Allable.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace loophp\collection\Contract\Transformation; +namespace loophp\collection\Contract\Operation; /** * @psalm-template TKey diff --git a/src/Contract/Transformation/Containsable.php b/src/Contract/Operation/Containsable.php similarity index 80% rename from src/Contract/Transformation/Containsable.php rename to src/Contract/Operation/Containsable.php index 4c1ccc3af..b78e7779b 100644 --- a/src/Contract/Transformation/Containsable.php +++ b/src/Contract/Operation/Containsable.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace loophp\collection\Contract\Transformation; +namespace loophp\collection\Contract\Operation; /** * @psalm-template T diff --git a/src/Contract/Transformation/Falsyable.php b/src/Contract/Operation/Falsyable.php similarity index 63% rename from src/Contract/Transformation/Falsyable.php rename to src/Contract/Operation/Falsyable.php index 93e5b4c3e..9e7ffd649 100644 --- a/src/Contract/Transformation/Falsyable.php +++ b/src/Contract/Operation/Falsyable.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace loophp\collection\Contract\Transformation; +namespace loophp\collection\Contract\Operation; interface Falsyable { diff --git a/src/Contract/Transformation/FoldLeftable.php b/src/Contract/Operation/FoldLeftable.php similarity index 88% rename from src/Contract/Transformation/FoldLeftable.php rename to src/Contract/Operation/FoldLeftable.php index 540d5833b..a4db77e6b 100644 --- a/src/Contract/Transformation/FoldLeftable.php +++ b/src/Contract/Operation/FoldLeftable.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace loophp\collection\Contract\Transformation; +namespace loophp\collection\Contract\Operation; /** * @psalm-template TKey diff --git a/src/Contract/Transformation/FoldRightable.php b/src/Contract/Operation/FoldRightable.php similarity index 88% rename from src/Contract/Transformation/FoldRightable.php rename to src/Contract/Operation/FoldRightable.php index ab534aade..2c78afab8 100644 --- a/src/Contract/Transformation/FoldRightable.php +++ b/src/Contract/Operation/FoldRightable.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace loophp\collection\Contract\Transformation; +namespace loophp\collection\Contract\Operation; /** * @psalm-template TKey diff --git a/src/Contract/Transformation/Getable.php b/src/Contract/Operation/Getable.php similarity index 89% rename from src/Contract/Transformation/Getable.php rename to src/Contract/Operation/Getable.php index ef497b4dc..d556d2900 100644 --- a/src/Contract/Transformation/Getable.php +++ b/src/Contract/Operation/Getable.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace loophp\collection\Contract\Transformation; +namespace loophp\collection\Contract\Operation; /** * @psalm-template TKey diff --git a/src/Contract/Transformation/Hasable.php b/src/Contract/Operation/Hasable.php similarity index 83% rename from src/Contract/Transformation/Hasable.php rename to src/Contract/Operation/Hasable.php index 6da78652a..b4804c26a 100644 --- a/src/Contract/Transformation/Hasable.php +++ b/src/Contract/Operation/Hasable.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace loophp\collection\Contract\Transformation; +namespace loophp\collection\Contract\Operation; /** * @psalm-template TKey diff --git a/src/Contract/Transformation/Implodeable.php b/src/Contract/Operation/Implodeable.php similarity index 68% rename from src/Contract/Transformation/Implodeable.php rename to src/Contract/Operation/Implodeable.php index ce0bf4d9a..d906ebfda 100644 --- a/src/Contract/Transformation/Implodeable.php +++ b/src/Contract/Operation/Implodeable.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace loophp\collection\Contract\Transformation; +namespace loophp\collection\Contract\Operation; interface Implodeable { diff --git a/src/Contract/Transformation/Nullsyable.php b/src/Contract/Operation/Nullsyable.php similarity index 64% rename from src/Contract/Transformation/Nullsyable.php rename to src/Contract/Operation/Nullsyable.php index 74cdf626e..214cb2d3e 100644 --- a/src/Contract/Transformation/Nullsyable.php +++ b/src/Contract/Operation/Nullsyable.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace loophp\collection\Contract\Transformation; +namespace loophp\collection\Contract\Operation; interface Nullsyable { diff --git a/src/Contract/Transformation/Reduceable.php b/src/Contract/Operation/Reduceable.php similarity index 88% rename from src/Contract/Transformation/Reduceable.php rename to src/Contract/Operation/Reduceable.php index e23432271..fdc294bdd 100644 --- a/src/Contract/Transformation/Reduceable.php +++ b/src/Contract/Operation/Reduceable.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace loophp\collection\Contract\Transformation; +namespace loophp\collection\Contract\Operation; /** * @psalm-template TKey diff --git a/src/Contract/Transformation/Truthyable.php b/src/Contract/Operation/Truthyable.php similarity index 64% rename from src/Contract/Transformation/Truthyable.php rename to src/Contract/Operation/Truthyable.php index ced83bad9..9d7f7b521 100644 --- a/src/Contract/Transformation/Truthyable.php +++ b/src/Contract/Operation/Truthyable.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace loophp\collection\Contract\Transformation; +namespace loophp\collection\Contract\Operation; interface Truthyable { diff --git a/src/Contract/Transformation.php b/src/Contract/Transformation.php deleted file mode 100644 index 1b92ae10d..000000000 --- a/src/Contract/Transformation.php +++ /dev/null @@ -1,24 +0,0 @@ - $collection - * @psalm-param \Iterator $collection - * - * @return mixed - * @psalm-return T|scalar|\Iterator|array|null - */ - public function __invoke(Iterator $collection); -} diff --git a/src/Contract/Transformation/Runable.php b/src/Contract/Transformation/Runable.php deleted file mode 100644 index dff0e8e32..000000000 --- a/src/Contract/Transformation/Runable.php +++ /dev/null @@ -1,20 +0,0 @@ - - */ - public function run(Operation ...$operations); -} diff --git a/src/Contract/Transformation/Transformable.php b/src/Contract/Transformation/Transformable.php deleted file mode 100644 index 0a70fb783..000000000 --- a/src/Contract/Transformation/Transformable.php +++ /dev/null @@ -1,23 +0,0 @@ - ...$transformers - * - * @return \loophp\collection\Iterator\ClosureIterator|mixed - */ - public function transform(Transformation ...$transformers); -} diff --git a/src/Iterator/StringIterator.php b/src/Iterator/StringIterator.php index 10c682294..5478d5d60 100644 --- a/src/Iterator/StringIterator.php +++ b/src/Iterator/StringIterator.php @@ -14,7 +14,7 @@ * @psalm-template T of string * * @extends ProxyIterator - * @implements \Iterator + * @implements Iterator */ final class StringIterator extends ProxyIterator implements Iterator, OuterIterator { @@ -22,7 +22,7 @@ public function __construct(string $data, string $delimiter = '') { $this->iterator = new ClosureIterator( /** - * @psalm-return \Generator + * @psalm-return Generator */ static function (string $input, string $delimiter): Generator { $offset = 0; diff --git a/src/Operation/AbstractOperation.php b/src/Operation/AbstractOperation.php index a9bf47445..5a3a781f5 100644 --- a/src/Operation/AbstractOperation.php +++ b/src/Operation/AbstractOperation.php @@ -4,18 +4,17 @@ namespace loophp\collection\Operation; -abstract class AbstractOperation +use Closure; +use loophp\collection\Contract\Operation; + +abstract class AbstractOperation implements Operation { - /** - * @var array - */ - protected $storage = []; + final public function __construct() + { + } - /** - * @return array - */ - public function getArguments(): array + public static function of(): Closure { - return $this->storage; + return (new static())->__invoke(); } } diff --git a/src/Operation/Append.php b/src/Operation/Append.php index 9a992dd4d..16aa1e261 100644 --- a/src/Operation/Append.php +++ b/src/Operation/Append.php @@ -17,31 +17,28 @@ final class Append extends AbstractOperation implements Operation { /** - * @param mixed ...$items - * @psalm-param T ...$items + * @psalm-return Closure(T...): Closure(Iterator): Generator */ - public function __construct(...$items) - { - $this->storage['items'] = $items; - } - public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * @psalm-param list $items - * - * @psalm-return Generator + * @psalm-param T ...$items */ - static function (Iterator $iterator, array $items): Generator { - foreach ($iterator as $key => $value) { - yield $key => $value; - } + static function (...$items): Closure { + return + /** + * @psalm-param Iterator $iterator + */ + static function (Iterator $iterator) use ($items): Generator { + foreach ($iterator as $key => $value) { + yield $key => $value; + } - foreach ($items as $key => $item) { - yield $key => $item; - } + foreach ($items as $key => $item) { + yield $key => $item; + } + }; }; } } diff --git a/src/Operation/Apply.php b/src/Operation/Apply.php index 88d40d3a8..e4bf5c5d7 100644 --- a/src/Operation/Apply.php +++ b/src/Operation/Apply.php @@ -17,36 +17,34 @@ final class Apply extends AbstractOperation implements Operation { /** - * @param callable ...$callbacks - * @psalm-param callable(T, TKey):(bool) ...$callbacks - */ - public function __construct(callable ...$callbacks) - { - $this->storage['callbacks'] = $callbacks; - } - - /** - * @psalm-return Closure(Iterator, list):(Generator) + * @psalm-return Closure((callable(T, TKey):(bool))...): Closure(Iterator): Generator */ public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * @psalm-param list $callbacks + * @psalm-param callable(T, TKey):(bool) ...$callbacks */ - static function (Iterator $iterator, array $callbacks): Generator { - foreach ($iterator as $key => $value) { - foreach ($callbacks as $callback) { - if (true === $callback($value, $key)) { - continue; - } + static function (callable ...$callbacks): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($callbacks): Generator { + foreach ($iterator as $key => $value) { + foreach ($callbacks as $callback) { + if (true === $callback($value, $key)) { + continue; + } - break; - } + break; + } - yield $key => $value; - } + yield $key => $value; + } + }; }; } } diff --git a/src/Operation/Associate.php b/src/Operation/Associate.php index 349552bbf..10b02fa89 100644 --- a/src/Operation/Associate.php +++ b/src/Operation/Associate.php @@ -17,36 +17,40 @@ final class Associate extends AbstractOperation implements Operation { /** - * @psalm-param null|callable(TKey, T):(TKey) $callbackForKeys - * @psalm-param null|callable(TKey, T):(T) $callbackForValues - */ - public function __construct(?callable $callbackForKeys = null, ?callable $callbackForValues = null) - { - $this->storage = [ - 'callbackForKeys' => $callbackForKeys ?? static function ($key, $value) { - return $key; - }, - 'callbackForValues' => $callbackForValues ?? static function ($key, $value) { - return $value; - }, - ]; - } - - /** - * @psalm-return Closure(Iterator, callable(TKey, T):(TKey), callable(TKey, T):(T)):(Generator) + * @psalm-return Closure(null|callable(TKey, T):(TKey)): Closure(null|callable(TKey, T):(T)): Generator */ public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * @psalm-param callable(TKey, T):(TKey) $callbackForKeys - * @psalm-param callable(TKey, T):(T) $callbackForValues + * @psalm-param null|callable(TKey, T):(TKey) $callbackForKeys */ - static function (Iterator $iterator, callable $callbackForKeys, callable $callbackForValues): Generator { - foreach ($iterator as $key => $value) { - yield $callbackForKeys($key, $value) => $callbackForValues($key, $value); - } + static function (?callable $callbackForKeys = null): Closure { + $callbackForKeys = $callbackForKeys ?? static function ($key, $value) { + return $key; + }; + + return + /** + * @psalm-param null|callable(TKey, T):(T) $callbackForValues + */ + static function (?callable $callbackForValues = null) use ($callbackForKeys): Closure { + $callbackForValues = $callbackForValues ?? static function ($key, $value) { + return $value; + }; + + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($callbackForKeys, $callbackForValues): Generator { + foreach ($iterator as $key => $value) { + yield $callbackForKeys($key, $value) => $callbackForValues($key, $value); + } + }; + }; }; } } diff --git a/src/Operation/Cache.php b/src/Operation/Cache.php index 43c6a1c69..85f0358da 100644 --- a/src/Operation/Cache.php +++ b/src/Operation/Cache.php @@ -18,21 +18,21 @@ */ final class Cache extends AbstractOperation implements Operation { - public function __construct(CacheItemPoolInterface $cache) - { - $this->storage['cache'] = $cache; - } - + /** + * @psalm-return Closure(CacheItemPoolInterface): Closure(Iterator): Generator + */ public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator - */ - static function (Iterator $iterator, CacheItemPoolInterface $cache): Generator { - return yield from new CacheIterator($iterator, $cache); - }; + return static function (CacheItemPoolInterface $cache): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($cache): Generator { + return yield from new CacheIterator($iterator, $cache); + }; + }; } } diff --git a/src/Operation/Chunk.php b/src/Operation/Chunk.php index 7e7983574..002ff7a81 100644 --- a/src/Operation/Chunk.php +++ b/src/Operation/Chunk.php @@ -9,7 +9,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; use function count; @@ -20,47 +19,48 @@ */ final class Chunk extends AbstractOperation implements Operation { - public function __construct(int ...$sizes) - { - $this->storage['sizes'] = new ArrayIterator($sizes); - } - /** - * @psalm-return Closure(Iterator, list):(Generator>) + * @psalm-return Closure(int...): Closure(Iterator): Generator> */ public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * @psalm-param ArrayIterator $sizes - * - * @psalm-return Generator> + * @psalm-param int ...$sizes */ - static function (Iterator $iterator, ArrayIterator $sizes): Generator { - $sizesIterator = (new Run(new Loop()))($sizes); + static function (int ...$sizes): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator> + */ + static function (Iterator $iterator) use ($sizes): Generator { + /** @psalm-var Iterator $sizesIterator */ + $sizesIterator = Loop::of()(new ArrayIterator($sizes)); - $values = []; + $values = []; - foreach ($iterator as $value) { - if (0 >= $sizesIterator->current()) { - return yield from []; - } + foreach ($iterator as $value) { + if (0 >= $sizesIterator->current()) { + return yield from []; + } - if (count($values) !== $sizesIterator->current()) { - $values[] = $value; + if (count($values) !== $sizesIterator->current()) { + $values[] = $value; - continue; - } + continue; + } - $sizesIterator->next(); + $sizesIterator->next(); - yield $values; + yield $values; - $values = [$value]; - } + $values = [$value]; + } - return yield $values; + return yield $values; + }; }; } } diff --git a/src/Operation/Collapse.php b/src/Operation/Collapse.php index a5eb37977..89495e02c 100644 --- a/src/Operation/Collapse.php +++ b/src/Operation/Collapse.php @@ -16,6 +16,9 @@ */ final class Collapse extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(Iterator): Generator + */ public function __invoke(): Closure { return diff --git a/src/Operation/Column.php b/src/Operation/Column.php index 5b1df8481..d6451864a 100644 --- a/src/Operation/Column.php +++ b/src/Operation/Column.php @@ -8,7 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -17,15 +16,6 @@ */ final class Column extends AbstractOperation implements Operation { - /** - * @param int|string $column - * @psalm-param array-key $column - */ - public function __construct($column) - { - $this->storage['column'] = $column; - } - /** * @psalm-return Closure(Iterator, array-key):(Generator>) */ @@ -33,23 +23,28 @@ public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * @psalm-param array-key $column + * @param int|string $column * - * @psalm-return Generator> - * - * @param mixed $column + * @psalm-param array-key $column */ - static function (Iterator $iterator, $column): Generator { - /** - * @psalm-var array-key $key - * @psalm-var iterable $value - */ - foreach ((new Run(new Transpose()))($iterator) as $key => $value) { - if ($key === $column) { - return yield from $value; - } - } + static function ($column): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator> + */ + static function (Iterator $iterator) use ($column): Generator { + /** + * @psalm-var array-key $key + * @psalm-var iterable $value + */ + foreach (Transpose::of()($iterator) as $key => $value) { + if ($key === $column) { + return yield from $value; + } + } + }; }; } } diff --git a/src/Operation/Combinate.php b/src/Operation/Combinate.php index 662c14c5f..815bb9943 100644 --- a/src/Operation/Combinate.php +++ b/src/Operation/Combinate.php @@ -19,65 +19,57 @@ */ final class Combinate extends AbstractOperation implements Operation { - public function __construct(?int $length = null) - { - $this->storage = [ - 'length' => $length, - 'getCombinations' => function (array $dataset, int $length): Generator { - return $this->getCombinations($dataset, $length); - }, - ]; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param callable(array, int): (array) $getCombinations - * - * @psalm-return Generator> - */ - static function (Iterator $iterator, ?int $length, callable $getCombinations): Generator { - $dataset = iterator_to_array($iterator); + return static function (?int $length = null): Closure { + $getCombinations = + /** + * @param array $dataset + * @psalm-param array $dataset + * + * @return Generator> + * @psalm-return Generator> + */ + static function (array $dataset, int $length) use (&$getCombinations): Generator { + for ($i = 0; count($dataset) - $length >= $i; ++$i) { + if (1 === $length) { + yield [$dataset[$i]]; - if (0 < $length) { - return yield from $getCombinations($dataset, $length); - } + continue; + } - $collectionSize = count($dataset); + /** @psalm-var array $permutation */ + foreach ($getCombinations(array_slice($dataset, $i + 1), $length - 1) as $permutation) { + array_unshift($permutation, $dataset[$i]); - if (0 === $length) { - return yield from $getCombinations($dataset, $collectionSize); - } + yield $permutation; + } + } + }; - for ($i = 1; $i <= $collectionSize; ++$i) { - yield from $getCombinations($dataset, $i); - } - }; - } + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator> + */ + static function (Iterator $iterator) use ($length, $getCombinations): Generator { + $dataset = iterator_to_array($iterator); - /** - * @param array $dataset - * @psalm-param array $dataset - * - * @return Generator> - * @psalm-return Generator> - */ - private function getCombinations(array $dataset, int $length): Generator - { - for ($i = 0; count($dataset) - $length >= $i; ++$i) { - if (1 === $length) { - yield [$dataset[$i]]; + if (0 < $length) { + return yield from $getCombinations($dataset, $length); + } - continue; - } + $collectionSize = count($dataset); - foreach ($this->getCombinations(array_slice($dataset, $i + 1), $length - 1) as $permutation) { - array_unshift($permutation, $dataset[$i]); + if (0 === $length) { + return yield from $getCombinations($dataset, $collectionSize); + } - yield $permutation; - } - } + for ($i = 1; $i <= $collectionSize; ++$i) { + yield from $getCombinations($dataset, $i); + } + }; + }; } } diff --git a/src/Operation/Combine.php b/src/Operation/Combine.php index 21c9e62f9..214ae4b5c 100644 --- a/src/Operation/Combine.php +++ b/src/Operation/Combine.php @@ -20,36 +20,37 @@ final class Combine extends AbstractOperation implements Operation { /** - * Combine constructor. - * - * @param mixed ...$keys - * @psalm-param TKey ...$keys + * @return Closure(T...): Closure(Iterator): Generator */ - public function __construct(...$keys) - { - $this->storage['keys'] = new ArrayIterator($keys); - } - public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * @psalm-param ArrayIterator $keys + * @psalm-param T ...$keys * - * @psalm-return Generator + * @psalm-return Closure(Iterator): Generator */ - static function (Iterator $iterator, ArrayIterator $keys): Generator { - while ($iterator->valid() && $keys->valid()) { - yield $keys->current() => $iterator->current(); - - $iterator->next(); - $keys->next(); - } - - if ($iterator->valid() !== $keys->valid()) { - trigger_error('Both keys and values must have the same amount of items.', E_USER_WARNING); - } + static function (...$keys): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-retur Generator + */ + static function (Iterator $iterator) use ($keys): Generator { + $keys = new ArrayIterator($keys); + + while ($iterator->valid() && $keys->valid()) { + yield $keys->current() => $iterator->current(); + + $iterator->next(); + $keys->next(); + } + + if ($iterator->valid() !== $keys->valid()) { + trigger_error('Both keys and values must have the same amount of items.', E_USER_WARNING); + } + }; }; } } diff --git a/src/Operation/Compact.php b/src/Operation/Compact.php index f02a6c3b7..fb25ef576 100644 --- a/src/Operation/Compact.php +++ b/src/Operation/Compact.php @@ -8,7 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; use function in_array; @@ -20,36 +19,36 @@ final class Compact extends AbstractOperation implements Operation { /** - * @param mixed ...$values - * @psalm-param T ...$values + * @psalm-return Closure(T...): Closure(Iterator): Generator */ - public function __construct(...$values) - { - $this->storage['values'] = [] === $values ? [null] : $values; - } - public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * @psalm-param list $values - * - * @psalm-return Generator + * @psalm-param T ...$values */ - static function (Iterator $iterator, array $values): Generator { - return yield from - (new Run( - new Filter( - /** - * @param mixed $item - */ - static function ($item) use ($values): bool { - return !in_array($item, $values, true); - } - ) - ) - )($iterator); + static function (...$values): Closure { + return + /** + * @psalm-param Iterator $iterator + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($values): Generator { + $values = [] === $values ? [null] : $values; + + /** @psalm-var callable(Iterator):Generator $filter */ + $filter = Filter::of()( + /** + * @param mixed $value + * @psalm-param T $value + */ + static function ($value) use ($values): bool { + return !in_array($value, $values, true); + } + ); + + return yield from $filter($iterator); + }; }; } } diff --git a/src/Operation/Compose.php b/src/Operation/Compose.php new file mode 100644 index 000000000..b8887f7c8 --- /dev/null +++ b/src/Operation/Compose.php @@ -0,0 +1,52 @@ +):Generator)...): Closure(Iterator): Generator + */ + // phpcs:enable + public function __invoke(): Closure + { + return + /** + * @psalm-param callable(Iterator): Generator ...$operations + */ + static function (callable ...$operations): Closure { + return + /** + * @psalm-param Iterator $iterator + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($operations): Generator { + $callback = + /** + * @psalm-param Iterator $iterator + * @psalm-param callable(Iterator): Generator $fn + * + * @psalm-return Generator + */ + static function (Iterator $iterator, callable $fn): Generator { + return $fn($iterator); + }; + + return yield from array_reduce($operations, $callback, $iterator); + }; + }; + } +} diff --git a/src/Operation/Contains.php b/src/Operation/Contains.php new file mode 100644 index 000000000..6cd1d10cd --- /dev/null +++ b/src/Operation/Contains.php @@ -0,0 +1,49 @@ + $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($values): Generator { + foreach ($iterator as $key => $value) { + foreach ($values as $k => $v) { + if ($v === $value) { + unset($values[$k]); + } + + if ([] === $values) { + return yield true; + } + } + } + + return yield false; + }; + }; + } +} diff --git a/src/Operation/Cycle.php b/src/Operation/Cycle.php index 99d1bad71..7a707c9e2 100644 --- a/src/Operation/Cycle.php +++ b/src/Operation/Cycle.php @@ -18,29 +18,29 @@ */ final class Cycle extends AbstractOperation implements Operation { - public function __construct(int $length) - { - $this->storage['length'] = $length; - } - + /** + * @psalm-return Closure(int): Closure(Iterator): Generator + */ public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator - */ - static function (Iterator $iterator, int $length): Generator { - if (0 === $length) { - return yield from []; - } + return static function (int $length): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($length): Generator { + if (0 === $length) { + return yield from []; + } - return yield from new LimitIterator( - new InfiniteIterator($iterator), - 0, - $length - ); - }; + return yield from new LimitIterator( + new InfiniteIterator($iterator), + 0, + $length + ); + }; + }; } } diff --git a/src/Operation/Diff.php b/src/Operation/Diff.php index c1b364869..cdd147f3f 100644 --- a/src/Operation/Diff.php +++ b/src/Operation/Diff.php @@ -19,29 +19,28 @@ final class Diff extends AbstractOperation implements Operation { /** - * @param mixed ...$values - * @psalm-param T ...$values + * @psalm-return Closure(T...): Closure(Iterator): Generator */ - public function __construct(...$values) - { - $this->storage['values'] = $values; - } - public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * @psalm-param list $values - * - * @psalm-return Generator + * @psalm-param T ...$values */ - static function (Iterator $iterator, array $values): Generator { - foreach ($iterator as $key => $value) { - if (false === in_array($value, $values, true)) { - yield $key => $value; - } - } + static function (...$values): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($values): Generator { + foreach ($iterator as $key => $value) { + if (false === in_array($value, $values, true)) { + yield $key => $value; + } + } + }; }; } } diff --git a/src/Operation/DiffKeys.php b/src/Operation/DiffKeys.php index ea9e21bb0..096a3b1fe 100644 --- a/src/Operation/DiffKeys.php +++ b/src/Operation/DiffKeys.php @@ -19,31 +19,26 @@ final class DiffKeys extends AbstractOperation implements Operation { /** - * @param mixed ...$values - * @psalm-param TKey ...$values + * @psalm-return Closure(TKey...): Closure(Iterator): Generator */ - public function __construct(...$values) - { - $this->storage['values'] = $values; - } - public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * @psalm-param list $values - * - * @psalm-return Generator - * - * @param mixed $values + * @psalm-param T ...$values */ - static function (Iterator $iterator, array $values): Generator { - foreach ($iterator as $key => $value) { - if (false === in_array($key, $values, true)) { - yield $key => $value; - } - } + static function (...$values): Closure { + return + /** + * @psalm-param Iterator $iterator + */ + static function (Iterator $iterator) use ($values): Generator { + foreach ($iterator as $key => $value) { + if (false === in_array($key, $values, true)) { + yield $key => $value; + } + } + }; }; } } diff --git a/src/Operation/Distinct.php b/src/Operation/Distinct.php index 4dfdb84c6..0d9b1d38d 100644 --- a/src/Operation/Distinct.php +++ b/src/Operation/Distinct.php @@ -18,6 +18,9 @@ */ final class Distinct extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(Iterator): Generator + */ public function __invoke(): Closure { return diff --git a/src/Operation/Explode.php b/src/Operation/Explode.php index 7cb2f6123..1f58eb7d6 100644 --- a/src/Operation/Explode.php +++ b/src/Operation/Explode.php @@ -8,7 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -17,46 +16,40 @@ */ final class Explode extends AbstractOperation implements Operation { - /** - * @param mixed ...$explodes - * @psalm-param T ...$explodes - */ - public function __construct(...$explodes) - { - $this->storage['explodes'] = $explodes; - } - public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * @psalm-param list $explodes - * - * @psalm-return Generator> + * @psalm-param T ...$explodes */ - static function (Iterator $iterator, array $explodes): Generator { - return yield from (new Run( - new Split( - ...array_map( - /** - * @param mixed $explode - * @psalm-param T $explode - */ - static function ($explode): Closure { - return - /** - * @param mixed $value - * @psalm-param T $value - */ - static function ($value) use ($explode): bool { - return $value === $explode; - }; - }, - $explodes - ) - ) - ))($iterator); + static function (...$explodes): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator> + */ + static function (Iterator $iterator) use ($explodes): Generator { + return yield from Split::of()( + ...array_map( + /** + * @param mixed $explode + * @psalm-param T $explode + */ + static function ($explode): Closure { + return + /** + * @param mixed $value + * @psalm-param T $value + */ + static function ($value) use ($explode): bool { + return $value === $explode; + }; + }, + $explodes + ) + )($iterator); + }; }; } } diff --git a/src/Operation/Falsy.php b/src/Operation/Falsy.php new file mode 100644 index 000000000..a8d3d0fbe --- /dev/null +++ b/src/Operation/Falsy.php @@ -0,0 +1,39 @@ +): Generator + */ + public function __invoke(): Closure + { + return + /** + * @psalm-param Iterator $iterator + * @psalm-return Generator $iterator + */ + static function (Iterator $iterator): Generator { + foreach ($iterator as $key => $value) { + if (false !== (bool) $value) { + return yield false; + } + } + + return yield true; + }; + } +} diff --git a/src/Operation/Filter.php b/src/Operation/Filter.php index cef23d1f1..baea1c623 100644 --- a/src/Operation/Filter.php +++ b/src/Operation/Filter.php @@ -17,42 +17,48 @@ */ final class Filter extends AbstractOperation implements Operation { - public function __construct(callable ...$callbacks) - { - $defaultCallback = - /** - * @param mixed $value - * @param mixed $key - * @psalm-param T $value - * @psalm-param TKey $key - * @psalm-param Iterator $iterator - */ - static function ($value, $key, Iterator $iterator): bool { - return (bool) $value; - }; - - $this->storage['callbacks'] = [] === $callbacks ? - [$defaultCallback] : - $callbacks; - } - + // phpcs:disable + /** + * @psalm-return Closure((callable(T, TKey, Iterator): bool)...): Closure(Iterator): Generator + */ + // phpcs:enable public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * @psalm-param list):(bool)> $callbacks - * - * @psalm-return Generator + * @psalm-param callable(T, TKey, Iterator): bool ...$callbacks */ - static function (Iterator $iterator, array $callbacks): Generator { - return yield from array_reduce( - $callbacks, - static function (Iterator $carry, callable $callback): CallbackFilterIterator { - return new CallbackFilterIterator($carry, $callback); - }, - $iterator - ); + static function (callable ...$callbacks): Closure { + return + /** + * @psalm-param Iterator $iterator + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($callbacks): Generator { + $defaultCallback = + /** + * @param mixed $value + * @param mixed $key + * @psalm-param T $value + * @psalm-param TKey $key + * @psalm-param Iterator $iterator + */ + static function ($value, $key, Iterator $iterator): bool { + return (bool) $value; + }; + + $callbacks = [] === $callbacks ? + [$defaultCallback] : + $callbacks; + + return yield from array_reduce( + $callbacks, + static function (Iterator $carry, callable $callback): CallbackFilterIterator { + return new CallbackFilterIterator($carry, $callback); + }, + $iterator + ); + }; }; } } diff --git a/src/Operation/First.php b/src/Operation/First.php index e352feb4f..33bf3da64 100644 --- a/src/Operation/First.php +++ b/src/Operation/First.php @@ -8,70 +8,47 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey * @psalm-template TKey of array-key * @psalm-template T - * - * @implements Operation */ final class First extends AbstractOperation implements Operation { - /** - * @var callable - * @psalm-var callable(T, TKey):(bool) - */ - private $callback; - - /** - * @psalm-param callable(T, TKey):(bool)|null $callback - * - * @psalm-param T|null $default - */ - public function __construct(?callable $callback = null, int $size = 1) - { - $defaultCallback = - /** - * @param mixed $value - * @param mixed $key - * @psalm-param T $value - * @psalm-param TKey $key - * @psalm-param Iterator $iterator - */ - static function ($value, $key, Iterator $iterator): bool { - return true; - }; - - $this->storage = [ - 'callback' => $callback ?? $defaultCallback, - 'size' => $size, - ]; - } - public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator + * @psalm-param callable(T, TKey):(bool)|null $callback */ - static function (Iterator $iterator, callable $callback, int $size): Generator { - $callback = + static function (?callable $callback = null): Closure { + return static function (int $size = 1) use ($callback): Closure { + return /** - * @param mixed $value - * @param mixed $key - * @psalm-param T $value - * @psalm-param TKey $key * @psalm-param Iterator $iterator */ - static function ($value, $key, Iterator $iterator) use ($callback): bool { - return true === $callback($value, $key, $iterator); + static function (Iterator $iterator) use ($callback, $size): Generator { + $defaultCallback = + /** + * @param mixed $value + * @param mixed $key + * @psalm-param T $value + * @psalm-param TKey $key + * @psalm-param Iterator $iterator + */ + static function ($value, $key, Iterator $iterator): bool { + return true; + }; + + $callback = $callback ?? $defaultCallback; + + return yield from Compose::of()( + Filter::of()($callback), + Limit::of()($size)(0) + )($iterator); }; - - return yield from (new Run(new Filter($callback), new Limit($size)))($iterator); + }; }; } } diff --git a/src/Operation/Flatten.php b/src/Operation/Flatten.php index 5b45e73b0..d6eb7b63a 100644 --- a/src/Operation/Flatten.php +++ b/src/Operation/Flatten.php @@ -9,7 +9,6 @@ use Iterator; use loophp\collection\Contract\Operation; use loophp\collection\Iterator\IterableIterator; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -18,37 +17,42 @@ */ final class Flatten extends AbstractOperation implements Operation { - public function __construct(int $depth) - { - $this->storage['depth'] = $depth; - } - + /** + * @psalm-return Closure(int): Closure(Iterator): Generator + */ public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator - */ - static function (Iterator $iterator, int $depth): Generator { - foreach ($iterator as $key => $value) { - if (false === is_iterable($value)) { - yield $key => $value; - } elseif (1 === $depth) { - /** @psalm-var T $subValue */ - foreach ($value as $subKey => $subValue) { - yield $subKey => $subValue; - } - } else { - /** @psalm-var IterableIterator $iterable */ - $iterable = (new Run(new Flatten($depth - 1)))(new IterableIterator($value)); + return static function (int $depth): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($depth): Generator { + foreach ($iterator as $key => $value) { + if (false === is_iterable($value)) { + yield $key => $value; + } elseif (1 === $depth) { + /** @psalm-var TKey $subKey */ + /** @psalm-var T $subValue */ + foreach ($value as $subKey => $subValue) { + yield $subKey => $subValue; + } + } else { + /** @psalm-var callable(Iterator): Generator $flatten */ + $flatten = Flatten::of()($depth - 1); - foreach ($iterable as $subKey => $subValue) { - yield $subKey => $subValue; + /** + * @psalm-var TKey $subKey + * @psalm-var T $subValue + */ + foreach ($flatten(new IterableIterator($value)) as $subKey => $subValue) { + yield $subKey => $subValue; + } } } - } - }; + }; + }; } } diff --git a/src/Operation/FoldLeft.php b/src/Operation/FoldLeft.php new file mode 100644 index 000000000..2af8b323a --- /dev/null +++ b/src/Operation/FoldLeft.php @@ -0,0 +1,54 @@ +): T): Closure(T|null): Closure(Iterator): T|null + */ + // phpcs:enable + public function __invoke(): Closure + { + return + /** + * @psalm-param callable(T|null, T, TKey, Iterator): T + */ + static function (callable $callback): Closure { + return + /** + * @psalm-param T|null $initial + * + * @param mixed|null $initial + */ + static function ($initial = null) use ($callback): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($callback, $initial): Generator { + foreach ($iterator as $key => $value) { + $initial = $callback($initial, $value, $key, $iterator); + } + + return yield $initial; + }; + }; + }; + } +} diff --git a/src/Operation/FoldRight.php b/src/Operation/FoldRight.php new file mode 100644 index 000000000..f09a4f381 --- /dev/null +++ b/src/Operation/FoldRight.php @@ -0,0 +1,55 @@ +): T): Closure(T|null): Closure(Iterator): T|null + */ + // phpcs:enable + public function __invoke(): Closure + { + return + /** + * @psalm-param callable(T|null, T, TKey, Iterator): T + */ + static function (callable $callback): Closure { + return + /** + * @param mixed|null $initial + * @psalm-param T|null $initial + */ + static function ($initial = null) use ($callback): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($callback, $initial): Generator { + /** @psalm-var callable(Iterator): Generator $foldRight */ + $foldRight = Compose::of()( + Reverse::of(), + FoldLeft::of()($callback)($initial) + ); + + return yield from $foldRight($iterator); + }; + }; + }; + } +} diff --git a/src/Operation/Forget.php b/src/Operation/Forget.php index 32cd3cc9e..1268f4054 100644 --- a/src/Operation/Forget.php +++ b/src/Operation/Forget.php @@ -19,31 +19,30 @@ final class Forget extends AbstractOperation implements Operation { /** - * @param mixed ...$keys - * @psalm-param TKey ...$keys + * @psalm-return Closure(TKey...): Closure(Iterator): Generator */ - public function __construct(...$keys) - { - $this->storage['keys'] = $keys; - } - public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * @psalm-param list $keys - * - * @psalm-return Generator + * @psalm-param TKey ...$keys */ - static function (Iterator $iterator, array $keys): Generator { - $keys = array_flip($keys); + static function (...$keys): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($keys): Generator { + $keys = array_flip($keys); - foreach ($iterator as $key => $value) { - if (false === array_key_exists($key, $keys)) { - yield $key => $value; - } - } + foreach ($iterator as $key => $value) { + if (false === array_key_exists($key, $keys)) { + yield $key => $value; + } + } + }; }; } } diff --git a/src/Operation/Get.php b/src/Operation/Get.php new file mode 100644 index 000000000..59579f0b0 --- /dev/null +++ b/src/Operation/Get.php @@ -0,0 +1,53 @@ + $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($keyToGet, $default): Generator { + foreach ($iterator as $key => $value) { + if ($key === $keyToGet) { + return yield $value; + } + } + + return yield $default; + }; + }; + }; + } +} diff --git a/src/Operation/Group.php b/src/Operation/Group.php index b834c298d..cdae76aea 100644 --- a/src/Operation/Group.php +++ b/src/Operation/Group.php @@ -8,8 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\FoldLeft; -use loophp\collection\Transformation\Transform; /** * @psalm-template TKey @@ -18,57 +16,65 @@ */ final class Group extends AbstractOperation implements Operation { - public function __construct(?callable $callable = null) - { - $this->storage['callable'] = $callable ?? - /** - * @param mixed $key - * @psalm-param TKey $key - * - * @param mixed $value - * @psalm-param T $value - * - * @return mixed - * @psalm-return TKey - */ - static function ($value, $key) { - return $key; - }; - } - + /** + * @psalm-return Closure(null|callable(TKey, T):(TKey)): Closure(Iterator): Generator> + */ public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * @psalm-param callable(TKey, T):(TKey) $callable - * - * @psalm-return Generator> + * @psalm-param null|callable(TKey, T):(T|TKey) $callable */ - static function (Iterator $iterator, callable $callable): Generator { - $callback = + static function (?callable $callable = null): Closure { + return /** - * @psalm-param array> $collect + * @psalm-param Iterator $iterator * - * @param mixed $value - * @psalm-param T $value - * - * @param mixed $key - * @psalm-param TKey $key - * - * @psalm-return array> + * @psalm-return Generator> */ - static function (array $collect, $value, $key) use ($callable): array { - if (null !== $groupKey = $callable($value, $key)) { - $collect[$groupKey][] = $value; - } else { - $collect[$key] = $value; - } + static function (Iterator $iterator) use ($callable): Generator { + $callable = $callable ?? + /** + * @param mixed $key + * @psalm-param TKey $key + * + * @param mixed $value + * @psalm-param T $value + * + * @return mixed + * @psalm-return TKey + */ + static function ($value, $key) { + return $key; + }; - return $collect; - }; + $callback = + /** + * @psalm-param array> $collect + * + * @param mixed $value + * @psalm-param T $value + * + * @param mixed $key + * @psalm-param TKey $key + * + * @psalm-return array> + */ + static function (array $collect, $value, $key) use ($callable): array { + if (null !== $groupKey = $callable($value, $key)) { + $collect[$groupKey][] = $value; + } else { + $collect[$key] = $value; + } - return yield from (new Transform(new FoldLeft($callback, [])))($iterator); + return $collect; + }; + + /** @psalm-var callable(Iterator): Generator $foldLeft */ + $foldLeft = FoldLeft::of()($callback)([]); + + return yield from ($foldLeft($iterator))->current(); + }; }; } } diff --git a/src/Operation/Has.php b/src/Operation/Has.php new file mode 100644 index 000000000..519261cae --- /dev/null +++ b/src/Operation/Has.php @@ -0,0 +1,45 @@ +): bool + */ + public function __invoke(): Closure + { + return + /** + * @psalm-param callable(TKey, T):(bool) $callback + */ + static function (callable $callback): Closure { + return + /** + * @psalm-param Iterator $iterator + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($callback): Generator { + foreach ($iterator as $key => $value) { + if ($callback($key, $value) === $value) { + return yield true; + } + } + + return yield false; + }; + }; + } +} diff --git a/src/Operation/IfThenElse.php b/src/Operation/IfThenElse.php index fbce20e58..eb8e70cfb 100644 --- a/src/Operation/IfThenElse.php +++ b/src/Operation/IfThenElse.php @@ -16,33 +16,43 @@ */ final class IfThenElse extends AbstractOperation implements Operation { - /** - * @psalm-param callable(T, TKey): bool $condition - * @psalm-param callable(T, TKey): (T|TKey) $then - * @psalm-param callable(T, TKey): (T|TKey) $else - */ - public function __construct(callable $condition, callable $then, callable $else) - { - $this->storage = [ - 'condition' => $condition, - 'then' => $then, - 'else' => $else, - ]; - } - // phpcs:disable /** - * @psalm-return Closure(Iterator, callable(T, TKey): bool, callable(T, TKey): (T|TKey), callable(T, TKey): (T|TKey)): Generator + * @psalm-return Closure(callable(T, TKey): bool): Closure(callable(T, TKey): (T)): Closure(callable(T, TKey): (T)): Generator */ // phpcs:enable public function __invoke(): Closure { - return static function (Iterator $iterator, callable $condition, callable $then, callable $else): Generator { - foreach ($iterator as $key => $value) { - yield $key => $condition($value, $key) ? - $then($value, $key) : - $else($value, $key); - } - }; + return + /** + * @psalm-param callable(T, TKey): bool $condition + */ + static function (callable $condition): Closure { + return + /** + * @psalm-param callable(T, TKey): (T) $then + */ + static function (callable $then) use ($condition): Closure { + return + /** + * @psalm-param callable(T, TKey): (T) $else + */ + static function (callable $else) use ($condition, $then): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($condition, $then, $else): Generator { + foreach ($iterator as $key => $value) { + yield $key => $condition($value, $key) ? + $then($value, $key) : + $else($value, $key); + } + }; + }; + }; + }; } } diff --git a/src/Operation/Implode.php b/src/Operation/Implode.php new file mode 100644 index 000000000..4a1d830a4 --- /dev/null +++ b/src/Operation/Implode.php @@ -0,0 +1,46 @@ +hasNext()) { + $carry .= $glue; + } + + return $carry; + }; + + return yield from FoldLeft::of()($callback)('')(new CachingIterator($iterator)); + }; + }; + } +} diff --git a/src/Operation/Intersect.php b/src/Operation/Intersect.php index e64ccb3a0..38e173682 100644 --- a/src/Operation/Intersect.php +++ b/src/Operation/Intersect.php @@ -19,31 +19,30 @@ final class Intersect extends AbstractOperation implements Operation { /** - * @param mixed ...$values - * @psalm-param T ...$values + * @psalm-return Closure(T...): Closure(Iterator): Generator */ - public function __construct(...$values) - { - $this->storage['values'] = $values; - } - public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * @psalm-param list $values - * - * @psalm-return Generator + * @psalm-param T ...$values */ - static function (Iterator $iterator, array $values): Generator { - foreach ($iterator as $key => $value) { - if (false === in_array($value, $values, true)) { - continue; - } + static function (...$values): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($values): Generator { + foreach ($iterator as $key => $value) { + if (false === in_array($value, $values, true)) { + continue; + } - yield $key => $value; - } + yield $key => $value; + } + }; }; } } diff --git a/src/Operation/IntersectKeys.php b/src/Operation/IntersectKeys.php index 3188fc1a9..7ef16770c 100644 --- a/src/Operation/IntersectKeys.php +++ b/src/Operation/IntersectKeys.php @@ -19,33 +19,30 @@ final class IntersectKeys extends AbstractOperation implements Operation { /** - * @param mixed ...$values - * @psalm-param TKey ...$values + * @psalm-return Closure(TKey...): Closure(Iterator): Generator */ - public function __construct(...$values) - { - $this->storage['values'] = $values; - } - public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * @psalm-param list $values - * - * @psalm-return Generator - * - * @param mixed $values + * @psalm-param TKey ...$values */ - static function (Iterator $iterator, array $values): Generator { - foreach ($iterator as $key => $value) { - if (false === in_array($key, $values, true)) { - continue; - } + static function (...$values): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($values): Generator { + foreach ($iterator as $key => $value) { + if (false === in_array($key, $values, true)) { + continue; + } - yield $key => $value; - } + yield $key => $value; + } + }; }; } } diff --git a/src/Operation/Intersperse.php b/src/Operation/Intersperse.php index f22e92544..86a4b2c88 100644 --- a/src/Operation/Intersperse.php +++ b/src/Operation/Intersperse.php @@ -11,11 +11,6 @@ use loophp\collection\Contract\Operation; /** - * Class Intersperse. - * - * Insert a given value between each element of a collection. - * Indices are not preserved. - * * @psalm-template TKey * @psalm-template TKey of array-key * @psalm-template T @@ -23,45 +18,48 @@ final class Intersperse extends AbstractOperation implements Operation { /** - * @param mixed $element - * @psalm-param T $element + * @psalm-return Closure(T): Closure(int): Closure(int): Closure(Iterator): Generator */ - public function __construct($element, int $atEvery, int $startAt) - { - if (0 > $atEvery) { - throw new InvalidArgumentException('The second parameter must be a positive integer.'); - } - - if (0 > $startAt) { - throw new InvalidArgumentException('The third parameter must be a positive integer.'); - } - - $this->storage = [ - 'element' => $element, - 'atEvery' => $atEvery, - 'startAt' => $startAt, - ]; - } - public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * - * @param mixed $element * @psalm-param T $element * - * @psalm-return Generator + * @param mixed $element */ - static function (Iterator $iterator, $element, int $every, int $startAt): Generator { - foreach ($iterator as $key => $value) { - if (0 === $startAt++ % $every) { - yield $element; - } + static function ($element): Closure { + return static function (int $atEvery) use ($element): Closure { + return static function (int $startAt) use ($element, $atEvery): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($element, $atEvery, $startAt): Generator { + if (0 > $atEvery) { + throw new InvalidArgumentException( + 'The second parameter must be a positive integer.' + ); + } + + if (0 > $startAt) { + throw new InvalidArgumentException( + 'The third parameter must be a positive integer.' + ); + } + + foreach ($iterator as $key => $value) { + if (0 === $startAt++ % $atEvery) { + yield $element; + } - yield $key => $value; - } + yield $key => $value; + } + }; + }; + }; }; } } diff --git a/src/Operation/Iterate.php b/src/Operation/Iterate.php index 2bdd4738a..3bed2512c 100644 --- a/src/Operation/Iterate.php +++ b/src/Operation/Iterate.php @@ -17,35 +17,34 @@ final class Iterate extends AbstractOperation implements Operation { /** - * @param array $parameters - * @psalm-param array $parameters - * - * @psalm-param callable(...list):(array) $callback + * @psalm-return Closure(callable(T...):(array)): Closure(T...): Generator */ - public function __construct(callable $callback, array $parameters = []) - { - $this->storage = [ - 'callback' => $callback, - 'parameters' => $parameters, - ]; - } - public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * @psalm-param callable(...list):(array) $callback - * - * @param array $parameters - * @psalm-param array $parameters + * @psalm-param callable(T...):(array) $callback */ - static function (Iterator $iterator, callable $callback, array $parameters): Generator { - while (true) { - yield current( - $parameters = (array) $callback(...array_values((array) $parameters)) - ); - } + static function (callable $callback): Closure { + return + /** + * @psalm-param T ...$parameters + */ + static function (...$parameters) use ($callback): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($callback, $parameters): Generator { + while (true) { + yield current( + $parameters = (array) $callback(...array_values((array) $parameters)) + ); + } + }; + }; }; } } diff --git a/src/Operation/Last.php b/src/Operation/Last.php index 4394b5573..193359e2f 100644 --- a/src/Operation/Last.php +++ b/src/Operation/Last.php @@ -8,7 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -17,58 +16,38 @@ */ final class Last extends AbstractOperation implements Operation { - /** - * @var callable|Closure - * @psalm-var callable(T, TKey):(bool)|Closure(T, TKey):(bool) - */ - private $callback; - - /** - * @psalm-param Closure(T, TKey):(bool)|callable(T, TKey):(bool)|null $callback - * @psalm-param T|null $default - */ - public function __construct(?callable $callback = null, int $size = 1) - { - $defaultCallback = - /** - * @param mixed $value - * @param mixed $key - * @psalm-param T $value - * @psalm-param TKey $key - * @psalm-param Iterator $iterator - */ - static function ($value, $key, Iterator $iterator): bool { - return true; - }; - - $this->storage = [ - 'callback' => $callback ?? $defaultCallback, - 'size' => $size, - ]; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator - */ - static function (Iterator $iterator, callable $callback, int $size): Generator { - $callback = + return static function (?callable $callback = null): Closure { + return static function (int $size) use ($callback): Closure { + return /** - * @param mixed $value - * @param mixed $key - * @psalm-param T $value - * @psalm-param TKey $key * @psalm-param Iterator $iterator + * + * @psalm-return Generator */ - static function ($value, $key, Iterator $iterator) use ($callback): bool { - return true === $callback($value, $key, $iterator); + static function (Iterator $iterator) use ($callback, $size): Generator { + $defaultCallback = + /** + * @param mixed $value + * @param mixed $key + * @psalm-param T $value + * @psalm-param TKey $key + * @psalm-param Iterator $iterator + */ + static function ($value, $key, Iterator $iterator): bool { + return true; + }; + + $callback = $callback ?? $defaultCallback; + + return yield from Compose::of()( + Filter::of()($callback), + Reverse::of(), + Limit::of()($size)(0) + )($iterator); }; - - return yield from (new Run(new Filter($callback), new Reverse(), new Limit($size)))($iterator); }; + }; } } diff --git a/src/Operation/Limit.php b/src/Operation/Limit.php index 9c625ecf4..175dec154 100644 --- a/src/Operation/Limit.php +++ b/src/Operation/Limit.php @@ -17,28 +17,27 @@ */ final class Limit extends AbstractOperation implements Operation { - public function __construct(int $limit, int $offset = 0) - { - $this->storage = [ - 'limit' => $limit, - 'offset' => $offset, - ]; - } - + /** + * @psalm-return Closure(int): Closure(int=): Closure(Iterator): Generator + */ public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator - */ - static function (Iterator $iterator, int $limit, int $offset): Generator { - if (0 === $limit) { - return yield from []; - } + return static function (int $limit): Closure { + return static function (int $offset = 0) use ($limit): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($limit, $offset): Generator { + if (0 === $limit) { + return yield from []; + } - return yield from new LimitIterator($iterator, $offset, $limit); + return yield from new LimitIterator($iterator, $offset, $limit); + }; }; + }; } } diff --git a/src/Operation/Loop.php b/src/Operation/Loop.php index 31ce8b1b6..04cef3e13 100644 --- a/src/Operation/Loop.php +++ b/src/Operation/Loop.php @@ -17,13 +17,16 @@ */ final class Loop extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(Iterator): Generator + */ public function __invoke(): Closure { return /** * @psalm-param Iterator $iterator * - * @psalm-return Generator + * @psalm-return Iterator */ static function (Iterator $iterator): Generator { return yield from new InfiniteIterator($iterator); diff --git a/src/Operation/Map.php b/src/Operation/Map.php index 9376bb3a2..e8f0245f9 100644 --- a/src/Operation/Map.php +++ b/src/Operation/Map.php @@ -16,35 +16,40 @@ */ final class Map extends AbstractOperation implements Operation { - public function __construct(callable ...$callbacks) - { - $this->storage['callbacks'] = $callbacks; - } - + /** + * @psalm-return Closure((callable(T, TKey): T)...): Closure(Iterator): Generator + */ public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * @psalm-param list $callbacks - * - * @psalm-return Generator + * @psalm-param callable(T, TKey): T ...$callbacks */ - static function (Iterator $iterator, array $callbacks): Generator { - foreach ($iterator as $key => $value) { - $callback = - /** - * @param mixed $carry - * @psalm-param T $carry - * @psalm-param callable(T, TKey): T $callback - * @psalm-return T - */ - static function ($carry, callable $callback) use ($value, $key) { - return $callback($value, $key); - }; + static function (callable ...$callbacks): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($callbacks): Generator { + foreach ($iterator as $key => $value) { + $callback = + /** + * @param mixed $carry + * @psalm-param T $carry + * + * @psalm-param callable(T, TKey): T $callback + * + * @psalm-return T + */ + static function ($carry, callable $callback) use ($value, $key) { + return $callback($value, $key); + }; - yield $key => array_reduce($callbacks, $callback, $value); - } + yield $key => array_reduce($callbacks, $callback, $value); + } + }; }; } } diff --git a/src/Operation/Merge.php b/src/Operation/Merge.php index 016bf1171..85d7f7d1e 100644 --- a/src/Operation/Merge.php +++ b/src/Operation/Merge.php @@ -17,33 +17,31 @@ final class Merge extends AbstractOperation implements Operation { /** - * @param iterable ...$sources - * @psalm-param Iterator ...$sources + * @psalm-return Closure(iterable...): Closure(Iterator): Generator */ - public function __construct(iterable ...$sources) - { - $this->storage['sources'] = $sources; - } - public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * @psalm-param list> $sources - * - * @psalm-return Generator + * @psalm-param iterable ...$sources */ - static function (Iterator $iterator, array $sources): Generator { - foreach ($iterator as $key => $value) { - yield $key => $value; - } - - foreach ($sources as $source) { - foreach ($source as $key => $value) { + static function (iterable ...$sources): Closure { + return + /** + * @psalm-param Iterator $iterator + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($sources): Generator { + foreach ($iterator as $key => $value) { yield $key => $value; } - } + + foreach ($sources as $source) { + foreach ($source as $key => $value) { + yield $key => $value; + } + } + }; }; } } diff --git a/src/Operation/Normalize.php b/src/Operation/Normalize.php index 259d48bfb..1162cd978 100644 --- a/src/Operation/Normalize.php +++ b/src/Operation/Normalize.php @@ -16,13 +16,16 @@ */ final class Normalize extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(Iterator): Generator + */ public function __invoke(): Closure { return /** * @psalm-param Iterator $iterator * - * @psalm-return Generator + * @psalm-return Generator */ static function (Iterator $iterator): Generator { foreach ($iterator as $value) { diff --git a/src/Operation/Nth.php b/src/Operation/Nth.php index 8de721c94..7c27e8dcc 100644 --- a/src/Operation/Nth.php +++ b/src/Operation/Nth.php @@ -16,32 +16,30 @@ */ final class Nth extends AbstractOperation implements Operation { - public function __construct(int $step, int $offset) - { - $this->storage = [ - 'step' => $step, - 'offset' => $offset, - ]; - } - + /** + * @psalm-return Closure(int): Closure(int): Closure(Iterator): Generator + */ public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator - */ - static function (Iterator $iterator, int $step, int $offset): Generator { - $position = 0; + return static function (int $step): Closure { + return static function (int $offset) use ($step): Closure { + return + /** + * @psalm-param Iterator $iterator + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($step, $offset): Generator { + $position = 0; - foreach ($iterator as $key => $value) { - if ($position++ % $step !== $offset) { - continue; - } + foreach ($iterator as $key => $value) { + if ($position++ % $step !== $offset) { + continue; + } - yield $key => $value; - } + yield $key => $value; + } + }; }; + }; } } diff --git a/src/Operation/Nullsy.php b/src/Operation/Nullsy.php new file mode 100644 index 000000000..c4e45f385 --- /dev/null +++ b/src/Operation/Nullsy.php @@ -0,0 +1,39 @@ +): Generator + */ + public function __invoke(): Closure + { + return + /** + * @psalm-param Iterator $iterator + * @psalm-return Generator + */ + static function (Iterator $iterator): Generator { + foreach ($iterator as $key => $value) { + if (null !== $value) { + return yield false; + } + } + + return yield true; + }; + } +} diff --git a/src/Operation/Only.php b/src/Operation/Only.php index d8a996b28..58d83d32a 100644 --- a/src/Operation/Only.php +++ b/src/Operation/Only.php @@ -19,39 +19,36 @@ final class Only extends AbstractOperation implements Operation { /** - * @param mixed ...$keys - * @psalm-param TKey ...$keys + * @psalm-return Closure(TKey...): Closure(Iterator): Generator */ - public function __construct(...$keys) - { - $this->storage = [ - 'keys' => $keys, - ]; - } - public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * @psalm-param list $keys - * - * @psalm-return Generator + * @psalm-param TKey ...$keys */ - static function (Iterator $iterator, array $keys): Generator { - if ([] === $keys) { - return yield from $iterator; - } - - $keys = array_flip($keys); - - foreach ($iterator as $key => $value) { - if (false === array_key_exists($key, $keys)) { - continue; - } - - yield $key => $value; - } + static function (...$keys): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($keys): Generator { + if ([] === $keys) { + return yield from $iterator; + } + + $keys = array_flip($keys); + + foreach ($iterator as $key => $value) { + if (false === array_key_exists($key, $keys)) { + continue; + } + + yield $key => $value; + } + }; }; } } diff --git a/src/Operation/Pack.php b/src/Operation/Pack.php index 615f78c64..965fd0997 100644 --- a/src/Operation/Pack.php +++ b/src/Operation/Pack.php @@ -16,6 +16,9 @@ */ final class Pack extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(Iterator): Generator + */ public function __invoke(): Closure { return diff --git a/src/Operation/Pad.php b/src/Operation/Pad.php index db684956b..6bd7df8f9 100644 --- a/src/Operation/Pad.php +++ b/src/Operation/Pad.php @@ -17,40 +17,38 @@ final class Pad extends AbstractOperation implements Operation { /** - * @param mixed $value - * @psalm-param T $value + * @return Closure(int): Closure(T): Closure(Iterator): Generator */ - public function __construct(int $size, $value) - { - $this->storage = [ - 'size' => $size, - 'value' => $value, - ]; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param T $padValue - * - * @psalm-return Generator - * - * @param mixed $padValue - */ - static function (Iterator $iterator, int $size, $padValue): Generator { - $y = 0; - - foreach ($iterator as $key => $value) { - ++$y; - - yield $key => $value; - } - - while ($y++ < $size) { - yield $padValue; - } - }; + return static function (int $size): Closure { + return + /** + * @psalm-param T $padValue + * + * @param mixed $padValue + */ + static function ($padValue) use ($size): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($size, $padValue): Generator { + $y = 0; + + foreach ($iterator as $key => $value) { + ++$y; + + yield $key => $value; + } + + while ($y++ < $size) { + yield $padValue; + } + }; + }; + }; } } diff --git a/src/Operation/Pair.php b/src/Operation/Pair.php index 1d536d717..96ecb52f2 100644 --- a/src/Operation/Pair.php +++ b/src/Operation/Pair.php @@ -8,7 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -17,6 +16,9 @@ */ final class Pair extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(Iterator): Generator + */ public function __invoke(): Closure { return @@ -27,7 +29,7 @@ public function __invoke(): Closure */ static function (Iterator $iterator): Generator { /** @psalm-var list $chunk */ - foreach ((new Run(new Chunk(2)))($iterator) as $chunk) { + foreach (Chunk::of()(2)($iterator) as $chunk) { $chunk = array_values($chunk); yield $chunk[0] => $chunk[1]; diff --git a/src/Operation/Pluck.php b/src/Operation/Pluck.php index 39f5618b0..a3e675b0e 100644 --- a/src/Operation/Pluck.php +++ b/src/Operation/Pluck.php @@ -11,93 +11,116 @@ use Iterator; use loophp\collection\Contract\Collection; use loophp\collection\Contract\Operation; -use loophp\collection\Iterator\IterableIterator; -use loophp\collection\Transformation\Get; -use loophp\collection\Transformation\Run; -use loophp\collection\Transformation\Transform; use ReflectionClass; -use ReflectionException; use function array_key_exists; use function in_array; use function is_array; use function is_object; +/** + * @psalm-template TKey + * @psalm-template TKey of array-key + * @psalm-template T + */ final class Pluck extends AbstractOperation implements Operation { /** - * Pluck constructor. - * - * @param array|string $key - * @param mixed $default + * @psalm-return Closure(T): Closure(T): Closure(Iterator): Generator */ - public function __construct($key, $default) - { - $this->storage = [ - 'key' => $key, - 'default' => $default, - 'operation' => Closure::fromCallable([$this, 'pick']), - ]; - } - public function __invoke(): Closure { return /** - * @param array|string $key - * @param mixed $default + * @psalm-param T $key + * + * @psalm-return Closure(T): Closure(Iterator): Generator, mixed, void> + * + * @param mixed $key */ - static function (Iterator $iterator, $key, $default, callable $pick): Generator { - $key = true === is_scalar($key) ? explode('.', trim((string) $key, '.')) : $key; + static function ($key): Closure { + return + /** + * @psalm-param T $default + * + * @psalm-return Closure(Iterator): Generator, mixed, void> + * + * @param mixed $default + */ + static function ($default) use ($key): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator, mixed, void> + */ + static function (Iterator $iterator) use ($key, $default): Generator { + $pick = + // phpcs:disable + /** + * @psalm-param Iterator $iterator + * @psalm-param T|iterable $target + * @psalm-param array $key + * @psalm-param T $default + * + * @psalm-return T|iterable + * + * @param mixed $target + * @param mixed|null $default + */ + static function (Iterator $iterator, $target, array $key, $default = null) use (&$pick) { + // phpcs:enable + while (null !== $segment = array_shift($key)) { + if ('*' === $segment) { + if (false === is_iterable($target)) { + return $default; + } - foreach ($iterator as $value) { - yield $pick($iterator, $value, $key, $default); - } - }; - } + /** @psalm-var array $result */ + $result = []; - /** - * Get an item from an array or object using "dot" notation. - * - * @param Iterator $iterator - * @param mixed $target - * @param array $key - * @param mixed $default - * - * @throws ReflectionException - * - * @return mixed - */ - private function pick(Iterator $iterator, $target, array $key, $default = null) - { - while (null !== $segment = array_shift($key)) { - if ('*' === $segment) { - if (false === is_iterable($target)) { - return $default; - } + foreach ($target as $item) { + $result[] = $pick($iterator, $item, $key); + } - $result = []; + /** @psalm-var Generator $collapse */ + $collapse = Collapse::of()(new ArrayIterator($result)); - foreach ($target as $item) { - $result[] = $this->pick($iterator, $item, $key); - } + return in_array('*', $key, true) ? $collapse : $result; + } - return in_array('*', $key, true) ? (new Run((new Collapse())))(new ArrayIterator($result)) : $result; - } + // phpcs:disable + if ((true === is_array($target)) && (true === array_key_exists($segment, $target))) { + /** @psalm-var T $target */ + $target = $target[$segment]; + } elseif (($target instanceof ArrayAccess) && (true === $target->offsetExists($segment))) { + /** @psalm-var T $target */ + $target = $target[$segment]; + } elseif ($target instanceof Collection) { + /** @psalm-var T $target */ + $target = (Get::of()($segment)($default)($target->getIterator()))->current(); + } elseif ((true === is_object($target)) && (true === property_exists($target, $segment))) { + /** @psalm-var T $target */ + $target = (new ReflectionClass($target))->getProperty($segment)->getValue($target); + } else { + /** @psalm-var T $target */ + $target = $default; + } + // phpcs:enable + } - if ((true === is_array($target)) && (true === array_key_exists($segment, $target))) { - $target = $target[$segment]; - } elseif (($target instanceof ArrayAccess) && (true === $target->offsetExists($segment))) { - $target = $target[$segment]; - } elseif ($target instanceof Collection) { - $target = (new Transform(new Get($segment, $default)))(new IterableIterator($target)); - } elseif ((true === is_object($target)) && (true === property_exists($target, $segment))) { - $target = (new ReflectionClass($target))->getProperty($segment)->getValue($target); - } else { - $target = $default; - } - } + return $target; + }; - return $target; + $key = true === is_scalar($key) ? explode('.', trim((string) $key, '.')) : $key; + + // phpcs:disable + foreach ($iterator as $value) { + yield $pick($iterator, $value, $key, $default); + } + // phpcs:enable + }; + }; + }; } } diff --git a/src/Operation/Prepend.php b/src/Operation/Prepend.php index 1a92729a6..8db15f4c1 100644 --- a/src/Operation/Prepend.php +++ b/src/Operation/Prepend.php @@ -17,31 +17,28 @@ final class Prepend extends AbstractOperation implements Operation { /** - * @param mixed ...$items - * @psalm-param T ...$items + * @psalm-return Closure(T...): Closure(Iterator): Generator */ - public function __construct(...$items) - { - $this->storage['items'] = $items; - } - public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * @psalm-param list $items - * - * @psalm-return Generator + * @psalm-param T ...$items */ - static function (Iterator $iterator, array $items): Generator { - foreach ($items as $key => $item) { - yield $key => $item; - } + static function (...$items): Closure { + return + /** + * @psalm-param Iterator $iterator + */ + static function (Iterator $iterator) use ($items): Generator { + foreach ($items as $key => $item) { + yield $key => $item; + } - foreach ($iterator as $key => $value) { - yield $key => $value; - } + foreach ($iterator as $key => $value) { + yield $key => $value; + } + }; }; } } diff --git a/src/Operation/Product.php b/src/Operation/Product.php index 518498700..e4eb970e1 100644 --- a/src/Operation/Product.php +++ b/src/Operation/Product.php @@ -19,37 +19,14 @@ */ final class Product extends AbstractOperation implements Operation { - /** - * @param iterable ...$iterables - * @psalm-param Iterator ...$iterables - */ - public function __construct(iterable ...$iterables) - { - $this->storage = [ - 'iterables' => $iterables, - 'cartesian' => - /** - * @param array $input - * @psalm-param array> $input - * - * @psalm-return Generator> - */ - function (array $input): Generator { - return $this->cartesian($input); - }, - ]; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param array> $iterables - * - * @psalm-return Generator> - */ - static function (Iterator $iterator, array $iterables, callable $cartesian): Generator { + $cartesian = function (array $input): Generator { + return $this->cartesian($input); + }; + + return static function (iterable ...$iterables) use ($cartesian): Closure { + return static function (Iterator $iterator) use ($cartesian, $iterables): Generator { $its = [$iterator]; foreach ($iterables as $iterable) { @@ -58,6 +35,7 @@ static function (Iterator $iterator, array $iterables, callable $cartesian): Gen return yield from $cartesian($its); }; + }; } /** diff --git a/src/Operation/RSample.php b/src/Operation/RSample.php index 581df41f3..47cc70027 100644 --- a/src/Operation/RSample.php +++ b/src/Operation/RSample.php @@ -8,7 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -17,27 +16,16 @@ */ final class RSample extends AbstractOperation implements Operation { - public function __construct(float $probability) - { - $this->storage['probability'] = $probability; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator - */ - static function (Iterator $iterator, float $probability): Generator { - return yield from (new Run( - new Filter( - static function () use ($probability): bool { - return (mt_rand() / mt_getrandmax()) < $probability; - } - ) - ))($iterator); + return static function (float $probability): Closure { + return static function (Iterator $iterator) use ($probability): Generator { + $callback = static function () use ($probability): bool { + return (mt_rand() / mt_getrandmax()) < $probability; + }; + + return yield from Filter::of()($callback)($iterator); }; + }; } } diff --git a/src/Operation/Random.php b/src/Operation/Random.php index 9e373510e..61a42f4c0 100644 --- a/src/Operation/Random.php +++ b/src/Operation/Random.php @@ -8,7 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -17,23 +16,15 @@ */ final class Random extends AbstractOperation implements Operation { - public function __construct(int $size) - { - $this->storage = [ - 'size' => $size, - ]; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator - */ - static function (Iterator $iterator, int $size): Generator { - return yield from (new Run(new Limit($size), new Shuffle()))($iterator); + return static function (int $size): Closure { + return static function (Iterator $iterator) use ($size): Generator { + return yield from (Compose::of()( + Limit::of()($size)(0), + Shuffle::of() + )($iterator)); }; + }; } } diff --git a/src/Operation/Range.php b/src/Operation/Range.php index 6988ff30c..11798d9d3 100644 --- a/src/Operation/Range.php +++ b/src/Operation/Range.php @@ -13,21 +13,18 @@ final class Range extends AbstractOperation implements Operation { - public function __construct(float $start = 0.0, float $end = INF, float $step = 1.0) - { - $this->storage = [ - 'start' => $start, - 'end' => $end, - 'step' => $step, - ]; - } - public function __invoke(): Closure { - return static function (Iterator $iterator, float $start, float $end, float $step): Generator { - for ($current = $start; $current < $end; $current += $step) { - yield $current; - } + return static function (float $start = 0.0): Closure { + return static function (float $end = INF) use ($start): Closure { + return static function (float $step = 1.0) use ($start, $end): Closure { + return static function (Iterator $iterator) use ($start, $end, $step): Generator { + for ($current = $start; $current < $end; $current += $step) { + yield $current; + } + }; + }; + }; }; } } diff --git a/src/Operation/Reduce.php b/src/Operation/Reduce.php new file mode 100644 index 000000000..0aaa16b42 --- /dev/null +++ b/src/Operation/Reduce.php @@ -0,0 +1,34 @@ + $collection + * + * @return mixed|null + * @psalm-return T|scalar|null|\Iterator + */ + public function __invoke(): Closure + { + return static function (callable $callback): Closure { + return static function ($initial = null) use ($callback): Closure { + return static function (Iterator $iterator) use ($callback, $initial) { + return yield from FoldLeft::of()($callback)($initial)($iterator); + }; + }; + }; + } +} diff --git a/src/Operation/Reduction.php b/src/Operation/Reduction.php index bf6f6c51c..0250a9e05 100644 --- a/src/Operation/Reduction.php +++ b/src/Operation/Reduction.php @@ -16,35 +16,36 @@ */ final class Reduction extends AbstractOperation implements Operation { + // phpcs:disable /** - * @param mixed|null $initial - * @psalm-param T|null $initial - * @psalm-param callable(T|null, T, TKey):(T|null) $callback + * @psalm-return Closure(callable(T|null, T, TKey):(T|null)): Closure(T|null): Closure(Iterator): Generator */ - public function __construct(callable $callback, $initial = null) - { - $this->storage = [ - 'callback' => $callback, - 'initial' => $initial, - ]; - } - + // phpcs:enable public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator * @psalm-param callable(T|null, T, TKey):(T|null) $callback - * - * @param mixed $initial - * @psalm-param T|null $initial - * - * @psalm-return Generator */ - static function (Iterator $iterator, callable $callback, $initial): Generator { - foreach ($iterator as $key => $value) { - yield $key => ($initial = $callback($initial, $value, $key)); - } + static function (callable $callback): Closure { + return + /** + * @param mixed|null $initial + * @psalm-param T|null $initial + */ + static function ($initial = null) use ($callback): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($callback, $initial): Generator { + foreach ($iterator as $key => $value) { + yield $key => ($initial = $callback($initial, $value, $key)); + } + }; + }; }; } } diff --git a/src/Operation/Reverse.php b/src/Operation/Reverse.php index d089b1dc2..44990a2c3 100644 --- a/src/Operation/Reverse.php +++ b/src/Operation/Reverse.php @@ -8,7 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -26,8 +25,9 @@ public function __invoke(): Closure * @psalm-return Generator */ static function (Iterator $iterator): Generator { - /** @psalm-var array $all */ - $all = iterator_to_array((new Run(new Pack()))($iterator)); + /** @psalm-var Generator $pack */ + $pack = Pack::of()($iterator); + $all = iterator_to_array($pack); for (end($all); null !== key($all); prev($all)) { $item = current($all); diff --git a/src/Operation/Scale.php b/src/Operation/Scale.php index 66fb9b996..33fc60484 100644 --- a/src/Operation/Scale.php +++ b/src/Operation/Scale.php @@ -8,7 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; use const INF; @@ -19,51 +18,61 @@ */ final class Scale extends AbstractOperation implements Operation { - public function __construct( - float $lowerBound, - float $upperBound, - float $wantedLowerBound = 0.0, - float $wantedUpperBound = 1.0, - float $base = 0.0 - ) { - $wantedLowerBound = (0.0 === $wantedLowerBound) ? (0.0 === $base ? 0.0 : 1.0) : $wantedLowerBound; // phpcs:ignore - $wantedUpperBound = (1.0 === $wantedUpperBound) ? (0.0 === $base ? 1.0 : $base) : $wantedUpperBound; // phpcs:ignore + // phpcs:disable + /** + * @psalm-return Closure(float): Closure(float): Closure(float): Closure(float): Closure(float): Closure(Iterator): Generator + */ + // phpcs:enable + public function __invoke(): Closure + { + return static function (float $lowerBound): Closure { + return static function (float $upperBound) use ($lowerBound): Closure { + return static function (float $wantedLowerBound = 0.0) use ($lowerBound, $upperBound): Closure { + return static function (float $wantedUpperBound = 1.0) use ($lowerBound, $upperBound, $wantedLowerBound): Closure { // phpcs:ignore + return static function (float $base = 0.0) use ($lowerBound, $upperBound, $wantedLowerBound, $wantedUpperBound): Closure { // phpcs:ignore + return static function (Iterator $iterator) use ($lowerBound, $upperBound, $wantedLowerBound, $wantedUpperBound, $base): Generator { // phpcs:ignore + $wantedLowerBound = (0.0 === $wantedLowerBound) ? (0.0 === $base ? 0.0 : 1.0) : $wantedLowerBound; // phpcs:ignore + $wantedUpperBound = (1.0 === $wantedUpperBound) ? (0.0 === $base ? 1.0 : $base) : $wantedUpperBound; // phpcs:ignore - $this->storage['mapper'] = new Map( - /** - * @param float|int $v - */ - static function ($v) use ($lowerBound, $upperBound, $wantedLowerBound, $wantedUpperBound, $base): float { // phpcs:ignore - $mx = 0.0 === $base ? - ($v - $lowerBound) / ($upperBound - $lowerBound) : - log($v - $lowerBound, $base) / log($upperBound - $lowerBound, $base); + /** @psalm-var callable(Generator): Generator $mapper */ + $mapper = Map::of()( + /** + * @param mixed $v + * @psalm-param float|int $v + */ + static function ($v) use ($lowerBound, $upperBound, $wantedLowerBound, $wantedUpperBound, $base): float { // phpcs:ignore + $mx = 0.0 === $base ? + ($v - $lowerBound) / ($upperBound - $lowerBound) : + log($v - $lowerBound, $base) / log($upperBound - $lowerBound, $base); - $mx = $mx === -INF ? 0 : $mx; + $mx = $mx === -INF ? 0 : $mx; - return $wantedLowerBound + $mx * ($wantedUpperBound - $wantedLowerBound); - } - ); + return $wantedLowerBound + $mx * ($wantedUpperBound - $wantedLowerBound); + } + ); - $this->storage['filter'] = new Filter( - /** - * @param float|int $item - */ - static function ($item) use ($lowerBound): bool { - return $item >= $lowerBound; - }, - /** - * @param float|int $item - */ - static function ($item) use ($upperBound): bool { - return $item <= $upperBound; - } - ); - } + /** @psalm-var callable(Iterator): Generator $filter */ + $filter = Filter::of()( + /** + * @param float|int $item + */ + static function ($item) use ($lowerBound): bool { + return $item >= $lowerBound; + }, + /** + * @param float|int $item + */ + static function ($item) use ($upperBound): bool { + return $item <= $upperBound; + } + ); - public function __invoke(): Closure - { - return static function (Iterator $iterator, Map $mapper, Filter $filter): Generator { - return yield from (new Run($filter, $mapper))($iterator); + return yield from Compose::of()($filter, $mapper)($iterator); + }; + }; + }; + }; + }; }; } } diff --git a/src/Operation/Shuffle.php b/src/Operation/Shuffle.php index 7c549ca77..cfe1f4d19 100644 --- a/src/Operation/Shuffle.php +++ b/src/Operation/Shuffle.php @@ -8,7 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -26,8 +25,9 @@ public function __invoke(): Closure * @psalm-return Generator */ static function (Iterator $iterator): Generator { - /** @psalm-var array $data */ - $data = iterator_to_array((new Run(new Pack()))($iterator)); + /** @psalm-var Iterator $pack */ + $pack = Pack::of()($iterator); + $data = iterator_to_array($pack); while ([] !== $data) { $randomKey = array_rand($data); diff --git a/src/Operation/Since.php b/src/Operation/Since.php index a7d0a4436..18303c754 100644 --- a/src/Operation/Since.php +++ b/src/Operation/Since.php @@ -16,25 +16,10 @@ */ final class Since extends AbstractOperation implements Operation { - /** - * @param callable ...$callbacks - * @psalm-param callable(T, TKey):(bool) ...$callbacks - */ - public function __construct(callable ...$callbacks) - { - $this->storage['callbacks'] = $callbacks; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param list $callbacks - * - * @psalm-return Generator - */ - static function (Iterator $iterator, array $callbacks): Generator { + return static function (callable ...$callbacks): Closure { + return static function (Iterator $iterator) use ($callbacks): Generator { while ($iterator->valid()) { $result = array_reduce( $callbacks, @@ -57,5 +42,6 @@ static function (bool $carry, callable $callable) use ($iterator): bool { yield $iterator->key() => $iterator->current(); } }; + }; } } diff --git a/src/Operation/Skip.php b/src/Operation/Skip.php index 6e3172a79..873d9af34 100644 --- a/src/Operation/Skip.php +++ b/src/Operation/Skip.php @@ -16,30 +16,29 @@ */ final class Skip extends AbstractOperation implements Operation { - public function __construct(int ...$skip) - { - $this->storage['skip'] = $skip; - } - + /** + * @psalm-return Closure(int...): Closure(Iterator): Generator + */ public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param list $skip - * - * @psalm-return Generator - */ - static function (Iterator $iterator, array $skip): Generator { - $skip = array_sum($skip); + return static function (int ...$skip): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($skip): Generator { + $skip = array_sum($skip); - foreach ($iterator as $key => $value) { - if (0 < $skip--) { - continue; - } + foreach ($iterator as $key => $value) { + if (0 < $skip--) { + continue; + } - yield $key => $value; - } - }; + yield $key => $value; + } + }; + }; } } diff --git a/src/Operation/Slice.php b/src/Operation/Slice.php index f3983727a..0dc46411a 100644 --- a/src/Operation/Slice.php +++ b/src/Operation/Slice.php @@ -8,7 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -17,30 +16,36 @@ */ final class Slice extends AbstractOperation implements Operation { - public function __construct(int $offset, int $length = -1) - { - $this->storage = [ - 'offset' => $offset, - 'length' => $length, - ]; - } - + /** + * @psalm-return Closure(int): Closure(int|null): Generator + */ public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator - */ - static function (Iterator $iterator, int $offset, int $length): Generator { - $skip = (new Run(new Skip($offset)))($iterator); + return static function (int $offset): Closure { + return + /** + * @psalm-param int|null $length + * + * @psalm-return Closure(Iterator): Generator + */ + static function (int $length = -1) use ($offset): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($offset, $length): Generator { + /** @psalm-var callable(Iterator): Generator $skip */ + $skip = Skip::of()($offset); - if (-1 === $length) { - return yield from $skip; - } + if (-1 === $length) { + return yield from $skip($iterator); + } - return yield from (new Run(new Limit($length)))($skip); - }; + return yield from Compose::of()($skip, Limit::of()($length)(0))($iterator); + }; + }; + }; } } diff --git a/src/Operation/Sort.php b/src/Operation/Sort.php index 666600da7..35ebeb7d1 100644 --- a/src/Operation/Sort.php +++ b/src/Operation/Sort.php @@ -10,7 +10,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -19,63 +18,61 @@ */ final class Sort extends AbstractOperation implements Operation { - public function __construct(int $type = Operation\Sortable::BY_VALUES, ?callable $callback = null) - { - $this->storage = [ - 'type' => $type, - 'callback' => $callback ?? Closure::fromCallable([$this, 'compare']), - ]; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param callable(T, T):(int) $callback - * - * @psalm-return Generator - */ - static function (Iterator $iterator, int $type, callable $callback): Generator { - if (Operation\Sortable::BY_VALUES !== $type && Operation\Sortable::BY_KEYS !== $type) { - throw new Exception('Invalid sort type.'); - } - - $operations = Operation\Sortable::BY_VALUES === $type ? - [ - 'before' => [new Pack()], - 'after' => [new Unpack()], - ] : - [ - 'before' => [new Flip(), new Pack()], - 'after' => [new Unpack(), new Flip()], - ]; - - $callback = + return static function (int $type = Operation\Sortable::BY_VALUES): Closure { + return static function (?callable $callback = null) use ($type): Closure { + $callback = $callback ?? /** - * @psalm-param array{0:TKey, 1:T} $left - * @psalm-param array{0:TKey, 1:T} $right + * @param mixed $left + * @psalm-param T|TKey $left + * + * @param mixed $right + * @psalm-param T|TKey $right */ - static function (array $left, array $right) use ($callback): int { - return $callback($left[1], $right[1]); + static function ($left, $right): int { + return $left <=> $right; }; - $arrayIterator = new ArrayIterator(iterator_to_array((new Run(...$operations['before']))($iterator))); - $arrayIterator->uasort($callback); + return + /** + * @psalm-param Iterator $iterator + * @psalm-param callable(T, T):(int) $callback + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($type, $callback): Generator { + if (Operation\Sortable::BY_VALUES !== $type && Operation\Sortable::BY_KEYS !== $type) { + throw new Exception('Invalid sort type.'); + } + + $operations = Operation\Sortable::BY_VALUES === $type ? + [ + 'before' => [Pack::of()], + 'after' => [Unpack::of()], + ] : + [ + 'before' => [Flip::of(), Pack::of()], + 'after' => [Unpack::of(), Flip::of()], + ]; - return yield from (new Run(...$operations['after']))($arrayIterator); - }; - } + /** @psalm-var callable(Iterator): Generator | callable(Iterator): Generator $before */ + $before = Compose::of()(...$operations['before']); - /** - * @psalm-param T $left - * @psalm-param T $right - * - * @param mixed $left - * @param mixed $right - */ - private function compare($left, $right): int - { - return $left <=> $right; + $arrayIterator = new ArrayIterator(iterator_to_array($before($iterator))); + $arrayIterator->uasort( + /** + * @psalm-param array{0:TKey|T, 1:T|TKey} $left + * @psalm-param array{0:TKey|T, 1:T|TKey} $right + */ + static function (array $left, array $right) use ($callback): int { + return $callback($left[1], $right[1]); + } + ); + + return yield from Compose::of()(...$operations['after'])($arrayIterator); + }; + }; + }; } } diff --git a/src/Operation/Split.php b/src/Operation/Split.php index 090ecd0ac..2ec57e485 100644 --- a/src/Operation/Split.php +++ b/src/Operation/Split.php @@ -16,44 +16,41 @@ */ final class Split extends AbstractOperation implements Operation { - public function __construct(callable ...$callbacks) - { - $this->storage['callbacks'] = $callbacks; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param list $callbacks - * - * @psalm-return Generator> - */ - static function (Iterator $iterator, array $callbacks): Generator { - $carry = []; - - foreach ($iterator as $key => $value) { - $callbackReturn = array_reduce( - $callbacks, - static function (bool $carry, callable $callback) use ($key, $value): bool { - return $callback($value, $key) !== $carry; - }, - false - ); - - if (true === $callbackReturn && [] !== $carry) { - yield $carry; - - $carry = []; + return static function (callable ...$callbacks): Closure { + return + /** + * @psalm-param Iterator $iterator + * @psalm-param list $callbacks + * + * @psalm-return Generator> + */ + static function (Iterator $iterator) use ($callbacks): Generator { + $carry = []; + + foreach ($iterator as $key => $value) { + $callbackReturn = array_reduce( + $callbacks, + static function (bool $carry, callable $callback) use ($key, $value): bool { + return $callback($value, $key) !== $carry; + }, + false + ); + + if (true === $callbackReturn && [] !== $carry) { + yield $carry; + + $carry = []; + } + + $carry[] = $value; } - $carry[] = $value; - } - - if ([] !== $carry) { - yield $carry; - } - }; + if ([] !== $carry) { + yield $carry; + } + }; + }; } } diff --git a/src/Operation/Tail.php b/src/Operation/Tail.php index db6fdade5..2efc69972 100644 --- a/src/Operation/Tail.php +++ b/src/Operation/Tail.php @@ -8,7 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -17,16 +16,19 @@ */ final class Tail extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(Iterator): Generator + */ public function __invoke(): Closure { return /** * @psalm-param Iterator $iterator * - * @psalm-return Generator + * @psalm-return Generator */ static function (Iterator $iterator): Generator { - return yield from (new Run(new Skip(1)))($iterator); + return yield from Skip::of()(1)($iterator); }; } } diff --git a/src/Operation/Times.php b/src/Operation/Times.php index c73aa14d9..bf4cd5d27 100644 --- a/src/Operation/Times.php +++ b/src/Operation/Times.php @@ -17,35 +17,24 @@ */ final class Times extends AbstractOperation implements Operation { - public function __construct(?int $number = null, ?callable $callback = null) + public function __invoke(): Closure { - $number = $number ?? 0; - - if (1 > $number) { - throw new InvalidArgumentException('Invalid parameter. $number must be greater than 1.'); - } + return static function (int $number = 0): Closure { + return static function (?callable $callback = null) use ($number): Closure { + return static function (Iterator $iterator) use ($number, $callback): Generator { + if (1 > $number) { + throw new InvalidArgumentException('Invalid parameter. $number must be greater than 1.'); + } - $this->storage = [ - 'number' => $number, - 'callback' => $callback ?? static function (int $value): int { - return $value; - }, - ]; - } + $callback = $callback ?? static function (int $value): int { + return $value; + }; - public function __invoke(): Closure - { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param callable(int):(int) $callback - * - * @psalm-return Generator - */ - static function (Iterator $iterator, ?int $number, callable $callback): Generator { - for ($current = 1; $current <= $number; ++$current) { - yield $callback($current); - } + for ($current = 1; $current <= $number; ++$current) { + yield $callback($current); + } + }; }; + }; } } diff --git a/src/Operation/Transpose.php b/src/Operation/Transpose.php index bdf770ad4..219b38c9a 100644 --- a/src/Operation/Transpose.php +++ b/src/Operation/Transpose.php @@ -18,6 +18,9 @@ */ final class Transpose extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(Iterator): Generator> + */ public function __invoke(): Closure { return diff --git a/src/Operation/Truthy.php b/src/Operation/Truthy.php new file mode 100644 index 000000000..2f7020f69 --- /dev/null +++ b/src/Operation/Truthy.php @@ -0,0 +1,39 @@ +): Generator + */ + public function __invoke(): Closure + { + return + /** + * @psalm-param Iterator $iterator + * @psalm-return Generator $iterator + */ + static function (Iterator $iterator): Generator { + foreach ($iterator as $key => $value) { + if (false === (bool) $value) { + return yield false; + } + } + + return yield true; + }; + } +} diff --git a/src/Operation/Unpack.php b/src/Operation/Unpack.php index 63ec06a30..e2dcab460 100644 --- a/src/Operation/Unpack.php +++ b/src/Operation/Unpack.php @@ -9,7 +9,6 @@ use Iterator; use loophp\collection\Contract\Operation; use loophp\collection\Iterator\IterableIterator; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -33,7 +32,7 @@ static function (Iterator $iterator): Generator { } /** @psalm-var array> $chunks */ - $chunks = (new Run((new Chunk(2))))(new IterableIterator($value)); + $chunks = Chunk::of()(2)(new IterableIterator($value)); foreach ($chunks as [$k, $v]) { yield $k => $v; diff --git a/src/Operation/Unpair.php b/src/Operation/Unpair.php index ef34231c4..968408e15 100644 --- a/src/Operation/Unpair.php +++ b/src/Operation/Unpair.php @@ -16,6 +16,9 @@ */ final class Unpair extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(Iterator): Generator + */ public function __invoke(): Closure { return diff --git a/src/Operation/Until.php b/src/Operation/Until.php index ab870fd1f..9af366b9c 100644 --- a/src/Operation/Until.php +++ b/src/Operation/Until.php @@ -17,41 +17,40 @@ final class Until extends AbstractOperation implements Operation { /** - * @param callable ...$callbacks - * @psalm-param callable(T, TKey):(bool) ...$callbacks + * @psalm-return Closure((callable(T, TKey):(bool))...): Closure(Iterator): Generator */ - public function __construct(callable ...$callbacks) - { - $this->storage['callbacks'] = $callbacks; - } - public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * @psalm-param list $callbacks - * - * @psalm-return Generator + * @psalm-param callable(T, TKey):(bool) ...$callbacks */ - static function (Iterator $iterator, array $callbacks): Generator { - foreach ($iterator as $key => $value) { - yield $key => $value; + static function (callable ...$callbacks): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($callbacks): Generator { + foreach ($iterator as $key => $value) { + yield $key => $value; - $result = array_reduce( - $callbacks, - static function (bool $carry, callable $callable) use ($key, $value): bool { - return ($callable($value, $key)) ? + $result = array_reduce( + $callbacks, + static function (bool $carry, callable $callable) use ($key, $value): bool { + return ($callable($value, $key)) ? $carry : false; - }, - true - ); + }, + true + ); - if (false !== $result) { - break; + if (false !== $result) { + break; + } } - } + }; }; } } diff --git a/src/Operation/Window.php b/src/Operation/Window.php index c9f130d43..47e475c97 100644 --- a/src/Operation/Window.php +++ b/src/Operation/Window.php @@ -9,7 +9,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -18,30 +17,32 @@ */ final class Window extends AbstractOperation implements Operation { - public function __construct(int ...$length) - { - $this->storage['length'] = new ArrayIterator($length); - } - + /** + * @psalm-return Closure(int...): Closure(Iterator): Generator> + */ public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param ArrayIterator $length - * - * @psalm-return Generator> - */ - static function (Iterator $iterator, ArrayIterator $length): Generator { - /** @psalm-var Iterator $length */ - $length = (new Run(new Loop()))($length); + return static function (int ...$lengths): Closure { + return + /** + * @psalm-param Iterator $iterator + * @psalm-param ArrayIterator $length + * + * @psalm-return Generator> + */ + static function (Iterator $iterator) use ($lengths): Generator { + /** @psalm-var Iterator $lengths */ + $lengths = Loop::of()(new ArrayIterator($lengths)); + + for ($i = 0; iterator_count($iterator) > $i; ++$i) { + /** @psalm-var Generator $slice */ + $slice = Slice::of()($i)($lengths->current())($iterator); - for ($i = 0; iterator_count($iterator) > $i; ++$i) { - /** @psalm-var list $window */ - yield iterator_to_array((new Run(new Slice($i, $length->current())))($iterator)); + yield iterator_to_array($slice); - $length->next(); - } - }; + $lengths->next(); + } + }; + }; } } diff --git a/src/Operation/Zip.php b/src/Operation/Zip.php index 71d510238..489af2dd0 100644 --- a/src/Operation/Zip.php +++ b/src/Operation/Zip.php @@ -18,36 +18,28 @@ */ final class Zip extends AbstractOperation implements Operation { - /** - * Zip constructor. - * - * @param iterable ...$iterables - */ - public function __construct(iterable ...$iterables) - { - $this->storage['iterables'] = $iterables; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param list> $iterables - * - * @psalm-return Generator> - */ - static function (Iterator $iterator, array $iterables): Generator { - $mit = new MultipleIterator(MultipleIterator::MIT_NEED_ANY); - $mit->attachIterator($iterator); + return static function (iterable ...$iterables): Closure { + return + /** + * @psalm-param Iterator $iterator + * @psalm-param list> $iterables + * + * @psalm-return Generator> + */ + static function (Iterator $iterator) use ($iterables): Generator { + $mit = new MultipleIterator(MultipleIterator::MIT_NEED_ANY); + $mit->attachIterator($iterator); - foreach ($iterables as $iterableIterator) { - $mit->attachIterator(new IterableIterator($iterableIterator)); - } + foreach ($iterables as $iterableIterator) { + $mit->attachIterator(new IterableIterator($iterableIterator)); + } - foreach ($mit as $values) { - yield $values; - } - }; + foreach ($mit as $values) { + yield $values; + } + }; + }; } } diff --git a/src/Transformation/All.php b/src/Transformation/All.php deleted file mode 100644 index bac2f6844..000000000 --- a/src/Transformation/All.php +++ /dev/null @@ -1,28 +0,0 @@ - - */ -final class All implements Transformation -{ - /** - * @return array - * @phpstan-return array - * @psalm-return array - */ - public function __invoke(Iterator $collection): array - { - return iterator_to_array($collection); - } -} diff --git a/src/Transformation/Contains.php b/src/Transformation/Contains.php deleted file mode 100644 index 4ffb76288..000000000 --- a/src/Transformation/Contains.php +++ /dev/null @@ -1,58 +0,0 @@ - - */ -final class Contains implements Transformation -{ - /** - * @var ArrayIterator - * @psalm-var ArrayIterator - */ - private $values; - - /** - * @param mixed ...$values - * @psalm-param T ...$values - */ - public function __construct(...$values) - { - $this->values = new ArrayIterator($values); - } - - /** - * @param Iterator $collection - * - * @return bool - */ - public function __invoke(Iterator $collection) - { - $values = $this->values; - - foreach ($collection as $key => $value) { - foreach ($values as $k => $v) { - if ($v === $value) { - unset($values[$k]); - } - - if (0 === $values->count()) { - return true; - } - } - } - - return false; - } -} diff --git a/src/Transformation/Count.php b/src/Transformation/Count.php deleted file mode 100644 index de48eb9bf..000000000 --- a/src/Transformation/Count.php +++ /dev/null @@ -1,24 +0,0 @@ - - */ -final class Count implements Transformation -{ - public function __invoke(Iterator $collection) - { - return iterator_count(new IterableIterator($collection)); - } -} diff --git a/src/Transformation/Falsy.php b/src/Transformation/Falsy.php deleted file mode 100644 index 4dfb8861b..000000000 --- a/src/Transformation/Falsy.php +++ /dev/null @@ -1,29 +0,0 @@ - - */ -final class Falsy implements Transformation -{ - public function __invoke(Iterator $collection): bool - { - foreach ($collection as $key => $value) { - if (false !== (bool) $value) { - return false; - } - } - - return true; - } -} diff --git a/src/Transformation/FoldLeft.php b/src/Transformation/FoldLeft.php deleted file mode 100644 index 371d9aa17..000000000 --- a/src/Transformation/FoldLeft.php +++ /dev/null @@ -1,60 +0,0 @@ - - */ -final class FoldLeft implements Transformation -{ - /** - * @var callable - * @psalm-var callable(T|null, T, TKey, \Iterator):(T|null) - */ - private $callback; - - /** - * @var mixed|null - * @psalm-var T|null - */ - private $initial; - - /** - * @psalm-param callable(T|null, T, TKey, \Iterator):(T|null) $callback - * - * @param mixed|null $initial - * @psalm-param T|null $initial - */ - public function __construct(callable $callback, $initial = null) - { - $this->callback = $callback; - $this->initial = $initial; - } - - /** - * @psalm-param Iterator $collection - * - * @return mixed|null - * @psalm-return T|null - */ - public function __invoke(Iterator $collection) - { - $callback = $this->callback; - $initial = $this->initial; - - foreach ($collection as $key => $value) { - $initial = $callback($initial, $value, $key, $collection); - } - - return $initial; - } -} diff --git a/src/Transformation/FoldRight.php b/src/Transformation/FoldRight.php deleted file mode 100644 index a3d2f41ad..000000000 --- a/src/Transformation/FoldRight.php +++ /dev/null @@ -1,57 +0,0 @@ - - */ -final class FoldRight implements Transformation -{ - /** - * @var callable - * @psalm-var callable(T|null, T|null, TKey, \Iterator):(T|null) - */ - private $callback; - - /** - * @var mixed|null - * @psalm-var T|null - */ - private $initial; - - /** - * @psalm-param callable(T|null, T|null, TKey, \Iterator):(T|null) $callback - * - * @param mixed|null $initial - * @psalm-param T|null $initial - */ - public function __construct(callable $callback, $initial = null) - { - $this->callback = $callback; - $this->initial = $initial; - } - - /** - * @psalm-param Iterator $collection - * - * @return mixed|null - * @psalm-return T|null - */ - public function __invoke(Iterator $collection) - { - $callback = $this->callback; - $initial = $this->initial; - - return (new Transform(new FoldLeft($callback, $initial)))((new Run(new Reverse()))($collection)); - } -} diff --git a/src/Transformation/Get.php b/src/Transformation/Get.php deleted file mode 100644 index 131227465..000000000 --- a/src/Transformation/Get.php +++ /dev/null @@ -1,59 +0,0 @@ - - */ -final class Get implements Transformation -{ - /** - * @var mixed - * @psalm-var T - */ - private $default; - - /** - * @var int|string - */ - private $key; - - /** - * @param int|string $key - * @param mixed $default - * @psalm-param T $default - */ - public function __construct($key, $default) - { - $this->key = $key; - $this->default = $default; - } - - /** - * @param Iterator $collection - * - * @return T - */ - public function __invoke(Iterator $collection) - { - $keyToGet = $this->key; - $default = $this->default; - - foreach ($collection as $key => $value) { - if ($key === $keyToGet) { - return $value; - } - } - - return $default; - } -} diff --git a/src/Transformation/Has.php b/src/Transformation/Has.php deleted file mode 100644 index d7a5be92a..000000000 --- a/src/Transformation/Has.php +++ /dev/null @@ -1,50 +0,0 @@ - - */ -final class Has implements Transformation -{ - /** - * @var callable - * @psalm-var callable(TKey, T):(bool) - */ - private $callback; - - /** - * @psalm-param callable(TKey, T):(bool) $callback - */ - public function __construct(callable $callback) - { - $this->callback = $callback; - } - - /** - * @param Iterator $collection - * - * @return bool - */ - public function __invoke(Iterator $collection) - { - $callback = $this->callback; - - foreach ($collection as $key => $value) { - if ($callback($key, $value) === $value) { - return true; - } - } - - return false; - } -} diff --git a/src/Transformation/Implode.php b/src/Transformation/Implode.php deleted file mode 100644 index aedaf15c3..000000000 --- a/src/Transformation/Implode.php +++ /dev/null @@ -1,54 +0,0 @@ - - */ -final class Implode implements Transformation -{ - /** - * @var string - */ - private $glue; - - public function __construct(string $glue) - { - $this->glue = $glue; - } - - public function __invoke(Iterator $collection): string - { - $glue = $this->glue; - - $callback = - /** - * @psalm-param TKey $key - * @psalm-param CachingIterator $iterator - * - * @param mixed $key - * @param mixed $iterator - */ - static function (string $carry, string $item, $key, CachingIterator $iterator) use ($glue): string { - $carry .= $item; - - if ($iterator->hasNext()) { - $carry .= $glue; - } - - return $carry; - }; - - return (string) (new Transform(new FoldLeft($callback, '')))(new CachingIterator($collection)); - } -} diff --git a/src/Transformation/Nullsy.php b/src/Transformation/Nullsy.php deleted file mode 100644 index 8b6d46aa4..000000000 --- a/src/Transformation/Nullsy.php +++ /dev/null @@ -1,32 +0,0 @@ - - */ -final class Nullsy implements Transformation -{ - /** - * @psalm-param Iterator $collection - */ - public function __invoke(Iterator $collection): bool - { - foreach ($collection as $key => $value) { - if (null !== $value) { - return false; - } - } - - return true; - } -} diff --git a/src/Transformation/Reduce.php b/src/Transformation/Reduce.php deleted file mode 100644 index b777c0369..000000000 --- a/src/Transformation/Reduce.php +++ /dev/null @@ -1,56 +0,0 @@ - - */ -final class Reduce implements Transformation -{ - /** - * @var callable - * @psalm-var callable(T|null, T|null, TKey):(T|null) - */ - private $callback; - - /** - * @var mixed|null - * @psalm-var T|null - */ - private $initial; - - /** - * @psalm-param callable(T|null, T|null, TKey):(T|null) $callback - * - * @param mixed|null $initial - * @psalm-param T|null $initial - */ - public function __construct(callable $callback, $initial = null) - { - $this->callback = $callback; - $this->initial = $initial; - } - - /** - * @psalm-param Iterator $collection - * - * @return mixed|null - * @psalm-return T|scalar|null|\Iterator - */ - public function __invoke(Iterator $collection) - { - $callback = $this->callback; - $initial = $this->initial; - - return (new Transform(new FoldLeft($callback, $initial)))($collection); - } -} diff --git a/src/Transformation/Run.php b/src/Transformation/Run.php deleted file mode 100644 index 43ed7682f..000000000 --- a/src/Transformation/Run.php +++ /dev/null @@ -1,47 +0,0 @@ - - */ -final class Run implements Transformation -{ - /** - * @var ArrayIterator - */ - private $operations; - - public function __construct(Operation ...$operations) - { - $this->operations = new ArrayIterator($operations); - } - - public function __invoke(Iterator $collection): Iterator - { - return ( - new FoldLeft( - static function (Iterator $collection, Operation $operation): ClosureIterator { - return new ClosureIterator( - $operation(), - $collection, - ...array_values($operation->getArguments()) - ); - }, - $collection - ) - )($this->operations); - } -} diff --git a/src/Transformation/Transform.php b/src/Transformation/Transform.php deleted file mode 100644 index e316c7d50..000000000 --- a/src/Transformation/Transform.php +++ /dev/null @@ -1,57 +0,0 @@ - - */ -final class Transform implements Transformation -{ - /** - * @var ArrayIterator> - */ - private $transformers; - - /** - * @param \loophp\collection\Contract\Transformation ...$transformers - */ - public function __construct(Transformation ...$transformers) - { - $this->transformers = new ArrayIterator($transformers); - } - - /** - * @psalm-param Iterator $collection - * - * @return mixed|null - * @psalm-return Iterator|T - */ - public function __invoke(Iterator $collection) - { - return (new FoldLeft( - /** - * @psalm-param Iterator $collection - * @psalm-param Transformation $transformer - * @psalm-param TKey $key - * - * @param mixed $key - * - * @psalm-return T - */ - static function (Iterator $collection, Transformation $transformer, $key) { - return $transformer($collection); - }, - $collection - ))($this->transformers); - } -} diff --git a/src/Transformation/Truthy.php b/src/Transformation/Truthy.php deleted file mode 100644 index c643a27b2..000000000 --- a/src/Transformation/Truthy.php +++ /dev/null @@ -1,29 +0,0 @@ - - */ -final class Truthy implements Transformation -{ - public function __invoke(Iterator $collection): bool - { - foreach ($collection as $key => $value) { - if (false === (bool) $value) { - return false; - } - } - - return true; - } -}