Skip to content

Commit

Permalink
feat: Add InterruptableIterableAggregate.
Browse files Browse the repository at this point in the history
  • Loading branch information
drupol committed Jun 13, 2022
1 parent 1010776 commit 11c558a
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 5 deletions.
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ The missing PHP iterators.
* `ClosureIterator`: `ClosureIterator(callable $callable, array $arguments = [])`
* `ClosureIteratorAggregate`: `ClosureIteratorAggregate(callable $callable, array $arguments = [])`
* `ConcatIterableAggregate`
* `InterruptableIterableAggregate`: `InterruptableIterableAggregate(iterable $iterable)`
* `IterableIterator`: `IterableIterator(iterable $iterable)`
* `IterableIteratorAggregate`: `IterableIteratorAggregate(iterable $iterable)`
* `MultipleIterableAggregate`
Expand Down Expand Up @@ -69,6 +70,35 @@ foreach ($iterator as $key => $value); // This will work.
foreach ($iterator as $key => $value); // This will also work.
```

### InterruptableIterableAggregate

Let you break the iterator at anytime.

Useful when working with infinite collection of items.

```php
<?php

// Generator
$naturals = static function () {
$i = 0;

while (true) {
yield $i++;
}
};

$iterator = new InterruptableIterableAggregate($generator());

foreach ($iterator as $generator => [$key, $value]) {
var_dump($value);

if (10 === $value) {
$generator->send(InterruptableIterableAggregate::BREAK);
}
}
```

### PackIterableAggregate

```php
Expand Down
10 changes: 5 additions & 5 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="v4.15.0@a1b5e489e6fcebe40cb804793d964e99fc347820">
<file src="src/RandomIterableAggregate.php">
<InvalidPropertyAssignmentValue occurrences="1">
<code>new PackIterableAggregate($iterable)</code>
</InvalidPropertyAssignmentValue>
<files psalm-version="4.23.0@f1fe6ff483bf325c803df9f510d09a03fd796f88">
<file src="src/InterruptableIteratorAggregate.php">
<ImplementedReturnTypeMismatch occurrences="1">
<code>Generator&lt;Generator&lt;TKey, T&gt;, array{0: TKey, 1: T}&gt;</code>
</ImplementedReturnTypeMismatch>
</file>
</files>
64 changes: 64 additions & 0 deletions src/InterruptableIteratorAggregate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?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 loophp\iterators;

use Generator;
use IteratorAggregate;

/**
* @template TKey
* @template T
*
* @implements IteratorAggregate<TKey, T>
*/
final class InterruptableIteratorAggregate implements IteratorAggregate
{
public const BREAK = 'break';

/**
* @var iterable<TKey, T>
*/
private iterable $iterable;

/**
* @param iterable<TKey, T> $iterable
*/
public function __construct(iterable $iterable)
{
$this->iterable = $iterable;
}

/**
* @return Generator<Generator<TKey, T>, array{0: TKey, 1: T}>
*/
public function getIterator(): Generator
{
$generator = $this->getGenerator();

foreach ($generator as $key => $value) {
yield $generator => [$key, $value];
}
}

/**
* @return Generator<TKey, T>
*/
private function getGenerator(): Generator
{
foreach ($this->iterable as $key => $value) {
/** @var mixed $return */
$return = yield $key => $value;

if (self::BREAK === $return) {
break;
}
}
}
}
51 changes: 51 additions & 0 deletions tests/unit/InterruptableIteratorAggregateTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?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 tests\loophp\iterators;

use Generator;
use IteratorAggregate;
use loophp\iterators\InterruptableIteratorAggregate;
use PHPUnit\Framework\TestCase;

/**
* @internal
* @coversDefaultClass \loophp\iterators
*/
final class InterruptableIteratorAggregateTest extends TestCase
{
public function testBreakInterruption()
{
$naturals = static function () {
$i = 0;

while (true) {
yield $i++;
}
};

$subject = new InterruptableIteratorAggregate($naturals());

self::assertSame(
range(0, 10),
iterator_to_array($this->getSubjectGenerator($subject))
);
}

private function getSubjectGenerator(IteratorAggregate $subject): Generator
{
foreach ($subject as $generator => [$key, $value]) {
yield $key => $value;

if (10 === $value) {
$generator->send(InterruptableIteratorAggregate::BREAK);
}
}
}
}

0 comments on commit 11c558a

Please sign in to comment.