Completed
Push — master ( ebcbe7...06aa7a )
by Ryosuke
04:11
created

YieldableUtils::getApplier()   A

Complexity

Conditions 4
Paths 1

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 14
ccs 10
cts 10
cp 1
rs 9.2
cc 4
eloc 9
nc 1
nop 3
crap 4
1
<?php
2
3
namespace mpyw\Co\Internal;
4
use mpyw\RuntimePromise\Deferred;
5
6
class YieldableUtils
7
{
8
    /**
9
     * Recursively normalize value.
10
     *   Generator Closure  -> GeneratorContainer
11
     *   Array              -> Array (children's are normalized)
12
     *   Others             -> Others
13
     * @param  mixed    $value
14
     * @param  mixed    $yield_key
15
     * @return mixed
16
     */
17 33
    public static function normalize($value, $yield_key = null)
18 33
    {
19 33
        if (TypeUtils::isGeneratorClosure($value)) {
20 20
            $value = $value();
21
        }
22 33
        if ($value instanceof \Generator) {
23 33
            return new GeneratorContainer($value, $yield_key);
24
        }
25 32
        if (is_array($value)) {
26 22
            $tmp = [];
27 22
            foreach ($value as $k => $v) {
28 22
                $tmp[$k] = self::normalize($v, $yield_key);
29
            }
30 22
            return $tmp;
31
        }
32 31
        return $value;
33
    }
34
35
    /**
36
     * Recursively search yieldable values.
37
     * Each entries are assoc those contain keys 'value' and 'keylist'.
38
     *   value   -> the value itself.
39
     *   keylist -> position of the value. nests are represented as array values.
40
     * @param  mixed $value   Must be already normalized.
41
     * @param  array $keylist Internally used.
42
     * @param  array &$runners Running cURL or Generator identifiers.
43
     * @return array
44
     */
45 31
    public static function getYieldables($value, array $keylist = [], array &$runners = [])
46 31
    {
47 31
        $r = [];
48 31
        if (!is_array($value)) {
49 31
            if (TypeUtils::isCurl($value) || TypeUtils::isGeneratorContainer($value)) {
50 31
                if (isset($runners[(string)$value])) {
51 4
                    throw new \DomainException('Duplicated cURL resource or Generator instance found.');
52
                }
53 31
                $r[(string)$value] = $runners[(string)$value] = [
54 31
                    'value' => $value,
55 31
                    'keylist' => $keylist,
56
                ];
57
            }
58 31
            return $r;
59
        }
60 21
        foreach ($value as $k => $v) {
61 21
            $newlist = array_merge($keylist, [$k]);
62 21
            $r = array_merge($r, self::getYieldables($v, $newlist, $runners));
63
        }
64 17
        return $r;
65
    }
66
67
    /**
68
     * Return function that apply changes in yieldables.
69
     * @param  mixed         $yielded
70
     * @param  array         $yieldables
71
     * @param  callable|null $next
72
     * @return mixed
73
     */
74 23
    public static function getApplier($yielded, array $yieldables, callable $next = null)
75 23
    {
76
        return function (array $results) use ($yielded, $yieldables, $next) {
77 19
            foreach ($results as $hash => $resolved) {
78 19
                $current = &$yielded;
79 19
                foreach ($yieldables[$hash]['keylist'] as $key) {
80 8
                    $current = &$current[$key];
81
                }
82 19
                $current = $resolved;
83 19
                unset($current);
84
            }
85 19
            return $next ? $next($yielded) : $yielded;
86 23
        };
87
    }
88
89
    /**
90
     * Return Deferred that absorbs rejects.
91
     * @param  Deferred $original_dfd
92
     * @return Deferred
93
     */
94 10
    public static function safeDeferred(Deferred $original_dfd)
95 10
    {
96 10
        $dfd = new Deferred;
97 10
        $absorber = function ($any) use ($original_dfd) {
98 8
            $original_dfd->resolve($any);
99 10
        };
100 10
        $dfd->promise()->then($absorber, $absorber);
101 10
        return $dfd;
102
    }
103
}
104