• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

azjezz / psl / 22520286073

28 Feb 2026 11:57AM UTC coverage: 97.795% (+0.3%) from 97.532%
22520286073

Pull #586

github

azjezz
fix cidr block validation
Pull Request #586: add more tests

16 of 16 new or added lines in 4 files covered. (100.0%)

20 existing lines in 13 files now uncovered.

7494 of 7663 relevant lines covered (97.79%)

43.36 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.0
/src/Psl/Async/Awaitable.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Psl\Async;
6

7
use Closure;
8
use Generator;
9
use Psl\Async\Internal\AwaitableIterator;
10
use Psl\Async\Internal\State;
11
use Psl\Promise\PromiseInterface;
12
use Revolt\EventLoop;
13
use Throwable;
14

15
use function is_array;
16

17
/**
18
 * The following class was derived from code of Amphp.
19
 *
20
 * https://github.com/amphp/amp/blob/ac89b9e2ee04228e064e424056a08590b0cdc7b3/lib/Future.php
21
 *
22
 * Code subject to the MIT license (https://github.com/amphp/amp/blob/ac89b9e2ee04228e064e424056a08590b0cdc7b3/LICENSE).
23
 *
24
 * Copyright (c) 2015-2021 Amphp ( https://amphp.org )
25
 *
26
 * @template T
27
 *
28
 * @implements PromiseInterface<T>
29
 *
30
 * @mago-expect lint:no-else-clause
31
 */
32
final readonly class Awaitable implements PromiseInterface
33
{
34
    private State $state;
35

36
    /**
37
     * @param State<T> $state
38
     *
39
     * @internal Use {@see Deferred} to create and resolve an awaitable.
40
     */
41
    public function __construct(State $state)
42
    {
43
        $this->state = $state;
134✔
44
    }
45

46
    /**
47
     * Iterate over the given `Awaitable`s in completion order.
48
     *
49
     * @template Tk
50
     * @template Tv
51
     *
52
     * @param iterable<Tk, Awaitable<Tv>> $awaitables
53
     *
54
     * @return Generator<Tk, Awaitable<Tv>, null, void>
55
     */
56
    public static function iterate(iterable $awaitables): Generator
57
    {
58
        $iterator = new AwaitableIterator();
63✔
59

60
        if (is_array($awaitables)) {
63✔
61
            foreach ($awaitables as $key => $awaitable) {
62✔
62
                $iterator->enqueue($awaitable->state, $key, $awaitable);
60✔
63
            }
64

65
            $iterator->complete();
62✔
66
        } else {
67
            EventLoop::defer(static function () use ($awaitables, $iterator): void {
1✔
68
                // @codeCoverageIgnoreStart
69
                try {
70
                    foreach ($awaitables as $key => $awaitable) {
71
                        $iterator->enqueue($awaitable->state, $key, $awaitable);
72
                    }
73

74
                    $iterator->complete();
75
                } catch (Throwable $throwable) {
76
                    $iterator->error($throwable);
77
                }
78
                // @codeCoverageIgnoreEnd
79
            });
1✔
80
        }
81

82
        do {
83
            $item = $iterator->consume();
63✔
84
            if (!$item) {
63✔
85
                break;
49✔
86
            }
87

88
            yield $item[0] => $item[1];
61✔
89
        } while (true);
53✔
90
    }
91

92
    /**
93
     * @template Tv
94
     *
95
     * @param Tv $result
96
     *
97
     * @return Awaitable<Tv>
98
     */
99
    public static function complete(mixed $result): self
100
    {
101
        $state = new State();
63✔
102
        $state->complete($result);
63✔
103

104
        return new self($state);
63✔
105
    }
106

107
    /**
108
     * @return Awaitable<void>
109
     */
110
    public static function error(Throwable $throwable): self
111
    {
112
        /** @var State<void> $state */
113
        $state = new State();
4✔
114
        $state->error($throwable);
4✔
115

116
        return new self($state);
4✔
117
    }
118

119
    /**
120
     * @return bool True if the operation has completed.
121
     *
122
     * @psalm-mutation-free
123
     */
124
    public function isComplete(): bool
125
    {
126
        return $this->state->isComplete();
25✔
127
    }
128

129
    /**
130
     * {@inheritDoc}
131
     *
132
     * @template Ts
133
     *
134
     * @param Closure(T): Ts $success
135
     * @param Closure(Throwable): Ts $failure
136
     *
137
     * @return Awaitable<Ts>
138
     */
139
    #[\Override]
140
    public function then(Closure $success, Closure $failure): Awaitable
141
    {
142
        $state = new State();
2✔
143

144
        $this->state->subscribe(
2✔
145
            /**
146
             * @param null|Throwable $error
147
             * @param null|T $value
148
             */
149
            static function (null|Throwable $error, mixed $value) use ($state, $success, $failure): void {
2✔
150
                if ($error) {
2✔
151
                    try {
152
                        $state->complete($failure($error));
2✔
153
                    } catch (Throwable $throwable) {
1✔
154
                        $state->error($throwable);
1✔
155
                    }
156

157
                    return;
2✔
158
                }
159

160
                try {
161
                    /**
162
                     * @var T $value
163
                     */
164
                    $state->complete($success($value));
2✔
165
                } catch (Throwable $throwable) {
2✔
166
                    $state->error($throwable);
2✔
167
                }
168
            },
2✔
169
        );
2✔
170

171
        return new self($state);
2✔
172
    }
173

174
    /**
175
     * {@inheritDoc}
176
     *
177
     * @template Ts
178
     *
179
     * @param Closure(T): Ts $success
180
     *
181
     * @return Awaitable<Ts>
182
     */
183
    #[\Override]
184
    public function map(Closure $success): Awaitable
185
    {
186
        return $this->then($success, static fn(Throwable $throwable): never => throw $throwable);
1✔
187
    }
188

189
    /**
190
     * {@inheritDoc}
191
     *
192
     * @template Ts
193
     *
194
     * @param Closure(Throwable): Ts $failure
195
     *
196
     * @return Awaitable<T|Ts>
197
     */
198
    #[\Override]
199
    public function catch(Closure $failure): Awaitable
200
    {
201
        return $this->then(
1✔
202
            /**
203
             * @param T $value
204
             *
205
             * @return T
206
             */
207
            static fn(mixed $value): mixed => $value,
1✔
208
            $failure,
1✔
209
        );
1✔
210
    }
211

212
    /**
213
     * {@inheritDoc}
214
     *
215
     * @param Closure(): void $always
216
     *
217
     * @return Awaitable<T>
218
     */
219
    #[\Override]
220
    public function always(Closure $always): Awaitable
221
    {
222
        $state = new State();
1✔
223

224
        $this->state->subscribe(static function (null|Throwable $error, mixed $value) use ($state, $always): void {
1✔
225
            try {
226
                $always();
1✔
227

228
                if ($error) {
1✔
UNCOV
229
                    $state->error($error);
×
230
                } else {
231
                    /**
232
                     * @var T $value
233
                     */
234
                    $state->complete($value);
1✔
235
                }
UNCOV
236
            } catch (Throwable $throwable) {
×
237
                $state->error($throwable);
×
238
            }
239
        });
1✔
240

241
        return new self($state);
1✔
242
    }
243

244
    /**
245
     * Awaits the operation to complete.
246
     *
247
     * Throws a `Throwable` if the operation fails.
248
     *
249
     * @return T
250
     */
251
    public function await(): mixed
252
    {
253
        $suspension = EventLoop::getSuspension();
131✔
254

255
        $this->state->subscribe(
131✔
256
            /**
257
             * @param null|Throwable $error
258
             * @param null|T $value
259
             */
260
            static function (null|Throwable $error, mixed $value) use ($suspension): void {
131✔
261
                if ($error) {
131✔
262
                    $suspension->throw($error);
34✔
263
                } else {
264
                    $suspension->resume($value);
112✔
265
                }
266
            },
131✔
267
        );
131✔
268

269
        /** @var T */
270
        return $suspension->suspend();
131✔
271
    }
272

273
    /**
274
     * Do not forward unhandled errors to the event loop handler.
275
     */
276
    public function ignore(): self
277
    {
278
        $this->state->ignore();
8✔
279

280
        return $this;
8✔
281
    }
282
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc