Browse code

added appinfo/info.xml appinfo/signature.json CHANGELOG.txt lib/AppInfo/Application.php css/style.css providers/Plivo

DoubleBastionAdmin authored on 05/11/2025 13:35:09
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,281 @@
1
+<?php
2
+
3
+declare(strict_types=1);
4
+
5
+namespace GuzzleHttp\Promise;
6
+
7
+/**
8
+ * Promises/A+ implementation that avoids recursion when possible.
9
+ *
10
+ * @see https://promisesaplus.com/
11
+ *
12
+ * @final
13
+ */
14
+class Promise implements PromiseInterface
15
+{
16
+    private $state = self::PENDING;
17
+    private $result;
18
+    private $cancelFn;
19
+    private $waitFn;
20
+    private $waitList;
21
+    private $handlers = [];
22
+
23
+    /**
24
+     * @param callable $waitFn   Fn that when invoked resolves the promise.
25
+     * @param callable $cancelFn Fn that when invoked cancels the promise.
26
+     */
27
+    public function __construct(
28
+        ?callable $waitFn = null,
29
+        ?callable $cancelFn = null
30
+    ) {
31
+        $this->waitFn = $waitFn;
32
+        $this->cancelFn = $cancelFn;
33
+    }
34
+
35
+    public function then(
36
+        ?callable $onFulfilled = null,
37
+        ?callable $onRejected = null
38
+    ): PromiseInterface {
39
+        if ($this->state === self::PENDING) {
40
+            $p = new Promise(null, [$this, 'cancel']);
41
+            $this->handlers[] = [$p, $onFulfilled, $onRejected];
42
+            $p->waitList = $this->waitList;
43
+            $p->waitList[] = $this;
44
+
45
+            return $p;
46
+        }
47
+
48
+        // Return a fulfilled promise and immediately invoke any callbacks.
49
+        if ($this->state === self::FULFILLED) {
50
+            $promise = Create::promiseFor($this->result);
51
+
52
+            return $onFulfilled ? $promise->then($onFulfilled) : $promise;
53
+        }
54
+
55
+        // It's either cancelled or rejected, so return a rejected promise
56
+        // and immediately invoke any callbacks.
57
+        $rejection = Create::rejectionFor($this->result);
58
+
59
+        return $onRejected ? $rejection->then(null, $onRejected) : $rejection;
60
+    }
61
+
62
+    public function otherwise(callable $onRejected): PromiseInterface
63
+    {
64
+        return $this->then(null, $onRejected);
65
+    }
66
+
67
+    public function wait(bool $unwrap = true)
68
+    {
69
+        $this->waitIfPending();
70
+
71
+        if ($this->result instanceof PromiseInterface) {
72
+            return $this->result->wait($unwrap);
73
+        }
74
+        if ($unwrap) {
75
+            if ($this->state === self::FULFILLED) {
76
+                return $this->result;
77
+            }
78
+            // It's rejected so "unwrap" and throw an exception.
79
+            throw Create::exceptionFor($this->result);
80
+        }
81
+    }
82
+
83
+    public function getState(): string
84
+    {
85
+        return $this->state;
86
+    }
87
+
88
+    public function cancel(): void
89
+    {
90
+        if ($this->state !== self::PENDING) {
91
+            return;
92
+        }
93
+
94
+        $this->waitFn = $this->waitList = null;
95
+
96
+        if ($this->cancelFn) {
97
+            $fn = $this->cancelFn;
98
+            $this->cancelFn = null;
99
+            try {
100
+                $fn();
101
+            } catch (\Throwable $e) {
102
+                $this->reject($e);
103
+            }
104
+        }
105
+
106
+        // Reject the promise only if it wasn't rejected in a then callback.
107
+        /** @psalm-suppress RedundantCondition */
108
+        if ($this->state === self::PENDING) {
109
+            $this->reject(new CancellationException('Promise has been cancelled'));
110
+        }
111
+    }
112
+
113
+    public function resolve($value): void
114
+    {
115
+        $this->settle(self::FULFILLED, $value);
116
+    }
117
+
118
+    public function reject($reason): void
119
+    {
120
+        $this->settle(self::REJECTED, $reason);
121
+    }
122
+
123
+    private function settle(string $state, $value): void
124
+    {
125
+        if ($this->state !== self::PENDING) {
126
+            // Ignore calls with the same resolution.
127
+            if ($state === $this->state && $value === $this->result) {
128
+                return;
129
+            }
130
+            throw $this->state === $state
131
+                ? new \LogicException("The promise is already {$state}.")
132
+                : new \LogicException("Cannot change a {$this->state} promise to {$state}");
133
+        }
134
+
135
+        if ($value === $this) {
136
+            throw new \LogicException('Cannot fulfill or reject a promise with itself');
137
+        }
138
+
139
+        // Clear out the state of the promise but stash the handlers.
140
+        $this->state = $state;
141
+        $this->result = $value;
142
+        $handlers = $this->handlers;
143
+        $this->handlers = null;
144
+        $this->waitList = $this->waitFn = null;
145
+        $this->cancelFn = null;
146
+
147
+        if (!$handlers) {
148
+            return;
149
+        }
150
+
151
+        // If the value was not a settled promise or a thenable, then resolve
152
+        // it in the task queue using the correct ID.
153
+        if (!is_object($value) || !method_exists($value, 'then')) {
154
+            $id = $state === self::FULFILLED ? 1 : 2;
155
+            // It's a success, so resolve the handlers in the queue.
156
+            Utils::queue()->add(static function () use ($id, $value, $handlers): void {
157
+                foreach ($handlers as $handler) {
158
+                    self::callHandler($id, $value, $handler);
159
+                }
160
+            });
161
+        } elseif ($value instanceof Promise && Is::pending($value)) {
162
+            // We can just merge our handlers onto the next promise.
163
+            $value->handlers = array_merge($value->handlers, $handlers);
164
+        } else {
165
+            // Resolve the handlers when the forwarded promise is resolved.
166
+            $value->then(
167
+                static function ($value) use ($handlers): void {
168
+                    foreach ($handlers as $handler) {
169
+                        self::callHandler(1, $value, $handler);
170
+                    }
171
+                },
172
+                static function ($reason) use ($handlers): void {
173
+                    foreach ($handlers as $handler) {
174
+                        self::callHandler(2, $reason, $handler);
175
+                    }
176
+                }
177
+            );
178
+        }
179
+    }
180
+
181
+    /**
182
+     * Call a stack of handlers using a specific callback index and value.
183
+     *
184
+     * @param int   $index   1 (resolve) or 2 (reject).
185
+     * @param mixed $value   Value to pass to the callback.
186
+     * @param array $handler Array of handler data (promise and callbacks).
187
+     */
188
+    private static function callHandler(int $index, $value, array $handler): void
189
+    {
190
+        /** @var PromiseInterface $promise */
191
+        $promise = $handler[0];
192
+
193
+        // The promise may have been cancelled or resolved before placing
194
+        // this thunk in the queue.
195
+        if (Is::settled($promise)) {
196
+            return;
197
+        }
198
+
199
+        try {
200
+            if (isset($handler[$index])) {
201
+                /*
202
+                 * If $f throws an exception, then $handler will be in the exception
203
+                 * stack trace. Since $handler contains a reference to the callable
204
+                 * itself we get a circular reference. We clear the $handler
205
+                 * here to avoid that memory leak.
206
+                 */
207
+                $f = $handler[$index];
208
+                unset($handler);
209
+                $promise->resolve($f($value));
210
+            } elseif ($index === 1) {
211
+                // Forward resolution values as-is.
212
+                $promise->resolve($value);
213
+            } else {
214
+                // Forward rejections down the chain.
215
+                $promise->reject($value);
216
+            }
217
+        } catch (\Throwable $reason) {
218
+            $promise->reject($reason);
219
+        }
220
+    }
221
+
222
+    private function waitIfPending(): void
223
+    {
224
+        if ($this->state !== self::PENDING) {
225
+            return;
226
+        } elseif ($this->waitFn) {
227
+            $this->invokeWaitFn();
228
+        } elseif ($this->waitList) {
229
+            $this->invokeWaitList();
230
+        } else {
231
+            // If there's no wait function, then reject the promise.
232
+            $this->reject('Cannot wait on a promise that has '
233
+                .'no internal wait function. You must provide a wait '
234
+                .'function when constructing the promise to be able to '
235
+                .'wait on a promise.');
236
+        }
237
+
238
+        Utils::queue()->run();
239
+
240
+        /** @psalm-suppress RedundantCondition */
241
+        if ($this->state === self::PENDING) {
242
+            $this->reject('Invoking the wait callback did not resolve the promise');
243
+        }
244
+    }
245
+
246
+    private function invokeWaitFn(): void
247
+    {
248
+        try {
249
+            $wfn = $this->waitFn;
250
+            $this->waitFn = null;
251
+            $wfn(true);
252
+        } catch (\Throwable $reason) {
253
+            if ($this->state === self::PENDING) {
254
+                // The promise has not been resolved yet, so reject the promise
255
+                // with the exception.
256
+                $this->reject($reason);
257
+            } else {
258
+                // The promise was already resolved, so there's a problem in
259
+                // the application.
260
+                throw $reason;
261
+            }
262
+        }
263
+    }
264
+
265
+    private function invokeWaitList(): void
266
+    {
267
+        $waitList = $this->waitList;
268
+        $this->waitList = null;
269
+
270
+        foreach ($waitList as $result) {
271
+            do {
272
+                $result->waitIfPending();
273
+                $result = $result->result;
274
+            } while ($result instanceof Promise);
275
+
276
+            if ($result instanceof PromiseInterface) {
277
+                $result->wait(false);
278
+            }
279
+        }
280
+    }
281
+}
Browse code

removed appinfo/info.xml appinfo/signature.json CHANGELOG.txt lib/AppInfo/Application.php css/style.css providers/Plivo

DoubleBastionAdmin authored on 05/11/2025 13:12:22
Showing 1 changed files
1 1
deleted file mode 100644
... ...
@@ -1,278 +0,0 @@
1
-<?php
2
-
3
-namespace GuzzleHttp\Promise;
4
-
5
-/**
6
- * Promises/A+ implementation that avoids recursion when possible.
7
- *
8
- * @link https://promisesaplus.com/
9
- */
10
-class Promise implements PromiseInterface
11
-{
12
-    private $state = self::PENDING;
13
-    private $result;
14
-    private $cancelFn;
15
-    private $waitFn;
16
-    private $waitList;
17
-    private $handlers = [];
18
-
19
-    /**
20
-     * @param callable $waitFn   Fn that when invoked resolves the promise.
21
-     * @param callable $cancelFn Fn that when invoked cancels the promise.
22
-     */
23
-    public function __construct(
24
-        callable $waitFn = null,
25
-        callable $cancelFn = null
26
-    ) {
27
-        $this->waitFn = $waitFn;
28
-        $this->cancelFn = $cancelFn;
29
-    }
30
-
31
-    public function then(
32
-        callable $onFulfilled = null,
33
-        callable $onRejected = null
34
-    ) {
35
-        if ($this->state === self::PENDING) {
36
-            $p = new Promise(null, [$this, 'cancel']);
37
-            $this->handlers[] = [$p, $onFulfilled, $onRejected];
38
-            $p->waitList = $this->waitList;
39
-            $p->waitList[] = $this;
40
-            return $p;
41
-        }
42
-
43
-        // Return a fulfilled promise and immediately invoke any callbacks.
44
-        if ($this->state === self::FULFILLED) {
45
-            $promise = Create::promiseFor($this->result);
46
-            return $onFulfilled ? $promise->then($onFulfilled) : $promise;
47
-        }
48
-
49
-        // It's either cancelled or rejected, so return a rejected promise
50
-        // and immediately invoke any callbacks.
51
-        $rejection = Create::rejectionFor($this->result);
52
-        return $onRejected ? $rejection->then(null, $onRejected) : $rejection;
53
-    }
54
-
55
-    public function otherwise(callable $onRejected)
56
-    {
57
-        return $this->then(null, $onRejected);
58
-    }
59
-
60
-    public function wait($unwrap = true)
61
-    {
62
-        $this->waitIfPending();
63
-
64
-        if ($this->result instanceof PromiseInterface) {
65
-            return $this->result->wait($unwrap);
66
-        }
67
-        if ($unwrap) {
68
-            if ($this->state === self::FULFILLED) {
69
-                return $this->result;
70
-            }
71
-            // It's rejected so "unwrap" and throw an exception.
72
-            throw Create::exceptionFor($this->result);
73
-        }
74
-    }
75
-
76
-    public function getState()
77
-    {
78
-        return $this->state;
79
-    }
80
-
81
-    public function cancel()
82
-    {
83
-        if ($this->state !== self::PENDING) {
84
-            return;
85
-        }
86
-
87
-        $this->waitFn = $this->waitList = null;
88
-
89
-        if ($this->cancelFn) {
90
-            $fn = $this->cancelFn;
91
-            $this->cancelFn = null;
92
-            try {
93
-                $fn();
94
-            } catch (\Throwable $e) {
95
-                $this->reject($e);
96
-            } catch (\Exception $e) {
97
-                $this->reject($e);
98
-            }
99
-        }
100
-
101
-        // Reject the promise only if it wasn't rejected in a then callback.
102
-        /** @psalm-suppress RedundantCondition */
103
-        if ($this->state === self::PENDING) {
104
-            $this->reject(new CancellationException('Promise has been cancelled'));
105
-        }
106
-    }
107
-
108
-    public function resolve($value)
109
-    {
110
-        $this->settle(self::FULFILLED, $value);
111
-    }
112
-
113
-    public function reject($reason)
114
-    {
115
-        $this->settle(self::REJECTED, $reason);
116
-    }
117
-
118
-    private function settle($state, $value)
119
-    {
120
-        if ($this->state !== self::PENDING) {
121
-            // Ignore calls with the same resolution.
122
-            if ($state === $this->state && $value === $this->result) {
123
-                return;
124
-            }
125
-            throw $this->state === $state
126
-                ? new \LogicException("The promise is already {$state}.")
127
-                : new \LogicException("Cannot change a {$this->state} promise to {$state}");
128
-        }
129
-
130
-        if ($value === $this) {
131
-            throw new \LogicException('Cannot fulfill or reject a promise with itself');
132
-        }
133
-
134
-        // Clear out the state of the promise but stash the handlers.
135
-        $this->state = $state;
136
-        $this->result = $value;
137
-        $handlers = $this->handlers;
138
-        $this->handlers = null;
139
-        $this->waitList = $this->waitFn = null;
140
-        $this->cancelFn = null;
141
-
142
-        if (!$handlers) {
143
-            return;
144
-        }
145
-
146
-        // If the value was not a settled promise or a thenable, then resolve
147
-        // it in the task queue using the correct ID.
148
-        if (!is_object($value) || !method_exists($value, 'then')) {
149
-            $id = $state === self::FULFILLED ? 1 : 2;
150
-            // It's a success, so resolve the handlers in the queue.
151
-            Utils::queue()->add(static function () use ($id, $value, $handlers) {
152
-                foreach ($handlers as $handler) {
153
-                    self::callHandler($id, $value, $handler);
154
-                }
155
-            });
156
-        } elseif ($value instanceof Promise && Is::pending($value)) {
157
-            // We can just merge our handlers onto the next promise.
158
-            $value->handlers = array_merge($value->handlers, $handlers);
159
-        } else {
160
-            // Resolve the handlers when the forwarded promise is resolved.
161
-            $value->then(
162
-                static function ($value) use ($handlers) {
163
-                    foreach ($handlers as $handler) {
164
-                        self::callHandler(1, $value, $handler);
165
-                    }
166
-                },
167
-                static function ($reason) use ($handlers) {
168
-                    foreach ($handlers as $handler) {
169
-                        self::callHandler(2, $reason, $handler);
170
-                    }
171
-                }
172
-            );
173
-        }
174
-    }
175
-
176
-    /**
177
-     * Call a stack of handlers using a specific callback index and value.
178
-     *
179
-     * @param int   $index   1 (resolve) or 2 (reject).
180
-     * @param mixed $value   Value to pass to the callback.
181
-     * @param array $handler Array of handler data (promise and callbacks).
182
-     */
183
-    private static function callHandler($index, $value, array $handler)
184
-    {
185
-        /** @var PromiseInterface $promise */
186
-        $promise = $handler[0];
187
-
188
-        // The promise may have been cancelled or resolved before placing
189
-        // this thunk in the queue.
190
-        if (Is::settled($promise)) {
191
-            return;
192
-        }
193
-
194
-        try {
195
-            if (isset($handler[$index])) {
196
-                /*
197
-                 * If $f throws an exception, then $handler will be in the exception
198
-                 * stack trace. Since $handler contains a reference to the callable
199
-                 * itself we get a circular reference. We clear the $handler
200
-                 * here to avoid that memory leak.
201
-                 */
202
-                $f = $handler[$index];
203
-                unset($handler);
204
-                $promise->resolve($f($value));
205
-            } elseif ($index === 1) {
206
-                // Forward resolution values as-is.
207
-                $promise->resolve($value);
208
-            } else {
209
-                // Forward rejections down the chain.
210
-                $promise->reject($value);
211
-            }
212
-        } catch (\Throwable $reason) {
213
-            $promise->reject($reason);
214
-        } catch (\Exception $reason) {
215
-            $promise->reject($reason);
216
-        }
217
-    }
218
-
219
-    private function waitIfPending()
220
-    {
221
-        if ($this->state !== self::PENDING) {
222
-            return;
223
-        } elseif ($this->waitFn) {
224
-            $this->invokeWaitFn();
225
-        } elseif ($this->waitList) {
226
-            $this->invokeWaitList();
227
-        } else {
228
-            // If there's no wait function, then reject the promise.
229
-            $this->reject('Cannot wait on a promise that has '
230
-                . 'no internal wait function. You must provide a wait '
231
-                . 'function when constructing the promise to be able to '
232
-                . 'wait on a promise.');
233
-        }
234
-
235
-        Utils::queue()->run();
236
-
237
-        /** @psalm-suppress RedundantCondition */
238
-        if ($this->state === self::PENDING) {
239
-            $this->reject('Invoking the wait callback did not resolve the promise');
240
-        }
241
-    }
242
-
243
-    private function invokeWaitFn()
244
-    {
245
-        try {
246
-            $wfn = $this->waitFn;
247
-            $this->waitFn = null;
248
-            $wfn(true);
249
-        } catch (\Exception $reason) {
250
-            if ($this->state === self::PENDING) {
251
-                // The promise has not been resolved yet, so reject the promise
252
-                // with the exception.
253
-                $this->reject($reason);
254
-            } else {
255
-                // The promise was already resolved, so there's a problem in
256
-                // the application.
257
-                throw $reason;
258
-            }
259
-        }
260
-    }
261
-
262
-    private function invokeWaitList()
263
-    {
264
-        $waitList = $this->waitList;
265
-        $this->waitList = null;
266
-
267
-        foreach ($waitList as $result) {
268
-            do {
269
-                $result->waitIfPending();
270
-                $result = $result->result;
271
-            } while ($result instanceof Promise);
272
-
273
-            if ($result instanceof PromiseInterface) {
274
-                $result->wait(false);
275
-            }
276
-        }
277
-    }
278
-}
Browse code

Added README.md appinfo/info.xml appinfo/signature.json lib/Controller/AuthorApiController.php and the providers directory

DoubleBastionAdmin authored on 20/08/2022 16:33:00
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,278 @@
1
+<?php
2
+
3
+namespace GuzzleHttp\Promise;
4
+
5
+/**
6
+ * Promises/A+ implementation that avoids recursion when possible.
7
+ *
8
+ * @link https://promisesaplus.com/
9
+ */
10
+class Promise implements PromiseInterface
11
+{
12
+    private $state = self::PENDING;
13
+    private $result;
14
+    private $cancelFn;
15
+    private $waitFn;
16
+    private $waitList;
17
+    private $handlers = [];
18
+
19
+    /**
20
+     * @param callable $waitFn   Fn that when invoked resolves the promise.
21
+     * @param callable $cancelFn Fn that when invoked cancels the promise.
22
+     */
23
+    public function __construct(
24
+        callable $waitFn = null,
25
+        callable $cancelFn = null
26
+    ) {
27
+        $this->waitFn = $waitFn;
28
+        $this->cancelFn = $cancelFn;
29
+    }
30
+
31
+    public function then(
32
+        callable $onFulfilled = null,
33
+        callable $onRejected = null
34
+    ) {
35
+        if ($this->state === self::PENDING) {
36
+            $p = new Promise(null, [$this, 'cancel']);
37
+            $this->handlers[] = [$p, $onFulfilled, $onRejected];
38
+            $p->waitList = $this->waitList;
39
+            $p->waitList[] = $this;
40
+            return $p;
41
+        }
42
+
43
+        // Return a fulfilled promise and immediately invoke any callbacks.
44
+        if ($this->state === self::FULFILLED) {
45
+            $promise = Create::promiseFor($this->result);
46
+            return $onFulfilled ? $promise->then($onFulfilled) : $promise;
47
+        }
48
+
49
+        // It's either cancelled or rejected, so return a rejected promise
50
+        // and immediately invoke any callbacks.
51
+        $rejection = Create::rejectionFor($this->result);
52
+        return $onRejected ? $rejection->then(null, $onRejected) : $rejection;
53
+    }
54
+
55
+    public function otherwise(callable $onRejected)
56
+    {
57
+        return $this->then(null, $onRejected);
58
+    }
59
+
60
+    public function wait($unwrap = true)
61
+    {
62
+        $this->waitIfPending();
63
+
64
+        if ($this->result instanceof PromiseInterface) {
65
+            return $this->result->wait($unwrap);
66
+        }
67
+        if ($unwrap) {
68
+            if ($this->state === self::FULFILLED) {
69
+                return $this->result;
70
+            }
71
+            // It's rejected so "unwrap" and throw an exception.
72
+            throw Create::exceptionFor($this->result);
73
+        }
74
+    }
75
+
76
+    public function getState()
77
+    {
78
+        return $this->state;
79
+    }
80
+
81
+    public function cancel()
82
+    {
83
+        if ($this->state !== self::PENDING) {
84
+            return;
85
+        }
86
+
87
+        $this->waitFn = $this->waitList = null;
88
+
89
+        if ($this->cancelFn) {
90
+            $fn = $this->cancelFn;
91
+            $this->cancelFn = null;
92
+            try {
93
+                $fn();
94
+            } catch (\Throwable $e) {
95
+                $this->reject($e);
96
+            } catch (\Exception $e) {
97
+                $this->reject($e);
98
+            }
99
+        }
100
+
101
+        // Reject the promise only if it wasn't rejected in a then callback.
102
+        /** @psalm-suppress RedundantCondition */
103
+        if ($this->state === self::PENDING) {
104
+            $this->reject(new CancellationException('Promise has been cancelled'));
105
+        }
106
+    }
107
+
108
+    public function resolve($value)
109
+    {
110
+        $this->settle(self::FULFILLED, $value);
111
+    }
112
+
113
+    public function reject($reason)
114
+    {
115
+        $this->settle(self::REJECTED, $reason);
116
+    }
117
+
118
+    private function settle($state, $value)
119
+    {
120
+        if ($this->state !== self::PENDING) {
121
+            // Ignore calls with the same resolution.
122
+            if ($state === $this->state && $value === $this->result) {
123
+                return;
124
+            }
125
+            throw $this->state === $state
126
+                ? new \LogicException("The promise is already {$state}.")
127
+                : new \LogicException("Cannot change a {$this->state} promise to {$state}");
128
+        }
129
+
130
+        if ($value === $this) {
131
+            throw new \LogicException('Cannot fulfill or reject a promise with itself');
132
+        }
133
+
134
+        // Clear out the state of the promise but stash the handlers.
135
+        $this->state = $state;
136
+        $this->result = $value;
137
+        $handlers = $this->handlers;
138
+        $this->handlers = null;
139
+        $this->waitList = $this->waitFn = null;
140
+        $this->cancelFn = null;
141
+
142
+        if (!$handlers) {
143
+            return;
144
+        }
145
+
146
+        // If the value was not a settled promise or a thenable, then resolve
147
+        // it in the task queue using the correct ID.
148
+        if (!is_object($value) || !method_exists($value, 'then')) {
149
+            $id = $state === self::FULFILLED ? 1 : 2;
150
+            // It's a success, so resolve the handlers in the queue.
151
+            Utils::queue()->add(static function () use ($id, $value, $handlers) {
152
+                foreach ($handlers as $handler) {
153
+                    self::callHandler($id, $value, $handler);
154
+                }
155
+            });
156
+        } elseif ($value instanceof Promise && Is::pending($value)) {
157
+            // We can just merge our handlers onto the next promise.
158
+            $value->handlers = array_merge($value->handlers, $handlers);
159
+        } else {
160
+            // Resolve the handlers when the forwarded promise is resolved.
161
+            $value->then(
162
+                static function ($value) use ($handlers) {
163
+                    foreach ($handlers as $handler) {
164
+                        self::callHandler(1, $value, $handler);
165
+                    }
166
+                },
167
+                static function ($reason) use ($handlers) {
168
+                    foreach ($handlers as $handler) {
169
+                        self::callHandler(2, $reason, $handler);
170
+                    }
171
+                }
172
+            );
173
+        }
174
+    }
175
+
176
+    /**
177
+     * Call a stack of handlers using a specific callback index and value.
178
+     *
179
+     * @param int   $index   1 (resolve) or 2 (reject).
180
+     * @param mixed $value   Value to pass to the callback.
181
+     * @param array $handler Array of handler data (promise and callbacks).
182
+     */
183
+    private static function callHandler($index, $value, array $handler)
184
+    {
185
+        /** @var PromiseInterface $promise */
186
+        $promise = $handler[0];
187
+
188
+        // The promise may have been cancelled or resolved before placing
189
+        // this thunk in the queue.
190
+        if (Is::settled($promise)) {
191
+            return;
192
+        }
193
+
194
+        try {
195
+            if (isset($handler[$index])) {
196
+                /*
197
+                 * If $f throws an exception, then $handler will be in the exception
198
+                 * stack trace. Since $handler contains a reference to the callable
199
+                 * itself we get a circular reference. We clear the $handler
200
+                 * here to avoid that memory leak.
201
+                 */
202
+                $f = $handler[$index];
203
+                unset($handler);
204
+                $promise->resolve($f($value));
205
+            } elseif ($index === 1) {
206
+                // Forward resolution values as-is.
207
+                $promise->resolve($value);
208
+            } else {
209
+                // Forward rejections down the chain.
210
+                $promise->reject($value);
211
+            }
212
+        } catch (\Throwable $reason) {
213
+            $promise->reject($reason);
214
+        } catch (\Exception $reason) {
215
+            $promise->reject($reason);
216
+        }
217
+    }
218
+
219
+    private function waitIfPending()
220
+    {
221
+        if ($this->state !== self::PENDING) {
222
+            return;
223
+        } elseif ($this->waitFn) {
224
+            $this->invokeWaitFn();
225
+        } elseif ($this->waitList) {
226
+            $this->invokeWaitList();
227
+        } else {
228
+            // If there's no wait function, then reject the promise.
229
+            $this->reject('Cannot wait on a promise that has '
230
+                . 'no internal wait function. You must provide a wait '
231
+                . 'function when constructing the promise to be able to '
232
+                . 'wait on a promise.');
233
+        }
234
+
235
+        Utils::queue()->run();
236
+
237
+        /** @psalm-suppress RedundantCondition */
238
+        if ($this->state === self::PENDING) {
239
+            $this->reject('Invoking the wait callback did not resolve the promise');
240
+        }
241
+    }
242
+
243
+    private function invokeWaitFn()
244
+    {
245
+        try {
246
+            $wfn = $this->waitFn;
247
+            $this->waitFn = null;
248
+            $wfn(true);
249
+        } catch (\Exception $reason) {
250
+            if ($this->state === self::PENDING) {
251
+                // The promise has not been resolved yet, so reject the promise
252
+                // with the exception.
253
+                $this->reject($reason);
254
+            } else {
255
+                // The promise was already resolved, so there's a problem in
256
+                // the application.
257
+                throw $reason;
258
+            }
259
+        }
260
+    }
261
+
262
+    private function invokeWaitList()
263
+    {
264
+        $waitList = $this->waitList;
265
+        $this->waitList = null;
266
+
267
+        foreach ($waitList as $result) {
268
+            do {
269
+                $result->waitIfPending();
270
+                $result = $result->result;
271
+            } while ($result instanceof Promise);
272
+
273
+            if ($result instanceof PromiseInterface) {
274
+                $result->wait(false);
275
+            }
276
+        }
277
+    }
278
+}