sanmai/LazyLINQ

View on GitHub
src/LazyLINQ/LazyCollection.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php
/**
 * Copyright 2018 Alexey Kopytko <alexey@kopytko.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

declare(strict_types=1);

namespace LazyLINQ;

use LazyLINQ\Util\FromSource;

final class LazyCollection implements Interfaces\Collection
{
    use FromSource;

    /**
     * @var Collection|Interfaces\Collection
     */
    private $collection;

    /**
     * @var array
     */
    private $queue;

    /**
     * @param mixed ...$args
     */
    private function defer(string $method, ...$args)
    {
        $this->queue[] = [$method, $args];

        return $this;
    }

    /** @return Collection */
    private function immediate()
    {
        foreach ($this->queue as list($method, $args)) {
            $this->collection->{$method}(...$args);
        }

        // Done with queue, flushing
        $this->queue = [];

        return $this->collection;
    }

    private function __construct(\Traversable $input = null)
    {
        $this->collection = Collection::from($input);

        $this->queue = [];
    }

    public function average(callable $selector = null): float
    {
        return $this->immediate()->average($selector);
    }

    public function select(callable $selector): Interfaces\Collection
    {
        return $this->defer(__FUNCTION__, $selector);
    }

    public function prepend($element): Interfaces\Collection
    {
        return $this->defer(__FUNCTION__, $element);
    }

    public function distinct(callable $comparer = null, bool $strict = false): Interfaces\Collection
    {
        return $this->defer(__FUNCTION__, $comparer, $strict);
    }

    public function elementAt(int $index)
    {
        return $this->immediate()->elementAt($index);
    }

    public function elementAtOrDefault(int $index)
    {
        return $this->immediate()->elementAtOrDefault($index);
    }

    public function takeWhile(callable $predicate): Interfaces\Collection
    {
        return $this->defer(__FUNCTION__, $predicate);
    }

    public function skip(int $count): Interfaces\Collection
    {
        return $this->defer(__FUNCTION__, $count);
    }

    public function sum(callable $selector = null)
    {
        return $this->immediate()->sum($selector);
    }

    public function aggregate($seed, callable $func, callable $resultSelector = null)
    {
        return $this->immediate()->aggregate($seed, $func, $resultSelector);
    }

    public function cast($type): Interfaces\Collection
    {
        return $this->defer(__FUNCTION__, $type);
    }

    public function skipWhile(callable $predicate): Interfaces\Collection
    {
        return $this->defer(__FUNCTION__, $predicate);
    }

    public function jsonSerialize()
    {
        return $this->immediate()->jsonSerialize();
    }

    public function min(callable $selector = null)
    {
        return $this->immediate()->min($selector);
    }

    public function where(callable $predicate): Interfaces\Collection
    {
        return $this->defer(__FUNCTION__, $predicate);
    }

    public function ofType(string $type): Interfaces\Collection
    {
        return $this->defer(__FUNCTION__, $type);
    }

    public function all(callable $predicate = null): bool
    {
        return $this->immediate()->all($predicate);
    }

    public function zip($collection, callable $resultSelector = null): Interfaces\Collection
    {
        return $this->defer(__FUNCTION__, $collection, $resultSelector);
    }

    public function last(callable $predicate = null)
    {
        return $this->immediate()->last($predicate);
    }

    public function max(callable $selector = null)
    {
        return $this->immediate()->max($selector);
    }

    public function ofClass(string $className): Interfaces\Collection
    {
        return $this->defer(__FUNCTION__, $className);
    }

    public function count(callable $predicate = null): int
    {
        return $this->immediate()->count($predicate);
    }

    public function concat($second): Interfaces\Collection
    {
        return $this->defer(__FUNCTION__, $second);
    }

    public function any(callable $predicate = null): bool
    {
        return $this->immediate()->any($predicate);
    }

    public function single(callable $predicate = null)
    {
        return $this->immediate()->single($predicate);
    }

    public function take(int $count): Interfaces\Collection
    {
        return $this->defer(__FUNCTION__, $count);
    }

    public function contains($value, callable $comparer = null): bool
    {
        return $this->immediate()->contains($value, $comparer);
    }

    public function containsExactly($value): bool
    {
        return $this->immediate()->containsExactly($value);
    }

    public function selectMany(callable $selector = null): Interfaces\Collection
    {
        return $this->defer(__FUNCTION__, $selector);
    }

    public function except($collection, callable $comparer = null, bool $strict = false): Interfaces\Collection
    {
        return $this->defer(__FUNCTION__, $collection, $comparer, $strict);
    }

    public function append($element): Interfaces\Collection
    {
        return $this->defer(__FUNCTION__, $element);
    }

    public function first(callable $predicate = null)
    {
        return $this->immediate()->first($predicate);
    }

    public function toArray(): array
    {
        return $this->immediate()->toArray();
    }

    public function map(callable $func): Interfaces\Collection
    {
        return $this->select($func);
    }

    public function unpack(callable $func = null): Interfaces\Collection
    {
        return $this->defer(__FUNCTION__, $func);
    }

    public function reduce(callable $func = null, $initial = null)
    {
        return $this->immediate()->reduce($func, $initial);
    }

    public function filter(callable $func = null): Interfaces\Collection
    {
        return $this->defer(__FUNCTION__, $func);
    }

    public function getIterator(): \Traversable
    {
        return $this->immediate()->getIterator();
    }

    public function __invoke()
    {
        yield from $this->immediate();
    }
}