PluginProbe
Gmail SMTP / trunk
Gmail SMTP vtrunk
1.2.3.21 1.2.3.20 trunk 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.9 1.2.0 1.2.3.14 1.2.3.15 1.2.3.16 1.2.3.18 1.2.3.5
gmail-smtp / google-api-php-client / vendor / guzzlehttp / promises / src / Utils.php

Utils.php in Gmail SMTP trunk, at google-api-php-client/vendor/guzzlehttp/promises/src/Utils.php

306 lines 9.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4
5 namespace GuzzleHttp\Promise;
6
7 final class Utils
8 {
9 /**
10 * Get the global task queue used for promise resolution.
11 *
12 * This task queue MUST be run in an event loop in order for promises to be
13 * settled asynchronously. It will be automatically run when synchronously
14 * waiting on a promise.
15 *
16 * <code>
17 * while ($eventLoop->isRunning()) {
18 * GuzzleHttp\Promise\Utils::queue()->run();
19 * }
20 * </code>
21 *
22 * @param TaskQueueInterface|null $assign Optionally specify a new queue instance.
23 */
24 public static function queue(?TaskQueueInterface $assign = null): TaskQueueInterface
25 {
26 static $queue;
27
28 if ($assign) {
29 $queue = $assign;
30 } elseif (!$queue) {
31 $queue = new TaskQueue();
32 }
33
34 return $queue;
35 }
36
37 /**
38 * Adds a function to run in the task queue when it is next `run()` and
39 * returns a promise that is fulfilled or rejected with the result.
40 *
41 * @param callable $task Task function to run.
42 */
43 public static function task(callable $task): PromiseInterface
44 {
45 $queue = self::queue();
46 $promise = new Promise([$queue, 'run']);
47 $queue->add(function () use ($task, $promise): void {
48 try {
49 if (Is::pending($promise)) {
50 $promise->resolve($task());
51 }
52 } catch (\Throwable $e) {
53 $promise->reject($e);
54 }
55 });
56
57 return $promise;
58 }
59
60 /**
61 * Synchronously waits on a promise to resolve and returns an inspection
62 * state array.
63 *
64 * Returns a state associative array containing a "state" key mapping to a
65 * valid promise state. If the state of the promise is "fulfilled", the
66 * array will contain a "value" key mapping to the fulfilled value of the
67 * promise. If the promise is rejected, the array will contain a "reason"
68 * key mapping to the rejection reason of the promise.
69 *
70 * @param PromiseInterface $promise Promise or value.
71 */
72 public static function inspect(PromiseInterface $promise): array
73 {
74 try {
75 return [
76 'state' => PromiseInterface::FULFILLED,
77 'value' => $promise->wait(),
78 ];
79 } catch (\Throwable $e) {
80 if ($e instanceof AggregateException) {
81 return ['state' => PromiseInterface::REJECTED, 'reason' => $e];
82 }
83
84 if ($e instanceof RejectionException) {
85 return ['state' => PromiseInterface::REJECTED, 'reason' => $e->getReason()];
86 }
87
88 return ['state' => PromiseInterface::REJECTED, 'reason' => $e];
89 }
90 }
91
92 /**
93 * Waits on all of the provided promises, but does not unwrap rejected
94 * promises as thrown exception.
95 *
96 * Returns an array of inspection state arrays.
97 *
98 * @see inspect for the inspection state array format.
99 *
100 * @param PromiseInterface[] $promises Traversable of promises to wait upon.
101 */
102 public static function inspectAll($promises): array
103 {
104 $promises = self::prepareIterable($promises, __FUNCTION__);
105
106 $results = [];
107 foreach ($promises as $key => $promise) {
108 $results[$key] = self::inspect($promise);
109 }
110
111 return $results;
112 }
113
114 /**
115 * Waits on all of the provided promises and returns the fulfilled values.
116 *
117 * Returns an array that contains the value of each promise (in the same
118 * order the promises were provided). An exception is thrown if any of the
119 * promises are rejected.
120 *
121 * @param iterable<PromiseInterface> $promises Iterable of PromiseInterface objects to wait on.
122 *
123 * @throws \Throwable on error
124 */
125 public static function unwrap($promises): array
126 {
127 $promises = self::prepareIterable($promises, __FUNCTION__);
128
129 $results = [];
130 foreach ($promises as $key => $promise) {
131 $results[$key] = $promise->wait();
132 }
133
134 return $results;
135 }
136
137 /**
138 * Given an array of promises, return a promise that is fulfilled when all
139 * the items in the array are fulfilled.
140 *
141 * The promise's fulfillment value is an array with fulfillment values at
142 * respective positions to the original array. If any promise in the array
143 * rejects, the returned promise is rejected with the rejection reason.
144 *
145 * @param mixed $promises Promises or values.
146 * @param bool $recursive If true, resolves new promises that might have been added to the stack during its own resolution.
147 */
148 public static function all($promises, bool $recursive = false): PromiseInterface
149 {
150 $promises = self::prepareIterable($promises, __FUNCTION__);
151
152 $results = [];
153 $promise = Each::of(
154 $promises,
155 function ($value, $idx) use (&$results): void {
156 $results[$idx] = $value;
157 },
158 function ($reason, $idx, Promise $aggregate): void {
159 if (Is::pending($aggregate)) {
160 $aggregate->reject($reason);
161 }
162 }
163 )->then(function () use (&$results) {
164 ksort($results);
165
166 return $results;
167 });
168
169 if (true === $recursive) {
170 $promise = $promise->then(function ($results) use ($recursive, &$promises) {
171 foreach ($promises as $promise) {
172 if (Is::pending($promise)) {
173 return self::all($promises, $recursive);
174 }
175 }
176
177 return $results;
178 });
179 }
180
181 return $promise;
182 }
183
184 /**
185 * Initiate a competitive race between multiple promises or values (values
186 * will become immediately fulfilled promises).
187 *
188 * When count amount of promises have been fulfilled, the returned promise
189 * is fulfilled with an array that contains the fulfillment values of the
190 * winners in order of resolution.
191 *
192 * This promise is rejected with a {@see AggregateException} if the number
193 * of fulfilled promises is less than the desired $count.
194 *
195 * @param int $count Total number of promises.
196 * @param mixed $promises Promises or values.
197 */
198 public static function some(int $count, $promises): PromiseInterface
199 {
200 $promises = self::prepareIterable($promises, __FUNCTION__);
201
202 $results = [];
203 $rejections = [];
204
205 return Each::of(
206 $promises,
207 function ($value, $idx, PromiseInterface $p) use (&$results, $count): void {
208 if (Is::settled($p)) {
209 return;
210 }
211 $results[$idx] = $value;
212 if (count($results) >= $count) {
213 $p->resolve(null);
214 }
215 },
216 function ($reason) use (&$rejections): void {
217 $rejections[] = $reason;
218 }
219 )->then(
220 function () use (&$results, &$rejections, $count) {
221 if (count($results) !== $count) {
222 throw new AggregateException(
223 'Not enough promises to fulfill count',
224 $rejections
225 );
226 }
227 ksort($results);
228
229 return array_values($results);
230 }
231 );
232 }
233
234 /**
235 * Like some(), with 1 as count. However, if the promise fulfills, the
236 * fulfillment value is not an array of 1 but the value directly.
237 *
238 * @param mixed $promises Promises or values.
239 */
240 public static function any($promises): PromiseInterface
241 {
242 $promises = self::prepareIterable($promises, __FUNCTION__);
243
244 return self::some(1, $promises)->then(function ($values) {
245 return $values[0];
246 });
247 }
248
249 /**
250 * Returns a promise that is fulfilled when all of the provided promises have
251 * been fulfilled or rejected.
252 *
253 * The returned promise is fulfilled with an array of inspection state arrays.
254 *
255 * @see inspect for the inspection state array format.
256 *
257 * @param mixed $promises Promises or values.
258 */
259 public static function settle($promises): PromiseInterface
260 {
261 $promises = self::prepareIterable($promises, __FUNCTION__);
262
263 $results = [];
264
265 return Each::of(
266 $promises,
267 function ($value, $idx) use (&$results): void {
268 $results[$idx] = ['state' => PromiseInterface::FULFILLED, 'value' => $value];
269 },
270 function ($reason, $idx) use (&$results): void {
271 $results[$idx] = ['state' => PromiseInterface::REJECTED, 'reason' => $reason];
272 }
273 )->then(function () use (&$results) {
274 ksort($results);
275
276 return $results;
277 });
278 }
279
280 private static function prepareIterable($promises, string $method): iterable
281 {
282 if (is_iterable($promises)) {
283 return $promises;
284 }
285
286 self::triggerNonIterableDeprecation($promises, $method);
287
288 return [$promises];
289 }
290
291 private static function triggerNonIterableDeprecation($promises, string $method): void
292 {
293 if (is_iterable($promises)) {
294 return;
295 }
296
297 \trigger_deprecation(
298 'guzzlehttp/promises',
299 '2.5',
300 'Passing a non-iterable to %s::%s() is deprecated; guzzlehttp/promises 3.0 will require an iterable.',
301 self::class,
302 $method
303 );
304 }
305 }
306