1<?php
2/**
3 * This file is part of the FreeDSx ASN1 package.
4 *
5 * (c) Chad Sikorra <Chad.Sikorra@gmail.com>
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10
11namespace FreeDSx\Asn1\Type;
12
13/**
14 * Used between the Set type and Encoder.
15 *
16 * @author Chad Sikorra <Chad.Sikorra@gmail.com>
17 */
18trait SetTrait
19{
20    /**
21     * X.680 Sec 8.4. A set is canonical when:
22     *    - Universal classes first.
23     *    - Application classes second.
24     *    - Context specific classes third.
25     *    - Private classes last.
26     *    - Within each group of classes above, tag numbers should be ordered in ascending order.
27     *
28     * @param AbstractType ...$set
29     * @return AbstractType[]
30     */
31    protected function canonicalize(AbstractType ...$set) : array
32    {
33        $children = [
34            AbstractType::TAG_CLASS_UNIVERSAL => [],
35            AbstractType::TAG_CLASS_APPLICATION => [],
36            AbstractType::TAG_CLASS_CONTEXT_SPECIFIC => [],
37            AbstractType::TAG_CLASS_PRIVATE => [],
38        ];
39
40        # Group them by their respective class type.
41        foreach ($set as $child) {
42            $children[$child->getTagClass()][] = $child;
43        }
44
45        # Sort the classes by tag number.
46        foreach ($children as $class => $type) {
47            \usort($children[$class], function ($a, $b) {
48                /* @var AbstractType $a
49                 * @var AbstractType $b */
50                return ($a->getTagNumber() < $b->getTagNumber()) ? -1 : 1;
51            });
52        }
53
54        return \array_merge(
55            $children[AbstractType::TAG_CLASS_UNIVERSAL],
56            $children[AbstractType::TAG_CLASS_APPLICATION],
57            $children[AbstractType::TAG_CLASS_CONTEXT_SPECIFIC],
58            $children[AbstractType::TAG_CLASS_PRIVATE]
59        );
60    }
61}
62