Completed
Push — master ( 8afd90...4bf010 )
by Kirill
03:48
created

Pipeline::runtime()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of Railt package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
declare(strict_types=1);
9
10
namespace Railt\SDL\Compiler;
11
12
/**
13
 * Class Pipeline
14
 */
15
class Pipeline implements \IteratorAggregate, \Countable
16
{
17
    private const PRIORITY_BUILDING = 1;
18
    private const PRIORITY_EXTENSIONS = 2;
19
    private const PRIORITY_TYPE_RESOLVING = 3;
20
    private const PRIORITY_RUNTIME = 4;
21
22
    /**
23
     * Example struct:
24
     *
25
     * <code>
26
     *  [
27
     *      PRIORITY_1 => \SplQueue([1, 2, 3]),
28
     *      PRIORITY_2 => \SplQueue([1, 2, 3]),
29
     *      PRIORITY_3 => \SplQueue([1, 2, 3]),
30
     *  ]
31
     * </code>
32
     *
33
     * @var \SplQueue[]
34
     */
35
    private $queue = [];
36
37
    /**
38
     * @return \Traversable|callable[]
39
     */
40 1
    public function getIterator(): \Traversable
41
    {
42 1
        while ($next = $this->next()) {
43 1
            yield $next;
44
        }
45 1
    }
46
47
    /**
48
     * @return null|callable
49
     */
50 1
    private function next(): ?callable
51
    {
52 1
        foreach ($this->queue as $queue) {
53 1
            if ($queue->count() > 0) {
54 1
                return $queue->shift();
55
            }
56
        }
57
58 1
        return null;
59
    }
60
61
    /**
62
     * @param \Closure $then
63
     */
64
    public function building(\Closure $then): void
65
    {
66
        $this->push(self::PRIORITY_BUILDING, $then);
67
    }
68
69
    /**
70
     * @param \Closure $then
71
     */
72
    public function extending(\Closure $then): void
73
    {
74
        $this->push(self::PRIORITY_EXTENSIONS, $then);
75
    }
76
77
    /**
78
     * @param \Closure $then
79
     */
80 1
    public function resolving(\Closure $then): void
81
    {
82 1
        $this->push(self::PRIORITY_TYPE_RESOLVING, $then);
83 1
    }
84
85
    /**
86
     * @param \Closure $then
87
     */
88 1
    public function runtime(\Closure $then): void
89
    {
90 1
        $this->push(self::PRIORITY_RUNTIME, $then);
91 1
    }
92
93
    /**
94
     * @param int $priority
95
     * @param callable $then
96
     */
97 1
    public function push(int $priority, callable $then): void
98
    {
99 1
        if (! \array_key_exists($priority, $this->queue)) {
100 1
            $this->queue[$priority] = $this->createList();
101
        }
102
103 1
        $this->queue[$priority]->push($then);
104 1
    }
105
106
    /**
107
     * @return \SplDoublyLinkedList
108
     */
109 1
    protected function createList(): \SplDoublyLinkedList
110
    {
111 1
        return new \SplQueue();
112
    }
113
114
    /**
115
     * @return int
116
     */
117
    public function count(): int
118
    {
119
        return (int)\array_reduce($this->queue, function (int $result, \SplQueue $queue): int {
120
            return $result + $queue->count();
121
        }, 0);
122
    }
123
124
    /**
125
     * @return callable
126
     * @throws \UnderflowException
127
     */
128
    public function pop(): callable
129
    {
130
        $result = $this->next();
131
132
        if ($result === null) {
133
            throw new \UnderflowException('Can not fetch data from empty heap');
134
        }
135
136
        return $result;
137
    }
138
139
    /**
140
     * @param \Closure $each
141
     */
142
    public function reduce(\Closure $each): void
143
    {
144
        foreach ($this->getIterator() as $callback) {
145
            $each($callback);
146
        }
147
    }
148
}
149