Passed
Pull Request — master (#78)
by Eugene
02:11
created

DecimalExtension::unpackExt()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 11
c 1
b 0
f 0
nc 6
nop 2
dl 0
loc 21
ccs 12
cts 12
cp 1
crap 4
rs 9.9
1
<?php
2
3
/**
4
 * This file is part of the tarantool/client package.
5
 *
6
 * (c) Eugene Leonovich <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Tarantool\Client\Packer\Extension;
15
16
use Decimal\Decimal;
17
use MessagePack\BufferUnpacker;
18
use MessagePack\Extension;
19
use MessagePack\Packer;
20
21
final class DecimalExtension implements Extension
22
{
23
    private const TYPE = 1;
24
    private const PRECISION = 38;
25
26 48
    public function getType() : int
27
    {
28 48
        return self::TYPE;
29
    }
30
31 38
    public function pack(Packer $packer, $value) : ?string
32
    {
33 38
        if (!$value instanceof Decimal) {
34
            return null;
35
        }
36
37
        // @see https://github.com/php-decimal/ext-decimal/issues/22#issuecomment-512364914
38 38
        $data = $value->toFixed(self::PRECISION);
39
40 38
        if ('-' === $data[0]) {
41 8
            $nibble = 'd';
42 8
            $data = \substr($data, 1);
43
        } else {
44 30
            $nibble = 'c';
45
        }
46
47 38
        $pieces = \explode('.', $data, 2);
48 38
        $pieces[1] = \rtrim($pieces[1], '0');
49
50 38
        $data = "{$pieces[0]}{$pieces[1]}{$nibble}";
51 38
        if (0 !== \strlen($data) % 2) {
52 24
            $data = '0'.$data;
53
        }
54
55 38
        return $packer->packExt(self::TYPE,
56 38
            $packer->packInt('' === $pieces[1] ? 0 : \strlen($pieces[1])).\hex2bin($data)
57
        );
58
    }
59
60
    /**
61
     * @return Decimal
62
     */
63 38
    public function unpackExt(BufferUnpacker $unpacker, int $extLength)
64
    {
65
        /**
66
         * @psalm-suppress UndefinedDocblockClass (suppresses \GMP)
67
         * @var int $scale
68
         */
69 38
        $scale = $unpacker->unpackInt();
70 38
        $data = $unpacker->read($extLength - 1);
71 38
        $data = \bin2hex($data);
72
73 38
        $sign = 'd' === $data[-1] ? '-' : '';
74 38
        $dec = \substr($data, 0, -1);
75
76 38
        if (0 !== $scale) {
77 22
            $length = \strlen($dec);
78 22
            $dec = ($length <= $scale)
79 10
                ? \substr_replace($dec, '0.'.\str_repeat('0', $scale - $length), -$scale, 0)
80 22
                : \substr_replace($dec, '.', -$scale, 0);
81
        }
82
83 38
        return new Decimal($sign.$dec, self::PRECISION);
0 ignored issues
show
Bug introduced by
Are you sure $dec of type array|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

83
        return new Decimal($sign./** @scrutinizer ignore-type */ $dec, self::PRECISION);
Loading history...
84
    }
85
}
86