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
13use function array_merge;
14use function usort;
15
16/**
17 * Used between the Set type and Encoder.
18 *
19 * @author Chad Sikorra <Chad.Sikorra@gmail.com>
20 */
21trait SetTrait
22{
23    /**
24     * X.680 Sec 8.4. A set is canonical when:
25     *    - Universal classes first.
26     *    - Application classes second.
27     *    - Context specific classes third.
28     *    - Private classes last.
29     *    - Within each group of classes above, tag numbers should be ordered in ascending order.
30     *
31     * @param AbstractType ...$set
32     * @return AbstractType[]
33     */
34    protected function canonicalize(AbstractType ...$set): array
35    {
36        $children = [
37            AbstractType::TAG_CLASS_UNIVERSAL => [],
38            AbstractType::TAG_CLASS_APPLICATION => [],
39            AbstractType::TAG_CLASS_CONTEXT_SPECIFIC => [],
40            AbstractType::TAG_CLASS_PRIVATE => [],
41        ];
42
43        # Group them by their respective class type.
44        foreach ($set as $child) {
45            $children[$child->getTagClass()][] = $child;
46        }
47
48        # Sort the classes by tag number.
49        foreach ($children as $class => $type) {
50            usort($children[$class], function ($a, $b) {
51                /* @var AbstractType $a
52                 * @var AbstractType $b */
53                return ($a->getTagNumber() < $b->getTagNumber()) ? -1 : 1;
54            });
55        }
56
57        return array_merge(
58            $children[AbstractType::TAG_CLASS_UNIVERSAL],
59            $children[AbstractType::TAG_CLASS_APPLICATION],
60            $children[AbstractType::TAG_CLASS_CONTEXT_SPECIFIC],
61            $children[AbstractType::TAG_CLASS_PRIVATE]
62        );
63    }
64}
65