Passed
Pull Request — master (#306)
by Pol
03:58 queued 01:52
created

Collection::falsy()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
ccs 1
cts 1
cp 1
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace loophp\collection;
6
7
use Closure;
8
use Countable;
9
use Doctrine\Common\Collections\Criteria;
10
use Generator;
11
use JsonSerializable;
12
use loophp\collection\Contract\Collection as CollectionInterface;
13
use loophp\collection\Contract\Operation as OperationInterface;
14
use loophp\collection\Utils\CallbacksArrayReducer;
15
use loophp\iterators\ClosureIteratorAggregate;
16
use loophp\iterators\IterableIteratorAggregate;
17
use loophp\iterators\ResourceIteratorAggregate;
18
use loophp\iterators\StringIteratorAggregate;
19
use NoRewindIterator;
20
use Psr\Cache\CacheItemPoolInterface;
21
use Symfony\Component\Cache\Adapter\ArrayAdapter;
22
use Traversable;
23
24
use const INF;
25
use const PHP_INT_MAX;
26
27
/**
28
 * @immutable
29
 *
30
 * @template TKey
31
 * @template T
32
 *
33
 * @implements \loophp\collection\Contract\Collection<TKey, T>
34
 */
35
final class Collection implements CollectionInterface, JsonSerializable, Countable
36
{
37
    /**
38
     * @var ClosureIteratorAggregate<TKey, T>
39
     */
40
    private ClosureIteratorAggregate $innerIterator;
41
42
    /**
43
     * @param callable(mixed ...$parameters): iterable<TKey, T> $callable
44
     * @param iterable<int, mixed> $parameters
45
     */
46 707
    private function __construct(callable $callable, iterable $parameters = [])
47
    {
48 707
        $this->innerIterator = new ClosureIteratorAggregate($callable, $parameters);
49
    }
50
51 19
    public function all(bool $normalize = true): array
52
    {
53 19
        return iterator_to_array((new Operation\All())()($normalize)($this));
54
    }
55
56 2
    public function append(mixed ...$items): CollectionInterface
57
    {
58 2
        return new self((new Operation\Append())()($items), [$this]);
59
    }
60
61 4
    public function apply(callable ...$callbacks): CollectionInterface
62
    {
63 4
        return new self((new Operation\Apply())()(...$callbacks), [$this]);
64
    }
65
66 4
    public function associate(
67
        ?callable $callbackForKeys = null,
68
        ?callable $callbackForValues = null
69
    ): CollectionInterface {
70 4
        $defaultCallback = static fn (mixed $carry): mixed => $carry;
71
72 4
        return new self((new Operation\Associate())()($callbackForKeys ?? $defaultCallback)($callbackForValues ?? $defaultCallback), [$this]);
73
    }
74
75 2
    public function asyncMap(callable $callback): CollectionInterface
76
    {
77 2
        return new self((new Operation\AsyncMap())()($callback), [$this]);
78
    }
79
80 2
    public function asyncMapN(callable ...$callbacks): CollectionInterface
81
    {
82 2
        return new self((new Operation\AsyncMapN())()(...$callbacks), [$this]);
83
    }
84
85 4
    public function averages(): CollectionInterface
86
    {
87 4
        return new self((new Operation\Averages())(), [$this]);
88
    }
89
90 3
    public function cache(?CacheItemPoolInterface $cache = null): CollectionInterface
91
    {
92 3
        return new self((new Operation\Cache())()($cache ?? new ArrayAdapter()), [$this]);
93
    }
94
95 8
    public function chunk(int ...$sizes): CollectionInterface
96
    {
97 8
        return new self((new Operation\Chunk())()(...$sizes), [$this]);
98
    }
99
100 4
    public function coalesce(): CollectionInterface
101
    {
102 4
        return new self((new Operation\Coalesce())(), [$this]);
103
    }
104
105 4
    public function collapse(): CollectionInterface
106
    {
107 4
        return new self((new Operation\Collapse())(), [$this]);
108
    }
109
110 6
    public function column(mixed $column): CollectionInterface
111
    {
112 6
        return new self((new Operation\Column())()($column), [$this]);
113
    }
114
115 6
    public function combinate(?int $length = null): CollectionInterface
116
    {
117 6
        return new self((new Operation\Combinate())()($length), [$this]);
118
    }
119
120 6
    public function combine(mixed ...$keys): CollectionInterface
121
    {
122 6
        return new self((new Operation\Combine())()($keys), [$this]);
123
    }
124
125 4
    public function compact(mixed ...$values): CollectionInterface
126
    {
127 4
        return new self((new Operation\Compact())()($values), [$this]);
128
    }
129
130 10
    public function compare(callable $comparator, $default = null)
131
    {
132 10
        return (new self((new Operation\Compare())()($comparator), [$this]))->current(0, $default);
133
    }
134
135 10
    public function contains(mixed ...$values): bool
136
    {
137 10
        return (new Operation\Contains())()($values)($this)->current();
138
    }
139
140 8
    public function count(): int
141
    {
142 8
        return iterator_count($this);
143
    }
144
145 97
    public function countIn(int &$counter): CollectionInterface
146
    {
147 97
        $callback = static function () use (&$counter): void {
148
            ++$counter;
149
        };
150 4
151
        return new self((new Operation\Apply())()($callback), [$this]);
152 4
    }
153
154
    public function current(int $index = 0, $default = null)
155 14
    {
156
        return (new Operation\Current())()($index)($default)($this)->current();
157 14
    }
158
159
    public function cycle(): CollectionInterface
160 4
    {
161
        return new self((new Operation\Cycle())(), [$this]);
162 4
    }
163
164
    public function diff(mixed ...$values): CollectionInterface
165 12
    {
166
        return new self((new Operation\Diff())()($values), [$this]);
167 12
    }
168
169
    public function diffKeys(mixed ...$keys): CollectionInterface
170
    {
171
        return new self((new Operation\DiffKeys())()($keys), [$this]);
172
    }
173
174 12
    public function distinct(?callable $comparatorCallback = null, ?callable $accessorCallback = null): CollectionInterface
175
    {
176 12
        $accessorCallback ??=
177
            /**
178
             * @param T $value
0 ignored issues
show
Bug introduced by
The type loophp\collection\T was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
179
             * @param TKey $key
0 ignored issues
show
Bug introduced by
The type loophp\collection\TKey was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
180
             *
181
             * @return T
182 12
             */
183
            static fn (mixed $value, mixed $key): mixed => $value;
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

183
            static fn (mixed $value, /** @scrutinizer ignore-unused */ mixed $key): mixed => $value;

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
184
185
        $comparatorCallback ??=
186 8
            /**
187
             * @param T $left
188 12
             *
189
             * @return Closure(T): bool
190
             */
191 4
            static fn (mixed $left): Closure =>
192
                /**
193 4
                 * @param T $right
194
                 */
195
                static fn (mixed $right): bool => $left === $right;
196 4
197
        return new self((new Operation\Distinct())()($comparatorCallback)($accessorCallback), [$this]);
198 4
    }
199
200
    public function drop(int $count): CollectionInterface
201 4
    {
202
        return new self((new Operation\Drop())()($count), [$this]);
203 4
    }
204
205
    public function dropWhile(callable ...$callbacks): CollectionInterface
206 10
    {
207
        return new self((new Operation\DropWhile())()(...$callbacks), [$this]);
208 10
    }
209
210
    public function dump(string $name = '', int $size = 1, ?Closure $closure = null): CollectionInterface
211
    {
212
        return new self((new Operation\Dump())()($name)($size)($closure), [$this]);
213
    }
214
215 10
    public function duplicate(?callable $comparatorCallback = null, ?callable $accessorCallback = null): CollectionInterface
216
    {
217 10
        $accessorCallback ??=
218
            /**
219
             * @param T $value
220
             * @param TKey $key
221
             *
222
             * @return T
223 10
             */
224
            static fn (mixed $value, mixed $key): mixed => $value;
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

224
            static fn (mixed $value, /** @scrutinizer ignore-unused */ mixed $key): mixed => $value;

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
225
226
        $comparatorCallback ??=
227 6
            /**
228
             * @param T $left
229 10
             *
230
             * @return Closure(T): bool
231
             */
232
            static fn (mixed $left): Closure =>
233
                /**
234
                 * @param T $right
235
                 */
236
                static fn (mixed $right): bool => $left === $right;
237
238 4
        return new self((new Operation\Duplicate())()($comparatorCallback)($accessorCallback), [$this]);
239
    }
240 4
241
    /**
242
     * @template UKey
243 36
     * @template U
244
     *
245 36
     * @return self<UKey, U>
246
     */
247
    public static function empty(): CollectionInterface
248 16
    {
249
        return self::fromIterable([]);
250 16
    }
251 16
252
    public function equals(iterable $other): bool
253
    {
254 2
        return (new Operation\Equals())()($other)($this)->current();
255
    }
256 2
257
    public function every(callable ...$callbacks): bool
258
    {
259 8
        return (new Operation\Every())()(static fn (int $index, mixed $value, mixed $key, iterable $iterable): bool => CallbacksArrayReducer::or()($callbacks)($value, $key, $iterable))($this)
260
            ->current();
261 8
    }
262
263
    public function explode(mixed ...$explodes): CollectionInterface
264 8
    {
265
        return new self((new Operation\Explode())()($explodes), [$this]);
266 8
    }
267
268
    public function falsy(): bool
269 10
    {
270
        return (new Operation\Falsy())()($this)->current();
271 10
    }
272
273
    public function filter(callable ...$callbacks): CollectionInterface
274 10
    {
275
        return new self((new Operation\Filter())()(...$callbacks), [$this]);
276 10
    }
277
278
    public function find(mixed $default = null, callable ...$callbacks)
279 14
    {
280
        return (new Operation\Find())()($default)(...$callbacks)($this)->current();
281 14
    }
282
283
    public function first(mixed $default = null)
284 6
    {
285
        return (new self((new Operation\First())(), [$this]))->current(0, $default);
286 6
    }
287
288
    public function flatMap(callable $callback): CollectionInterface
289 4
    {
290
        return new self((new Operation\FlatMap())()($callback), [$this]);
291 4
    }
292
293
    public function flatten(int $depth = PHP_INT_MAX): CollectionInterface
294 8
    {
295
        return new self((new Operation\Flatten())()($depth), [$this]);
296 8
    }
297
298
    public function flip(): CollectionInterface
299 4
    {
300
        return new self((new Operation\Flip())(), [$this]);
301 4
    }
302
303
    public function foldLeft(callable $callback, mixed $initial)
304 2
    {
305
        return (new self((new Operation\FoldLeft())()($callback)($initial), [$this]))->current();
306 2
    }
307
308
    public function foldLeft1(callable $callback): mixed
309 4
    {
310
        return (new self((new Operation\FoldLeft1())()($callback), [$this]))->current();
311 4
    }
312
313
    public function foldRight(callable $callback, mixed $initial): mixed
314 2
    {
315
        return (new self((new Operation\FoldRight())()($callback)($initial), [$this]))->current();
316 2
    }
317
318
    public function foldRight1(callable $callback): mixed
319 2
    {
320
        return (new self((new Operation\FoldRight1())()($callback), [$this]))->current();
321 2
    }
322
323
    public function forget(mixed ...$keys): CollectionInterface
324
    {
325
        return new self((new Operation\Forget())()($keys), [$this]);
326
    }
327
328
    public function frequency(): CollectionInterface
329
    {
330
        return new self((new Operation\Frequency())(), [$this]);
331
    }
332
333 3
    /**
334
     * @template NewTKey
335 3
     * @template NewT
336
     *
337
     * @param callable(mixed ...$parameters): iterable<NewTKey, NewT> $callable
338
     * @param iterable<int, mixed> $parameters
339
     *
340
     * @return self<NewTKey, NewT>
341 2
     */
342
    public static function fromCallable(callable $callable, iterable $parameters = []): CollectionInterface
343 2
    {
344 2
        return new self($callable, $parameters);
345 2
    }
346
347
    /**
348
     * @return self<int, string>
349
     */
350
    public static function fromFile(string $filepath): CollectionInterface
351
    {
352
        return new self(
353
            static fn (): Generator => yield from new ResourceIteratorAggregate(fopen($filepath, 'rb'), true),
354
        );
355
    }
356 2
357
    /**
358 2
     * @template NewTKey
359
     * @template NewT
360
     *
361
     * @param Generator<NewTKey, NewT> $generator
362
     *
363
     * @return self<NewTKey, NewT>
364
     */
365
    public static function fromGenerator(Generator $generator): CollectionInterface
366
    {
367
        return new self(static fn (): Generator => yield from new NoRewindIterator($generator));
368
    }
369 690
370
    /**
371 690
     * @template UKey
372
     * @template U
373
     *
374
     * @param iterable<UKey, U> $iterable
375
     *
376
     * @return self<UKey, U>
377
     */
378
    public static function fromIterable(iterable $iterable): CollectionInterface
379 2
    {
380
        return new self(static fn (): Generator => yield from new IterableIteratorAggregate($iterable));
381 2
    }
382
383
    /**
384
     * @param resource $resource
385
     *
386
     * @return self<int, string>
387 2
     */
388
    public static function fromResource($resource): CollectionInterface
389 2
    {
390
        return new self(static fn (): Generator => yield from new ResourceIteratorAggregate($resource));
391
    }
392 5
393
    /**
394 5
     * @return self<int, string>
395
     */
396
    public static function fromString(string $string, string $delimiter = ''): CollectionInterface
397
    {
398
        return new self(static fn (): Generator => yield from new StringIteratorAggregate($string, $delimiter));
399
    }
400 707
401
    public function get(mixed $key, mixed $default = null)
402 707
    {
403
        return (new self((new Operation\Get())()($key)($default), [$this]))->current(0, $default);
404
    }
405 6
406
    /**
407 6
     * @return Traversable<TKey, T>
408
     */
409
    public function getIterator(): Traversable
410 4
    {
411
        yield from $this->innerIterator->getIterator();
412 4
    }
413
414
    public function group(): CollectionInterface
415 16
    {
416
        return new self((new Operation\Group())(), [$this]);
417 16
    }
418
419
    public function groupBy(callable $callback): CollectionInterface
420 6
    {
421
        return new self((new Operation\GroupBy())()($callback), [$this]);
422 6
    }
423
424
    public function has(callable ...$callbacks): bool
425 4
    {
426
        return (new Operation\Has())()(...$callbacks)($this)->current();
427 4
    }
428
429
    public function head(mixed $default = null)
430
    {
431
        return (new self((new Operation\Head())(), [$this]))->current(0, $default);
432
    }
433 4
434
    public function ifThenElse(callable $condition, callable $then, ?callable $else = null): CollectionInterface
435 4
    {
436
        $identity =
437
            /**
438 6
             * @param T $value
439
             *
440 6
             * @return T
441
             */
442
            static fn (mixed $value): mixed => $value;
443 4
444
        return new self((new Operation\IfThenElse())()($condition)($then)($else ?? $identity), [$this]);
445 4
    }
446
447
    public function implode(string $glue = ''): string
448 4
    {
449
        return (new self((new Operation\Implode())()($glue), [$this]))->current(0, '');
450 4
    }
451
452
    public function init(): CollectionInterface
453 4
    {
454
        return new self((new Operation\Init())(), [$this]);
455 4
    }
456
457
    public function inits(): CollectionInterface
458 6
    {
459
        return new self((new Operation\Inits())(), [$this]);
460 6
    }
461
462
    public function intersect(mixed ...$values): CollectionInterface
463 10
    {
464
        return new self((new Operation\Intersect())()($values), [$this]);
465 10
    }
466
467
    public function intersectKeys(mixed ...$keys): CollectionInterface
468 14
    {
469
        return new self((new Operation\IntersectKeys())()($keys), [$this]);
470 14
    }
471
472
    public function intersperse(mixed $element, int $every = 1, int $startAt = 0): CollectionInterface
473 14
    {
474
        return new self((new Operation\Intersperse())()($element)($every)($startAt), [$this]);
475 14
    }
476
477
    public function isEmpty(): bool
478
    {
479
        return (new Operation\IsEmpty())()($this)->current();
480
    }
481 1
482
    public function isNotEmpty(): bool
483 1
    {
484
        return (new Operation\IsNotEmpty())()($this)->current();
485
    }
486 6
487
    /**
488 6
     * @return array<mixed>
489
     */
490
    public function jsonSerialize(): array
491 2
    {
492
        return $this->all(false);
493 2
    }
494
495
    public function key(int $index = 0)
496 14
    {
497
        return (new Operation\Key())()($index)($this)->current();
498 14
    }
499
500
    public function keys(): CollectionInterface
501 12
    {
502
        return new self((new Operation\Keys())(), [$this]);
503 12
    }
504
505
    public function last(mixed $default = null)
506 2
    {
507
        return (new self((new Operation\Last())(), [$this]))->current(0, $default);
508 2
    }
509
510
    public function limit(int $count = -1, int $offset = 0): CollectionInterface
511 10
    {
512
        return new self((new Operation\Limit())()($count)($offset), [$this]);
513 10
    }
514
515
    public function lines(): CollectionInterface
516 4
    {
517
        return new self((new Operation\Lines())(), [$this]);
518 4
    }
519
520
    public function map(callable $callback): CollectionInterface
521 6
    {
522
        return new self((new Operation\Map())()($callback), [$this]);
523 6
    }
524
525
    public function mapN(callable ...$callbacks): CollectionInterface
526 2
    {
527
        return new self((new Operation\MapN())()(...$callbacks), [$this]);
528 2
    }
529
530
    public function match(callable $callback, ?callable $matcher = null): bool
531 8
    {
532
        return (new Operation\MatchOne())()($matcher ?? static fn (): bool => true)($callback)($this)->current();
533 8
    }
534
535
    public function matching(Criteria $criteria): CollectionInterface
536 2
    {
537
        return new self((new Operation\Matching())()($criteria), [$this]);
538 2
    }
539
540
    public function max(mixed $default = null)
541 8
    {
542
        return (new self((new Operation\Max())(), [$this]))->current(0, $default);
543 8
    }
544
545
    public function merge(iterable ...$sources): CollectionInterface
546 6
    {
547
        return new self((new Operation\Merge())()(...$sources), [$this]);
548 6
    }
549
550
    public function min(mixed $default = null)
551 4
    {
552
        return (new self((new Operation\Min())(), [$this]))->current(0, $default);
553 4
    }
554
555
    public function normalize(): CollectionInterface
556 8
    {
557
        return new self((new Operation\Normalize())(), [$this]);
558 8
    }
559
560
    public function nth(int $step, int $offset = 0): CollectionInterface
561 6
    {
562
        return new self((new Operation\Nth())()($step)($offset), [$this]);
563 6
    }
564
565
    public function nullsy(): bool
566 2
    {
567
        return (new Operation\Nullsy())()($this)->current();
568 2
    }
569
570
    public function pack(): CollectionInterface
571 4
    {
572
        return new self((new Operation\Pack())(), [$this]);
573 4
    }
574
575
    public function pad(int $size, mixed $value): CollectionInterface
576 2
    {
577
        return new self((new Operation\Pad())()($size)($value), [$this]);
578 2
    }
579 2
580
    public function pair(): CollectionInterface
581
    {
582
        return new self((new Operation\Pair())(), [$this]);
583
    }
584
585 2
    public function partition(callable ...$callbacks): CollectionInterface
586 2
    {
587
        return (new self((new Operation\Partition())()(...$callbacks), [$this]))
588
            ->map(
589 2
                /**
590
                 * @param iterable<TKey, T> $iterable
591 2
                 *
592
                 * @return Collection<TKey, T>
593
                 */
594 2
                static fn (iterable $iterable): Collection => Collection::fromIterable($iterable)
595
            );
596 2
    }
597
598
    public function permutate(): CollectionInterface
599 12
    {
600
        return new self((new Operation\Permutate())(), [$this]);
601 12
    }
602
603
    public function pipe(callable ...$callbacks): CollectionInterface
604 2
    {
605
        return new self((new Operation\Pipe())()(...$callbacks), [$this]);
606 2
    }
607
608
    public function pluck(mixed $pluck, mixed $default = null): CollectionInterface
609 4
    {
610
        return new self((new Operation\Pluck())()($pluck)($default), [$this]);
611 4
    }
612
613
    public function prepend(mixed ...$items): CollectionInterface
614 2
    {
615
        return new self((new Operation\Prepend())()($items), [$this]);
616 2
    }
617
618
    public function product(iterable ...$iterables): CollectionInterface
619
    {
620
        return new self((new Operation\Product())()(...$iterables), [$this]);
621
    }
622 2
623
    public function random(int $size = 1, ?int $seed = null): CollectionInterface
624 2
    {
625
        return new self((new Operation\Random())()($seed ?? random_int(0, 1000))($size), [$this]);
626
    }
627 6
628
    /**
629 6
     * @return self<int, float>
630
     */
631
    public static function range(float $start = 0.0, float $end = INF, float $step = 1.0): CollectionInterface
632 2
    {
633
        return new self((new Operation\Range())()($start)($end)($step));
634 2
    }
635
636
    public function reduce(callable $callback, mixed $initial = null)
637 8
    {
638
        return (new self((new Operation\Reduce())()($callback)($initial), [$this]))->current();
639 8
    }
640
641
    public function reduction(callable $callback, mixed $initial = null): CollectionInterface
642 4
    {
643
        return new self((new Operation\Reduction())()($callback)($initial), [$this]);
644 4
    }
645
646
    public function reject(callable ...$callbacks): CollectionInterface
647 2
    {
648
        return new self((new Operation\Reject())()(...$callbacks), [$this]);
649 2
    }
650
651
    public function reverse(): CollectionInterface
652 46
    {
653
        return new self((new Operation\Reverse())(), [$this]);
654 46
    }
655
656
    public function rsample(float $probability): CollectionInterface
657
    {
658
        return new self((new Operation\RSample())()($probability), [$this]);
659
    }
660
661 46
    public function same(iterable $other, ?callable $comparatorCallback = null): bool
662
    {
663
        $comparatorCallback ??=
664
            /**
665
             * @param T $leftValue
666 32
             * @param TKey $leftKey
667
             *
668 46
             * @return Closure(T, TKey): bool
669
             */
670
            static fn (mixed $leftValue, mixed $leftKey): Closure =>
671 2
                /**
672
                 * @param T $rightValue
673
                 * @param TKey $rightKey
674
                 */
675
                static fn (mixed $rightValue, mixed $rightKey): bool => $leftValue === $rightValue && $leftKey === $rightKey;
676
677
        return (new Operation\Same())()($other)($comparatorCallback)($this)->current();
678 2
    }
679
680
    public function scale(
681 4
        float $lowerBound,
682
        float $upperBound,
683 4
        float $wantedLowerBound = 0.0,
684
        float $wantedUpperBound = 1.0,
685
        float $base = 0.0
686 6
    ): CollectionInterface {
687
        return new self((new Operation\Scale())()($lowerBound)($upperBound)($wantedLowerBound)($wantedUpperBound)($base), [$this]);
688 6
    }
689
690
    public function scanLeft(callable $callback, mixed $initial): CollectionInterface
691 4
    {
692
        return new self((new Operation\ScanLeft())()($callback)($initial), [$this]);
693 4
    }
694
695
    public function scanLeft1(callable $callback): CollectionInterface
696 4
    {
697
        return new self((new Operation\ScanLeft1())()($callback), [$this]);
698 4
    }
699
700
    public function scanRight(callable $callback, mixed $initial): CollectionInterface
701 2
    {
702
        return new self((new Operation\ScanRight())()($callback)($initial), [$this]);
703 2
    }
704
705
    public function scanRight1(callable $callback): CollectionInterface
706 8
    {
707
        return new self((new Operation\ScanRight1())()($callback), [$this]);
708 8
    }
709
710
    public function shuffle(?int $seed = null): CollectionInterface
711 6
    {
712
        return new self((new Operation\Shuffle())()($seed ?? random_int(0, 1000)), [$this]);
713 6
    }
714
715
    public function since(callable ...$callbacks): CollectionInterface
716 12
    {
717
        return new self((new Operation\Since())()(...$callbacks), [$this]);
718 12
    }
719
720
    public function slice(int $offset, int $length = -1): CollectionInterface
721 2
    {
722
        return new self((new Operation\Slice())()($offset)($length), [$this]);
723 2
    }
724 2
725
    public function sort(int $type = OperationInterface\Sortable::BY_VALUES, ?callable $callback = null): CollectionInterface
726
    {
727
        return new self((new Operation\Sort())()($type)($callback), [$this]);
728
    }
729
730 2
    public function span(callable ...$callbacks): CollectionInterface
731 2
    {
732
        return (new self((new Operation\Span())()(...$callbacks), [$this]))
733
            ->map(
734 6
                /**
735
                 * @param iterable<TKey, T> $iterable
736 6
                 *
737
                 * @return Collection<TKey, T>
738
                 */
739 4
                static fn (iterable $iterable): Collection => Collection::fromIterable($iterable)
740
            );
741 4
    }
742
743
    public function split(int $type = OperationInterface\Splitable::BEFORE, callable ...$callbacks): CollectionInterface
744 4
    {
745
        return new self((new Operation\Split())()($type)(...$callbacks), [$this]);
746 4
    }
747
748
    public function squash(): CollectionInterface
749 2
    {
750
        return self::fromIterable($this->pack()->all(false))->unpack();
751 2
    }
752
753
    public function strict(?callable $callback = null): CollectionInterface
754 4
    {
755
        return new self((new Operation\Strict())()($callback), [$this]);
756 4
    }
757
758
    public function tail(): CollectionInterface
759 6
    {
760
        return new self((new Operation\Tail())(), [$this]);
761 6
    }
762
763
    public function tails(): CollectionInterface
764
    {
765
        return new self((new Operation\Tails())(), [$this]);
766
    }
767
768
    public function takeWhile(callable ...$callbacks): CollectionInterface
769
    {
770
        return new self((new Operation\TakeWhile())()(...$callbacks), [$this]);
771 2
    }
772
773 2
    /**
774
     * @template U
775
     *
776 2
     * @param callable(int): U $callback
777
     *
778 2
     * @return self<int, U>
779
     */
780
    public static function times(int $number = 0, ?callable $callback = null): CollectionInterface
781 8
    {
782
        return new self((new Operation\Times())()($number)($callback));
783 8
    }
784
785
    public function transpose(): CollectionInterface
786 2
    {
787
        return new self((new Operation\Transpose())(), [$this]);
788 2
    }
789
790
    public function truthy(): bool
791 2
    {
792
        return (new Operation\Truthy())()($this)->current();
793 2
    }
794
795
    public static function unfold(callable $callback, iterable $parameters = []): CollectionInterface
796 4
    {
797
        return new self((new Operation\Unfold())()($parameters)($callback));
798 4
    }
799
800
    public function unlines(): string
801 2
    {
802
        return (new self((new Operation\Unlines())(), [$this]))->current(0, '');
803 2
    }
804
805
    public function unpack(): CollectionInterface
806 4
    {
807
        return new self((new Operation\Unpack())(), [$this]);
808 4
    }
809
810
    public function unpair(): CollectionInterface
811 2
    {
812
        return new self((new Operation\Unpair())(), [$this]);
813 2
    }
814
815
    public function until(callable ...$callbacks): CollectionInterface
816 2
    {
817
        return new self((new Operation\Until())()(...$callbacks), [$this]);
818 2
    }
819
820
    public function unwindow(): CollectionInterface
821 6
    {
822
        return new self((new Operation\Unwindow())(), [$this]);
823 6
    }
824
825
    public function unwords(): string
826 2
    {
827
        return (new self((new Operation\Unwords())(), [$this]))->current(0, '');
828 2
    }
829
830
    public function unwrap(): CollectionInterface
831 4
    {
832
        return new self((new Operation\Unwrap())(), [$this]);
833 4
    }
834
835
    public function unzip(): CollectionInterface
836
    {
837
        return new self((new Operation\Unzip())(), [$this]);
838
    }
839 4
840
    public function when(callable $predicate, callable $whenTrue, ?callable $whenFalse = null): CollectionInterface
841 4
    {
842
        $whenFalse ??=
843
            /**
844 8
             * @param iterable<TKey, T> $iterable
845
             *
846 8
             * @return iterable<TKey, T>
847
             */
848
            static fn (iterable $iterable): iterable => $iterable;
849 2
850
        return new self((new Operation\When())()($predicate)($whenTrue)($whenFalse), [$this]);
851 2
    }
852
853
    public function window(int $size): CollectionInterface
854 4
    {
855
        return new self((new Operation\Window())()($size), [$this]);
856 4
    }
857
858
    public function words(): CollectionInterface
859 4
    {
860
        return new self((new Operation\Words())(), [$this]);
861 4
    }
862
863
    public function wrap(): CollectionInterface
864
    {
865
        return new self((new Operation\Wrap())(), [$this]);
866
    }
867
868
    public function zip(iterable ...$iterables): CollectionInterface
869
    {
870
        return new self((new Operation\Zip())()(...$iterables), [$this]);
871
    }
872
}
873