1<?php
2
3/**
4 * This file is part of the ramsey/collection library
5 *
6 * For the full copyright and license information, please view the LICENSE
7 * file that was distributed with this source code.
8 *
9 * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
10 * @license http://opensource.org/licenses/MIT MIT
11 */
12
13declare(strict_types=1);
14
15namespace Ramsey\Collection\Map;
16
17use Ramsey\Collection\Tool\TypeTrait;
18
19/**
20 * A `TypedMap` represents a map of elements where key and value are typed.
21 *
22 * Each element is identified by a key with defined type and a value of defined
23 * type. The keys of the map must be unique. The values on the map can be=
24 * repeated but each with its own different key.
25 *
26 * The most common case is to use a string type key, but it's not limited to
27 * this type of keys.
28 *
29 * This is a direct implementation of `TypedMapInterface`, provided for the sake
30 * of convenience.
31 *
32 * Example usage:
33 *
34 * ```php
35 * $map = new TypedMap('string', Foo::class);
36 * $map['x'] = new Foo();
37 * foreach ($map as $key => $value) {
38 *     // do something with $key, it will be a Foo::class
39 * }
40 *
41 * // this will throw an exception since key must be string
42 * $map[10] = new Foo();
43 *
44 * // this will throw an exception since value must be a Foo
45 * $map['bar'] = 'bar';
46 *
47 * // initialize map with contents
48 * $map = new TypedMap('string', Foo::class, [
49 *     new Foo(), new Foo(), new Foo()
50 * ]);
51 * ```
52 *
53 * It is preferable to subclass `AbstractTypedMap` to create your own typed map
54 * implementation:
55 *
56 * ```php
57 * class FooTypedMap extends AbstractTypedMap
58 * {
59 *     public function getKeyType()
60 *     {
61 *         return 'int';
62 *     }
63 *
64 *     public function getValueType()
65 *     {
66 *          return Foo::class;
67 *     }
68 * }
69 * ```
70 *
71 * … but you also may use the `TypedMap` class:
72 *
73 * ```php
74 * class FooTypedMap extends TypedMap
75 * {
76 *     public function __constructor(array $data = [])
77 *     {
78 *         parent::__construct('int', Foo::class, $data);
79 *     }
80 * }
81 * ```
82 *
83 * @template K
84 * @template T
85 * @extends AbstractTypedMap<K, T>
86 */
87class TypedMap extends AbstractTypedMap
88{
89    use TypeTrait;
90
91    /**
92     * The data type of keys stored in this collection.
93     *
94     * A map key's type is immutable once it is set. For this reason, this
95     * property is set private.
96     *
97     * @var string data type of the map key.
98     */
99    private $keyType;
100
101    /**
102     * The data type of values stored in this collection.
103     *
104     * A map value's type is immutable once it is set. For this reason, this
105     * property is set private.
106     *
107     * @var string data type of the map value.
108     */
109    private $valueType;
110
111    /**
112     * Constructs a map object of the specified key and value types,
113     * optionally with the specified data.
114     *
115     * @param string $keyType The data type of the map's keys.
116     * @param string $valueType The data type of the map's values.
117     * @param array<K, T> $data The initial data to set for this map.
118     */
119    public function __construct(string $keyType, string $valueType, array $data = [])
120    {
121        $this->keyType = $keyType;
122        $this->valueType = $valueType;
123
124        /** @psalm-suppress MixedArgumentTypeCoercion */
125        parent::__construct($data);
126    }
127
128    public function getKeyType(): string
129    {
130        return $this->keyType;
131    }
132
133    public function getValueType(): string
134    {
135        return $this->valueType;
136    }
137}
138