Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
Hint
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 4
90
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 build
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 isSame
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
30
 __toString
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2declare( strict_types=1 );
3
4/**
5 * @license GPL-2.0-or-later
6 * @file
7 */
8
9namespace Wikimedia\JsonCodec;
10
11use Stringable;
12
13/**
14 * Class hints with modifiers.
15 * @template T
16 */
17class Hint implements Stringable {
18
19    /** @see HintType::DEFAULT */
20    public const DEFAULT = HintType::DEFAULT;
21    /** @see HintType::LIST */
22    public const LIST = HintType::LIST;
23    /** @see HintType::STDCLASS */
24    public const STDCLASS = HintType::STDCLASS;
25    /** @see HintType::USE_SQUARE */
26    public const USE_SQUARE = HintType::USE_SQUARE;
27    /** @see HintType::ALLOW_OBJECT */
28    public const ALLOW_OBJECT = HintType::ALLOW_OBJECT;
29    /** @see HintType::INHERITED */
30    public const INHERITED = HintType::INHERITED;
31    /** @see HintType::ONLY_FOR_DECODE */
32    public const ONLY_FOR_DECODE = HintType::ONLY_FOR_DECODE;
33
34    /**
35     * Create a new serialization class type hint.
36     * @param class-string<T>|Hint<T> $parent
37     * @param HintType $modifier A hint modifier
38     */
39    public function __construct(
40        /** @var class-string<T>|Hint<T> */
41        public readonly string|Hint $parent,
42        public readonly HintType $modifier = HintType::DEFAULT,
43    ) {
44    }
45
46    /**
47     * Helper function to create nested hints.  For example, the
48     * `Foo[][]` type can be created as
49     * `Hint::build(Foo::class, Hint:LIST, Hint::LIST)`.
50     *
51     * Note that, in the grand (?) tradition of C-like types,
52     * modifiers are read right-to-left.  That is, a "stdClass containing
53     * values which are lists of Foo" is written 'backwards' as:
54     * `Hint::build(Foo::class, Hint::LIST, Hint::STDCLASS)`.
55     *
56     * @template T
57     * @param class-string<T>|Hint<T> $classNameOrHint
58     * @param HintType ...$modifiers
59     * @return class-string<T>|Hint<T>
60     */
61    public static function build( string|Hint $classNameOrHint, HintType ...$modifiers ) {
62        if ( count( $modifiers ) === 0 ) {
63            return $classNameOrHint;
64        }
65        $last = array_pop( $modifiers );
66        return new Hint( self::build( $classNameOrHint, ...$modifiers ), $last );
67    }
68
69    /**
70     * Return true if the hint $a is the same as the hint $b.
71     * @param class-string|Hint $a
72     * @param class-string|Hint $b
73     * @return bool
74     */
75    public static function isSame( string|Hint $a, string|Hint $b ): bool {
76        if ( is_string( $a ) ) {
77            return is_string( $b ) && ( $a === $b );
78        }
79        return ( $b instanceof Hint ) && ( $a->modifier === $b->modifier ) &&
80            self::isSame( $a->parent, $b->parent );
81    }
82
83    public function __toString(): string {
84        $parent = strval( $this->parent );
85        return "{$this->modifier->name}({$parent})";
86    }
87}