Completed
Branch 0.4-dev (f926df)
by Evgenij
04:00
created

PushbackIterator::__toString()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 2
eloc 2
nc 2
nop 0
crap 2
1
<?php
2
/**
3
 * Async sockets
4
 *
5
 * @copyright Copyright (c) 2015-2017, Efimov Evgenij <[email protected]>
6
 *
7
 * This source file is subject to the MIT license that is bundled
8
 * with this source code in the file LICENSE.
9
 */
10
11
namespace AsyncSockets\RequestExecutor\Pipeline;
12
13
/**
14
 * Class PushbackIterator
15
 */
16
class PushbackIterator implements \Iterator
17
{
18
    /**
19
     * Nested iterator
20
     *
21
     * @var \Iterator
22
     */
23
    private $nestedIterator;
24
25
    /**
26
     * Unread item from previous iteration
27
     *
28
     * @var string[]
29
     */
30
    private $unreadItems;
31
32
    /**
33
     * Result of previous iteration
34
     *
35
     * @var string
36
     */
37
    private $lastIterationResult;
38
39
    /**
40
     * String length to return from this iterator
41
     *
42
     * @var int
43
     */
44
    private $chunkSize;
45
46
    /**
47
     * Iteration key
48
     *
49
     * @var int
50
     */
51
    private $key;
52
53
    /**
54
     * Length of last result push back
55
     *
56
     * @var int
57
     */
58
    private $backLength;
59
60
    /**
61
     * PushbackIterator constructor.
62
     *
63
     * @param \Iterator $nestedIterator Nested iterator
64
     * @param int       $chunkSize      Max length of string to return
65
     */
66 37
    public function __construct(\Iterator $nestedIterator, $chunkSize)
67
    {
68 37
        $this->nestedIterator = $nestedIterator;
69 37
        $this->chunkSize      = $chunkSize;
70 37
        $this->unreadItems    = [];
71 37
    }
72
73
    /**
74
     * @inheritDoc
75
     */
76 19
    public function current()
77
    {
78 19
        return $this->lastIterationResult;
79
    }
80
81
    /**
82
     * @inheritDoc
83
     */
84 16
    public function next()
85
    {
86 16
        ++$this->key;
87
88 16
        $hasUnreadItem = $this->hasUnreadItem();
89 16
        if (!$hasUnreadItem && !$this->backLength) {
90 9
            $this->nestedIterator->next();
91 9
            if (!$this->nestedIterator->valid()) {
92 9
                $this->lastIterationResult = '';
93 9
                return;
94
            }
95 4
        }
96
97 12
        $this->lastIterationResult = $this->buildChunk();
98 12
    }
99
100
    /**
101
     * @inheritDoc
102
     */
103 5
    public function key()
104
    {
105 5
        return $this->key;
106
    }
107
108
    /**
109
     * @inheritDoc
110
     */
111 41
    public function valid()
112
    {
113 41
        return !empty($this->lastIterationResult) || $this->hasUnreadItem() || $this->nestedIterator->valid();
114
    }
115
116
    /**
117
     * @inheritDoc
118
     */
119 37
    public function rewind()
120
    {
121 37
        $this->key                 = 0;
122 37
        $this->backLength          = 0;
123 37
        $this->unreadItems         = [];
124 37
        $this->nestedIterator->rewind();
125 37
        $this->lastIterationResult = $this->buildChunk();
126 37
    }
127
128
    /**
129
     * Return given length of previously read string back into iterator
130
     *
131
     * @param int $length Length of string to return back
132
     *
133
     * @return void
134
     */
135 7
    public function unread($length)
136
    {
137 7
        if (empty($this->lastIterationResult) || $length <= 0) {
138
            return;
139
        }
140
141 7
        $itemLength       = strlen($this->lastIterationResult);
142 7
        $this->backLength = min($itemLength, $this->backLength + $length);
143 7
    }
144
145
    /**
146
     * Test if iterator has unread item
147
     *
148
     * @return bool
149
     */
150 41
    private function hasUnreadItem()
151
    {
152 41
        return !empty($this->unreadItems);
153
    }
154
155
    /**
156
     * Build chunk to return to user
157
     *
158
     * @return string
159
     */
160 37
    private function buildChunk()
161
    {
162 37
        $result = '';
163 37
        $this->popLastPushedBackItem();
164
165 37
        $result .= $this->hasUnreadItem() ?
166 37
            array_shift($this->unreadItems) :
167 37
            (string) $this->nestedIterator->current();
168
169 37
        while ($this->hasUnreadItem() && strlen($result) < $this->chunkSize) {
170
            $result .= array_shift($this->unreadItems);
171
        }
172
173 37
        while (strlen($result) < $this->chunkSize && $this->nestedIterator->valid()) {
174 15
            $this->nestedIterator->next();
175 15
            $result .= (string) $this->nestedIterator->current();
176 15
        }
177
178 37
        $split  = str_split($result, $this->chunkSize);
179 37
        $result = array_shift($split);
180 37
        if (!empty($split)) {
181 5
            $this->unreadItems = array_merge($split, $this->unreadItems);
0 ignored issues
show
Documentation Bug introduced by
It seems like array_merge($split, $this->unreadItems) of type array is incompatible with the declared type array<integer,string> of property $unreadItems.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
182 5
        }
183
184 37
        return $result;
185
    }
186
187
    /**
188
     * @inheritDoc
189
     */
190 3
    public function __toString()
191
    {
192 3
        return $this->valid() ? $this->current() : '';
193
    }
194
195
    /**
196
     * Return an item caused by unread operation
197
     *
198
     * @return void
199
     */
200 37
    private function popLastPushedBackItem()
201
    {
202 37
        if ($this->backLength) {
203 7
            $item = substr(
204 7
                $this->lastIterationResult,
205 7
                strlen($this->lastIterationResult) - $this->backLength,
206 7
                $this->backLength
207 7
            );
208
209 7
            array_unshift($this->unreadItems, $item);
210
211 7
            $this->backLength = 0;
212 7
        }
213 37
    }
214
}
215