1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.libraries.pcc.chronicle.util
18 
19 /**
20  * A [MutableTypedMap] is a mutable, type-safe map that allows for heterogeneously typed values.
21  *
22  * This map is keyed using implementations of the [Key] interface. A [Key] implementation will
23  * specify the class type of a corresponding value to be stored in the map.
24  *
25  * Example:
26  *
27  * ```kotlin
28  * object NameKey : Key<String>
29  * object IdKey : Key<Int>
30  *
31  * map[NameKey] = "First Last"
32  * map[IdKey] = 123
33  * ```
34  */
35 class MutableTypedMap(val map: MutableMap<Key<Any>, Any> = mutableMapOf()) {
36 
37   /** Set a value of type T for the given key */
setnull38   operator fun <T : Any> set(key: Key<T>, value: T) {
39     @Suppress("UNCHECKED_CAST")
40     map[key as Key<Any>] = value
41   }
42 
43   /** Get object of type T or null if not present */
getnull44   operator fun <T> get(key: Key<T>): T? {
45     @Suppress("UNCHECKED_CAST") return map[key as Key<Any>] as T
46   }
47 
48   /** Get immutable version of this [MutableTypedMap] */
toTypedMapnull49   fun toTypedMap() = TypedMap(this)
50 
51   override fun equals(other: Any?): Boolean {
52     if (this === other) return true
53     if (other !is MutableTypedMap) return false
54     if (map != other.map) return false
55     return true
56   }
57 
hashCodenull58   override fun hashCode(): Int {
59     return map.hashCode()
60   }
61 }
62 
63 /**
64  * Keying structure for the [TypedMap] that can be associated with a value of type T, where T is a
65  * basic type (https://kotlinlang.org/docs/basic-types.html)
66  *
67  * Non-basic types are not recommended, since deep copies are currently not supported.
68  *
69  * Example usage of a [Key] for a String value:
70  * ```kotlin
71  * object Name : Key<String>
72  *
73  * // Set Name
74  * mutableTypedMap[Name] = "First Last"
75  * typedMap = TypedMap(mutableTypedMap)
76  *
77  * // Get Name
78  * val myName = typedMap[Name]
79  * ```
80  */
81 interface Key<T>
82 
83 /**
84  * A [TypedMap] is an immutable, type-safe map that allows for heterogeneously typed values. It
85  * copies in the current state of a provided [MutableTypedMap].
86  */
87 class TypedMap(mutableTypedMap: MutableTypedMap = MutableTypedMap()) {
88   private val map: MutableTypedMap = MutableTypedMap(mutableTypedMap.map.toMutableMap())
89 
90   /** Get object of type T or null if not present */
getnull91   operator fun <T> get(key: Key<T>): T? = map[key]
92 
93   override fun equals(other: Any?): Boolean {
94     if (this === other) return true
95     if (other !is TypedMap) return false
96     if (map != other.map) return false
97     return true
98   }
99 
hashCodenull100   override fun hashCode(): Int {
101     return map.hashCode()
102   }
103 }
104