Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update various typing information #196

Merged
merged 10 commits into from
Sep 16, 2021
28 changes: 2 additions & 26 deletions docs/pages/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -287,32 +287,8 @@ Interface: `Associateable`_

Signature: ``Collection::associate(?callable $callbackForKeys = null, ?callable $callbackForValues = null): Collection;``

.. code-block:: php

$input = range(1, 10);

Collection::fromIterable($input)
->associate(
static function ($key, $value) {
return $key * 2;
},
static function ($key, $value) {
return $value * 2;
}
);

// [
// 0 => 2,
// 2 => 4,
// 4 => 6,
// 6 => 8,
// 8 => 10,
// 10 => 12,
// 12 => 14,
// 14 => 16,
// 16 => 18,
// 18 => 20,
// ]
.. literalinclude:: code/operations/associate.php
:language: php

asyncMap
~~~~~~~~
Expand Down
72 changes: 72 additions & 0 deletions docs/pages/code/operations/associate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

/**
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

declare(strict_types=1);

namespace App;

use loophp\collection\Collection;

include __DIR__ . '/../../../../vendor/autoload.php';

// Example 1: Both callbacks are provided
$input = range(1, 5);

Collection::fromIterable($input)
->associate(
static function ($key, $value) {
return $key * 2;
},
static function ($value, $key) {
return $value * 3;
}
);

// [
// 0 => 3,
// 2 => 6,
// 4 => 9,
// 6 => 12,
// 8 => 15,
// ]

// Example 2: Only the callback for keys is provided
$input = range(1, 5);

Collection::fromIterable($input)
->associate(
static function ($key, $value) {
return $key * 2;
}
);

// [
// 0 => 1,
// 2 => 2,
// 4 => 3,
// 6 => 4,
// 8 => 5,
// ]

// Example 3: Only the callback for values is provided
$input = range(1, 5);

Collection::fromIterable($input)
->associate(
null,
static function ($value, $key) {
return $value * 3;
}
);

// [
// 0 => 3,
// 1 => 6,
// 2 => 9,
// 3 => 12,
// 4 => 15,
// ]
13 changes: 12 additions & 1 deletion phpstan-unsupported-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ parameters:
path: src/Collection.php

-
message: "#^Generic type loophp\\\\collection\\\\Contract\\\\Operation\\\\Unpackable\\<mixed, mixed\\> in PHPDoc tag @extends does not specify all template types of interface loophp\\\\collection\\\\Contract\\\\Operation\\\\Unpackable\\: TKey, T, NewTKey, NewT$#"
message: "#^Generic type loophp\\\\collection\\\\Contract\\\\Operation\\\\Unpackable\\<mixed, array\\<int, mixed\\>\\> in PHPDoc tag @extends does not specify all template types of interface loophp\\\\collection\\\\Contract\\\\Operation\\\\Unpackable\\: TKey, T, NewTKey, NewT$#"
count: 1
path: src/Contract/Collection.php

Expand All @@ -20,7 +20,18 @@ parameters:
count: 1
path: src/Contract/Operation/Unpackable.php

-
message: "#^Parameter \\#1 \\$callable of class loophp\\\\collection\\\\Iterator\\\\ClosureIterator constructor expects callable\\(\\.\\.\\.mixed\\)\\: iterable\\<int, string\\>, Closure\\(mixed, bool\\)\\: Generator\\<int, string, mixed, void\\> given\\.$#"
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only part (The 2 new entries in this file) that I cannot fix. If you have any idea, just let me know.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's a bit difficult to tell at a glance, but leave this will me I will try to see if I can figure out the problem and fix it

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, thanks! :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@drupol so after testing I realised this happens when passing a callable which takes multiple parameters, both to the ClosureIterator and the Collection object itself. Why? I'm not entirely sure but see the latest commit and the other comment for the changes I did and let me know if you think that works

count: 1
path: src/Iterator/ResourceIterator.php

-
message: "#^Parameter \\#1 \\$callable of class loophp\\\\collection\\\\Iterator\\\\ClosureIterator constructor expects callable\\(\\.\\.\\.mixed\\)\\: iterable, Closure\\(Iterator, callable\\(\\)\\: mixed\\)\\: Generator\\<mixed, mixed, mixed, void\\> given\\.$#"
count: 1
path: src/Iterator/TypedIterator.php

-
message: "#^PHPDoc tag @template T for class loophp\\\\collection\\\\Operation\\\\Unpack with bound type array\\<int, NewT\\|NewTKey\\> is not supported\\.$#"
count: 1
path: src/Operation/Unpack.php

4 changes: 2 additions & 2 deletions spec/loophp/collection/CollectionSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -225,10 +225,10 @@ public function it_can_associate(): void

$this::fromIterable($input)
->associate(
static function (int $carry, int $key, int $value): int {
static function (int $key, int $value): int {
return $key * 2;
},
static function (int $carry, int $key, int $value): int {
static function (int $value, int $key): int {
return $value * 2;
}
)
Expand Down
10 changes: 5 additions & 5 deletions src/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@
final class Collection implements CollectionInterface
{
/**
* @var iterable<mixed>
* @var iterable<int, mixed>
*/
private iterable $parameters;

Expand All @@ -167,7 +167,7 @@ final class Collection implements CollectionInterface
* @psalm-external-mutation-free
*
* @param callable(mixed ...$parameters): iterable<TKey, T> $callable
* @param iterable<array-key, mixed> $parameters
* @param iterable<int, mixed> $parameters
*/
private function __construct(callable $callable, iterable $parameters = [])
{
Expand Down Expand Up @@ -196,9 +196,9 @@ public function associate(
): CollectionInterface {
$defaultCallback =
/**
* @param T|TKey $carry
* @param mixed $carry
*
* @return T|TKey
* @return mixed
*/
static fn ($carry) => $carry;

Expand Down Expand Up @@ -449,7 +449,7 @@ public function frequency(): CollectionInterface
* @template NewT
*
* @param callable(mixed ...$parameters): iterable<NewTKey, NewT> $callable
* @param iterable<mixed> $parameters
* @param iterable<int, mixed> $parameters
*
* @return self<NewTKey, NewT>
*/
Expand Down
2 changes: 1 addition & 1 deletion src/Contract/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@
* @template-extends Transposeable<TKey, T>
* @template-extends Truthyable<TKey, T>
* @template-extends Unlinesable<TKey, T>
* @template-extends Unpackable<TKey, T>
* @template-extends Unpackable<mixed, array{0: TKey, 1: T}>
* @template-extends Unpairable<TKey, T>
* @template-extends Untilable<TKey, T>
* @template-extends Unwindowable<TKey, T>
Expand Down
9 changes: 6 additions & 3 deletions src/Contract/Operation/Associateable.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@ interface Associateable
*
* @see https://loophp-collection.readthedocs.io/en/stable/pages/api.html#associate
*
* @param null|callable(TKey, TKey, T, Iterator<TKey, T>):(T|TKey) $callbackForKeys
* @param null|callable(T, TKey, T, Iterator<TKey, T>):(T|TKey) $callbackForValues
* @template NewT
* @template NewTKey
*
* @return Collection<T|TKey, T|TKey>
* @param callable(TKey=, T=, Iterator<TKey, T>=): NewTKey $callbackForKeys
* @param callable(T=, TKey=, Iterator<TKey, T>=): NewT $callbackForValues
*
* @return Collection<NewTKey, NewT>
*/
public function associate(?callable $callbackForKeys = null, ?callable $callbackForValues = null): Collection;
}
7 changes: 5 additions & 2 deletions src/Contract/Operation/Zipable.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@ interface Zipable
*
* @see https://loophp-collection.readthedocs.io/en/stable/pages/api.html#zip
*
* @param iterable<mixed, mixed> ...$iterables
* @template U
* @template UKey
*
* @return Collection<list<mixed>, list<mixed>>
* @param iterable<UKey, U> ...$iterables
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know that it's not possible to type this thing as it is a variadic parameter.

I don't know if it's a good idea, but I had the idea to do the typing of only one element, knowing that it would not be completely valid if there are more than one parameters given.

WDYT?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get what you're looking to do here. The only issue is that when a user will try to use it with multiple iterables of different types they will get an error and so think that it's not supposed to be used like that.

I'm not sure how people normally use zip, maybe it wouldn't be an issue if most often it's used with a single type.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I leave this question open as I don't have any idea yet on what is best to do...

*
* @return Collection<list<TKey|UKey>, list<T|U>>
*/
public function zip(iterable ...$iterables): Collection;
}
6 changes: 3 additions & 3 deletions src/Iterator/ClosureIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ final class ClosureIterator extends ProxyIterator

/**
* @param callable(mixed ...$parameters): iterable<TKey, T> $callable
* @param iterable<mixed> $parameters
* @param iterable<int, mixed> $parameters
*/
public function __construct(callable $callable, iterable $parameters)
{
Expand All @@ -48,10 +48,10 @@ public function rewind(): void
}

/**
* @return Generator<TKey, T>
* @return Generator<TKey, T, mixed, void>
*/
private function getGenerator(): Generator
{
return yield from ($this->callable)(...$this->parameters);
yield from ($this->callable)(...$this->parameters);
}
}
7 changes: 3 additions & 4 deletions src/Iterator/ResourceIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

use Generator;
use InvalidArgumentException;
use IteratorIterator;

use function is_resource;

Expand All @@ -38,9 +37,9 @@ public function __construct($resource, bool $closeResource = false)
/**
* @param resource $resource
*
* @return Generator<int, string>
* @return Generator<int, string, mixed, void>
*/
static function ($resource) use ($closeResource): Generator {
static function ($resource, bool $closeResource): Generator {
try {
while (false !== $chunk = fgetc($resource)) {
yield $chunk;
Expand All @@ -52,6 +51,6 @@ static function ($resource) use ($closeResource): Generator {
}
};

$this->iterator = new IteratorIterator($callback($resource));
$this->iterator = new ClosureIterator($callback, [$resource, $closeResource]);
}
}
12 changes: 9 additions & 3 deletions src/Iterator/TypedIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ final class TypedIterator extends ProxyIterator
{
/**
* @param Iterator<TKey, T> $iterator
* @param null|callable(mixed): string $getType
* @param callable(T): string $getType
drupol marked this conversation as resolved.
Show resolved Hide resolved
*/
public function __construct(Iterator $iterator, ?callable $getType = null)
{
Expand All @@ -55,7 +55,13 @@ static function ($variable): string {
};

$this->iterator = new ClosureIterator(
static function (Iterator $iterator) use ($getType): Generator {
/**
* @param Iterator<TKey, T> $iterator
* @param callable(T): string $getType
*
* @return Generator<TKey, T|null>
*/
static function (Iterator $iterator, callable $getType): Generator {
$previousType = null;

foreach ($iterator as $key => $value) {
Expand All @@ -81,7 +87,7 @@ static function (Iterator $iterator) use ($getType): Generator {
yield $key => $value;
}
},
[$iterator]
[$iterator, $getType]
);
}
}
52 changes: 12 additions & 40 deletions src/Operation/Associate.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

namespace loophp\collection\Operation;

use ArrayIterator;
use Closure;
use Generator;
use Iterator;
Expand All @@ -27,61 +26,34 @@ final class Associate extends AbstractOperation
/**
* @pure
*
* @return Closure(callable(TKey, TKey, T, Iterator<TKey, T>): (T|TKey) ...): Closure((callable(T, TKey, T, Iterator<TKey, T>): (T|TKey))...): Closure(Iterator<TKey, T>): Generator<TKey|T, T|TKey>
* @template NewTKey
* @template NewT
*
* @return Closure(callable(TKey=, T=, Iterator<TKey, T>=): NewTKey): Closure(callable(T=, TKey=, Iterator<TKey, T>=): NewT): Closure(Iterator<TKey, T>): Generator<NewTKey, NewT>
*/
public function __invoke(): Closure
{
return
/**
* @param callable(TKey, TKey, T, Iterator<TKey, T>): (T|TKey) ...$callbackForKeys
* @param callable(TKey=, T=, Iterator<TKey, T>=): NewTKey $callbackForKeys
*
* @return Closure((callable(T, TKey, T, Iterator<TKey, T>): (T|TKey))...): Closure(Iterator<TKey, T>): Generator<TKey|T, T|TKey>
* @return Closure((callable(T=, TKey=, Iterator<TKey, T>=): NewT)): Closure(Iterator<TKey, T>): Generator<NewTKey, NewT>
*/
static fn (callable ...$callbackForKeys): Closure =>
static fn (callable $callbackForKeys): Closure =>
/**
* @param callable(T, TKey, T, Iterator<TKey, T>): (T|TKey) ...$callbackForValues
* @param callable(T=, TKey=, Iterator<TKey, T>=): NewT $callbackForValues
*
* @return Closure(Iterator<TKey, T>): Generator<TKey|T, T|TKey>
* @return Closure(Iterator<TKey, T>): Generator<NewTKey, NewT>
*/
static fn (callable ...$callbackForValues): Closure =>
static fn (callable $callbackForValues): Closure =>
/**
* @param Iterator<TKey, T> $iterator
*
* @return Generator<T|TKey, T|TKey>
* @return Generator<NewTKey, NewT>
*/
static function (Iterator $iterator) use ($callbackForKeys, $callbackForValues): Generator {
$callbackFactory =
/**
* @param TKey $key
*
* @return Closure(T): Closure(T|TKey, callable(T|TKey, TKey, T, Iterator<TKey, T>): (T|TKey), int, Iterator<TKey, T>): (T|TKey)
*/
static fn ($key): Closure =>
/**
* @param T $value
*
* @return Closure(T|TKey, callable(T|TKey, TKey, T, Iterator<TKey, T>): (T|TKey), int, Iterator<TKey, T>): (T|TKey)
*/
static fn ($value): Closure =>
/**
* @param T|TKey $accumulator
* @param callable(T|TKey, TKey, T, Iterator<TKey, T>): (T|TKey) $callback
* @param Iterator<TKey, T> $iterator
*
* @return T|TKey
*/
static fn ($accumulator, callable $callback, int $callbackId, Iterator $iterator) => $callback($accumulator, $key, $value, $iterator);

foreach ($iterator as $key => $value) {
$reduceCallback = $callbackFactory($key)($value);

/** @var Generator<int, T|TKey> $k */
$k = Reduce::of()($reduceCallback)($key)(new ArrayIterator($callbackForKeys));

/** @var Generator<int, T|TKey> $c */
$c = Reduce::of()($reduceCallback)($value)(new ArrayIterator($callbackForValues));

yield $k->current() => $c->current();
yield $callbackForKeys($key, $value, $iterator) => $callbackForValues($value, $key, $iterator);
}
};
}
Expand Down
Loading