From 699e6f81c66d1dae182e74173edb0881991403e4 Mon Sep 17 00:00:00 2001 From: azjezz Date: Wed, 19 May 2021 12:33:22 +0100 Subject: [PATCH] fix strict type ignored when mapping or filtering arrays --- docs/component/vec.md | 8 ++++---- src/Psl/Dict/filter.php | 8 +++++++- src/Psl/Dict/filter_keys.php | 9 ++++++++- src/Psl/Iter/contains_key.php | 2 +- src/Psl/Vec/filter.php | 14 ++++++++++++++ src/Psl/Vec/filter_keys.php | 17 +++++++++++++++++ src/Psl/Vec/filter_nulls.php | 17 ++++++++--------- src/Psl/Vec/filter_with_key.php | 18 ++++++++++++++++++ src/Psl/Vec/map.php | 14 ++++++++++++++ tests/Psl/Dict/MapTest.php | 7 +++++-- tests/Psl/Vec/FilterKeysTest.php | 8 ++++++-- tests/Psl/Vec/FilterWithKeyTest.php | 9 +++++++-- tests/Psl/Vec/MapTest.php | 9 +++++++-- 13 files changed, 116 insertions(+), 24 deletions(-) diff --git a/docs/component/vec.md b/docs/component/vec.md index 685d86bf..d545e753 100644 --- a/docs/component/vec.md +++ b/docs/component/vec.md @@ -17,13 +17,13 @@ - [concat](./../../src/Psl/Vec/concat.php#L17) - [enumerate](./../../src/Psl/Vec/enumerate.php#L17) - [fill](./../../src/Psl/Vec/fill.php#L24) -- [filter](./../../src/Psl/Vec/filter.php#L30) -- [filter_keys](./../../src/Psl/Vec/filter_keys.php#L31) +- [filter](./../../src/Psl/Vec/filter.php#L34) +- [filter_keys](./../../src/Psl/Vec/filter_keys.php#L37) - [filter_nulls](./../../src/Psl/Vec/filter_nulls.php#L20) -- [filter_with_key](./../../src/Psl/Vec/filter_with_key.php#L34) +- [filter_with_key](./../../src/Psl/Vec/filter_with_key.php#L40) - [flat_map](./../../src/Psl/Vec/flat_map.php#L16) - [keys](./../../src/Psl/Vec/keys.php#L20) -- [map](./../../src/Psl/Vec/map.php#L27) +- [map](./../../src/Psl/Vec/map.php#L31) - [map_with_key](./../../src/Psl/Vec/map_with_key.php#L27) - [partition](./../../src/Psl/Vec/partition.php#L18) - [range](./../../src/Psl/Vec/range.php#L50) diff --git a/src/Psl/Dict/filter.php b/src/Psl/Dict/filter.php index 138be908..a5696e77 100644 --- a/src/Psl/Dict/filter.php +++ b/src/Psl/Dict/filter.php @@ -37,7 +37,13 @@ function filter(iterable $iterable, ?callable $predicate = null): array $predicate = $predicate ?? Closure::fromCallable('Psl\Internal\boolean'); if (is_array($iterable)) { - return array_filter($iterable, $predicate); + return array_filter( + $iterable, + /** + * @param Tv $v + */ + static fn($v): bool => $predicate($v) + ); } $result = []; diff --git a/src/Psl/Dict/filter_keys.php b/src/Psl/Dict/filter_keys.php index cb10ef17..1e15e9d1 100644 --- a/src/Psl/Dict/filter_keys.php +++ b/src/Psl/Dict/filter_keys.php @@ -39,7 +39,14 @@ function filter_keys(iterable $iterable, ?callable $predicate = null): array $predicate = $predicate ?? Closure::fromCallable('Psl\Internal\boolean'); if (is_array($iterable)) { - return array_filter($iterable, $predicate, ARRAY_FILTER_USE_KEY); + return array_filter( + $iterable, + /** + * @param Tk $k + */ + static fn($k): bool => $predicate($k), + ARRAY_FILTER_USE_KEY + ); } $result = []; diff --git a/src/Psl/Iter/contains_key.php b/src/Psl/Iter/contains_key.php index 35376d90..ae29cdc9 100644 --- a/src/Psl/Iter/contains_key.php +++ b/src/Psl/Iter/contains_key.php @@ -10,7 +10,7 @@ * @template Tk * @template Tv * - * @param iterable $iterable, + * @param iterable $iterable * @param Tk $key */ function contains_key(iterable $iterable, $key): bool diff --git a/src/Psl/Vec/filter.php b/src/Psl/Vec/filter.php index 226bd797..2960fc62 100644 --- a/src/Psl/Vec/filter.php +++ b/src/Psl/Vec/filter.php @@ -6,6 +6,10 @@ use Closure; +use function array_filter; +use function array_values; +use function is_array; + /** * Returns a vec containing only the values for which the given predicate * returns `true`. @@ -31,6 +35,16 @@ function filter(iterable $iterable, ?callable $predicate = null): array { /** @var (callable(T): bool) $predicate */ $predicate = $predicate ?? Closure::fromCallable('Psl\Internal\boolean'); + if (is_array($iterable)) { + return array_values(array_filter( + $iterable, + /** + * @param T $t + */ + static fn($t): bool => $predicate($t) + )); + } + $result = []; foreach ($iterable as $v) { if ($predicate($v)) { diff --git a/src/Psl/Vec/filter_keys.php b/src/Psl/Vec/filter_keys.php index aebf5ae7..54b4ba74 100644 --- a/src/Psl/Vec/filter_keys.php +++ b/src/Psl/Vec/filter_keys.php @@ -6,6 +6,12 @@ use Closure; +use function array_filter; +use function array_values; +use function is_array; + +use const ARRAY_FILTER_USE_KEY; + /** * Returns a vec containing only the values for which the given predicate * returns `true`. @@ -32,6 +38,17 @@ function filter_keys(iterable $iterable, ?callable $predicate = null): array { /** @var (callable(Tk): bool) $predicate */ $predicate = $predicate ?? Closure::fromCallable('Psl\Internal\boolean'); + if (is_array($iterable)) { + return array_values(array_filter( + $iterable, + /** + * @param Tk $t + */ + static fn($t): bool => $predicate($t), + ARRAY_FILTER_USE_KEY + )); + } + $result = []; foreach ($iterable as $k => $v) { if ($predicate($k)) { diff --git a/src/Psl/Vec/filter_nulls.php b/src/Psl/Vec/filter_nulls.php index 5fc8aa16..fd0cc4c6 100644 --- a/src/Psl/Vec/filter_nulls.php +++ b/src/Psl/Vec/filter_nulls.php @@ -19,13 +19,12 @@ */ function filter_nulls(iterable $iterable): array { - /** @var list $result */ - $result = []; - foreach ($iterable as $value) { - if (null !== $value) { - $result[] = $value; - } - } - - return $result; + /** @var list */ + return filter( + $iterable, + /** + * @param T|null $value + */ + static fn($value): bool => null !== $value + ); } diff --git a/src/Psl/Vec/filter_with_key.php b/src/Psl/Vec/filter_with_key.php index 69fcede0..fca36f5d 100644 --- a/src/Psl/Vec/filter_with_key.php +++ b/src/Psl/Vec/filter_with_key.php @@ -6,6 +6,12 @@ use Psl; +use function array_filter; +use function array_values; +use function is_array; + +use const ARRAY_FILTER_USE_BOTH; + /** * Returns a vec containing only the values for which the given predicate * returns `true`. @@ -40,6 +46,18 @@ function filter_with_key(iterable $iterable, ?callable $predicate = null): array */ static fn ($_k, $v): bool => Psl\Internal\boolean($v); + if (is_array($iterable)) { + return array_values(array_filter( + $iterable, + /** + * @param Tv $v + * @param Tk $k + */ + static fn($v, $k): bool => $predicate($k, $v), + ARRAY_FILTER_USE_BOTH + )); + } + $result = []; foreach ($iterable as $k => $v) { if ($predicate($k, $v)) { diff --git a/src/Psl/Vec/map.php b/src/Psl/Vec/map.php index 7c42d6b7..6e41a1b2 100644 --- a/src/Psl/Vec/map.php +++ b/src/Psl/Vec/map.php @@ -4,6 +4,10 @@ namespace Psl\Vec; +use function array_map; +use function array_values; +use function is_array; + /** * Applies a mapping function to all values of an iterable. * @@ -26,6 +30,16 @@ */ function map(iterable $iterable, callable $function): array { + if (is_array($iterable)) { + return array_values(array_map( + /** + * @param Tv $v + */ + static fn($v) => $function($v), + $iterable + )); + } + $result = []; foreach ($iterable as $value) { $result[] = $function($value); diff --git a/tests/Psl/Dict/MapTest.php b/tests/Psl/Dict/MapTest.php index 4166b9f7..feee5b4b 100644 --- a/tests/Psl/Dict/MapTest.php +++ b/tests/Psl/Dict/MapTest.php @@ -5,6 +5,7 @@ namespace Psl\Tests\Dict; use PHPUnit\Framework\TestCase; +use Psl\Collection; use Psl\Dict; final class MapTest extends TestCase @@ -12,9 +13,9 @@ final class MapTest extends TestCase /** * @dataProvider provideData */ - public function testMap(array $expected, array $array, callable $function): void + public function testMap(array $expected, iterable $iterable, callable $function): void { - $result = Dict\map($array, $function); + $result = Dict\map($iterable, $function); static::assertSame($expected, $result); } @@ -24,6 +25,8 @@ public function provideData(): iterable yield [[1, 2, 3], [1, 2, 3], static fn (int $v): int => $v]; yield [[2, 4, 6], [1, 2, 3], static fn (int $v): int => $v * 2]; yield [['1', '2', '3'], [1, 2, 3], static fn (int $v): string => (string)$v]; + yield [['1', '2', '3'], Collection\Map::fromArray([1, 2, 3]), static fn (int $v): string => (string)$v]; + yield [[], Collection\Map::fromArray([]), static fn (int $v): string => (string)$v]; yield [[], [], static fn (int $v): string => (string)$v]; } } diff --git a/tests/Psl/Vec/FilterKeysTest.php b/tests/Psl/Vec/FilterKeysTest.php index 69145bba..cb4c7f30 100644 --- a/tests/Psl/Vec/FilterKeysTest.php +++ b/tests/Psl/Vec/FilterKeysTest.php @@ -5,6 +5,7 @@ namespace Psl\Tests\Vec; use PHPUnit\Framework\TestCase; +use Psl\Collection; use Psl\Vec; final class FilterKeysTest extends TestCase @@ -12,9 +13,9 @@ final class FilterKeysTest extends TestCase /** * @dataProvider provideData */ - public function testFilter(array $expected, array $array, ?callable $predicate = null): void + public function testFilter(array $expected, iterable $iterable, ?callable $predicate = null): void { - $result = Vec\filter_keys($array, $predicate); + $result = Vec\filter_keys($iterable, $predicate); static::assertSame($expected, $result); } @@ -25,6 +26,9 @@ public function provideData(): iterable yield [['b'], ['a', 'b']]; yield [['a'], ['a', 'b'], static fn (int $k): bool => $k !== 1]; yield [['b'], ['a', 'b'], static fn (int $k): bool => $k !== 0]; + yield [['b'], Collection\Vector::fromArray(['a', 'b']), static fn (int $k): bool => $k !== 0]; + yield [[], Collection\Vector::fromArray(['a', 'b']), static fn (int $k): bool => false]; + yield [[], Collection\Vector::fromArray([]), static fn (int $k): bool => false]; yield [[], ['a', 'b'], static fn (int $_) => false]; yield [['a', 'b'], ['a', 'b'], static fn (int $_): bool => true]; } diff --git a/tests/Psl/Vec/FilterWithKeyTest.php b/tests/Psl/Vec/FilterWithKeyTest.php index 5dd8e6cf..59f71482 100644 --- a/tests/Psl/Vec/FilterWithKeyTest.php +++ b/tests/Psl/Vec/FilterWithKeyTest.php @@ -5,6 +5,7 @@ namespace Psl\Tests\Vec; use PHPUnit\Framework\TestCase; +use Psl\Collection; use Psl\Vec; final class FilterWithKeyTest extends TestCase @@ -12,9 +13,9 @@ final class FilterWithKeyTest extends TestCase /** * @dataProvider provideData */ - public function testFilterWithKey(array $expected, array $array, ?callable $predicate = null): void + public function testFilterWithKey(array $expected, iterable $iterable, ?callable $predicate = null): void { - $result = Vec\filter_with_key($array, $predicate); + $result = Vec\filter_with_key($iterable, $predicate); static::assertSame($expected, $result); } @@ -25,6 +26,10 @@ public function provideData(): iterable yield [['a', 'b'], ['a', 'b']]; yield [[], ['a', 'b'], static fn (int $_k, string $_v) => false]; yield [['a', 'b'], ['a', 'b'], static fn (int $_k, string $_v): bool => true]; + yield [[], Collection\Vector::fromArray([])]; + yield [['a', 'b'], Collection\Vector::fromArray(['a', 'b'])]; + yield [[], Collection\Vector::fromArray(['a', 'b']), static fn (int $_k, string $_v) => false]; + yield [['a', 'b'], Collection\Vector::fromArray(['a', 'b']), static fn (int $_k, string $_v): bool => true]; yield [['a'], ['a', 'b'], static fn (int $k, string $v): bool => 'b' !== $v]; yield [[], ['a', 'b'], static fn (int $k, string $v): bool => 'b' !== $v && 0 !== $k]; yield [['a'], ['a', 'b'], static fn (int $k, string $v): bool => 'b' !== $v && 1 !== $k]; diff --git a/tests/Psl/Vec/MapTest.php b/tests/Psl/Vec/MapTest.php index 72881a20..fc08c6d1 100644 --- a/tests/Psl/Vec/MapTest.php +++ b/tests/Psl/Vec/MapTest.php @@ -5,6 +5,7 @@ namespace Psl\Tests\Vec; use PHPUnit\Framework\TestCase; +use Psl\Collection; use Psl\Vec; final class MapTest extends TestCase @@ -12,9 +13,9 @@ final class MapTest extends TestCase /** * @dataProvider provideData */ - public function testMap(array $expected, array $array, callable $function): void + public function testMap(array $expected, iterable $iterable, callable $function): void { - $result = Vec\map($array, $function); + $result = Vec\map($iterable, $function); static::assertSame($expected, $result); } @@ -25,5 +26,9 @@ public function provideData(): iterable yield [[2, 4, 6], [1, 2, 3], static fn (int $v): int => $v * 2]; yield [['1', '2', '3'], [1, 2, 3], static fn (int $v): string => (string)$v]; yield [[], [], static fn (int $v): string => (string)$v]; + yield [[1, 2, 3], Collection\Vector::fromArray([1, 2, 3]), static fn (int $v): int => $v]; + yield [[2, 4, 6], Collection\Vector::fromArray([1, 2, 3]), static fn (int $v): int => $v * 2]; + yield [['1', '2', '3'], Collection\Vector::fromArray([1, 2, 3]), static fn (int $v): string => (string)$v]; + yield [[], Collection\Vector::fromArray([]), static fn (int $v): string => (string)$v]; } }