1 /* <lambda>null2 * 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.api.integration 18 19 import com.android.libraries.pcc.chronicle.api.DataTypeDescriptor 20 import com.android.libraries.pcc.chronicle.api.DataTypeDescriptorSet 21 import com.android.libraries.pcc.chronicle.api.FieldType 22 import java.time.Duration 23 import java.time.Instant 24 import kotlin.reflect.KClass 25 26 /** Default implementation of [DataTypeDescriptorSet]. */ 27 class DefaultDataTypeDescriptorSet(private val dtds: Set<DataTypeDescriptor>) : 28 DataTypeDescriptorSet { 29 private val dtdsByName: Map<String, DataTypeDescriptor> = 30 dtds.flatMap { collectNestedDataTypeDescriptors(it) }.associateBy { it.name } 31 32 private val dtdsByKClass: Map<KClass<*>, DataTypeDescriptor> = 33 dtdsByName.values.associateBy { it.cls } 34 35 private fun collectNestedDataTypeDescriptors(dtd: DataTypeDescriptor): List<DataTypeDescriptor> { 36 return dtd.innerTypes.fold(listOf(dtd)) { acc, t -> acc + collectNestedDataTypeDescriptors(t) } 37 } 38 39 override fun getOrNull(name: String): DataTypeDescriptor? = dtdsByName[name] 40 41 override tailrec fun findFieldTypeOrThrow( 42 dtd: DataTypeDescriptor, 43 accessPath: List<String>, 44 ): FieldType { 45 require(accessPath.isNotEmpty()) { "Cannot find field type for empty access path." } 46 47 val field = accessPath[0] 48 val fieldType = 49 requireNotNull(dtd.fields[field]) { "Field \"$field\" not found in ${dtd.name}" } 50 51 if (accessPath.size == 1) return fieldType 52 53 val nextDtd = requireNotNull(findDataTypeDescriptor(fieldType)) 54 return findFieldTypeOrThrow(nextDtd, accessPath.drop(1)) 55 } 56 57 override fun findDataTypeDescriptor(fieldType: FieldType): DataTypeDescriptor? { 58 return when (fieldType) { 59 is FieldType.Array -> findDataTypeDescriptor(fieldType.itemFieldType) 60 is FieldType.List -> findDataTypeDescriptor(fieldType.itemFieldType) 61 is FieldType.Nullable -> findDataTypeDescriptor(fieldType.itemFieldType) 62 is FieldType.Nested -> getOrNull(fieldType.name) 63 is FieldType.Reference -> getOrNull(fieldType.name) 64 FieldType.Boolean, 65 FieldType.Byte, 66 FieldType.ByteArray, 67 FieldType.Char, 68 FieldType.Double, 69 FieldType.Duration, 70 FieldType.Float, 71 FieldType.Instant, 72 FieldType.Integer, 73 FieldType.Long, 74 FieldType.Short, 75 FieldType.String, 76 is FieldType.Enum, 77 is FieldType.Opaque, 78 // We would need to know which item within the tuple we are interested in. 79 is FieldType.Tuple -> null 80 } 81 } 82 83 override fun findDataTypeDescriptor(cls: KClass<*>): DataTypeDescriptor? = dtdsByKClass[cls] 84 85 override fun fieldTypeAsClass(fieldType: FieldType): Class<*> { 86 return when (fieldType) { 87 FieldType.Boolean -> Boolean::class.javaObjectType 88 FieldType.Byte -> Byte::class.javaObjectType 89 FieldType.ByteArray -> ByteArray::class.java 90 FieldType.Char -> Char::class.javaObjectType 91 FieldType.Double -> Double::class.javaObjectType 92 FieldType.Duration -> Duration::class.java 93 FieldType.Float -> Float::class.javaObjectType 94 FieldType.Instant -> Instant::class.java 95 FieldType.Integer -> Int::class.javaObjectType 96 FieldType.Long -> Long::class.javaObjectType 97 FieldType.Short -> Short::class.javaObjectType 98 FieldType.String -> String::class.java 99 is FieldType.Enum -> Enum::class.java 100 is FieldType.Array -> Array::class.java 101 is FieldType.List -> List::class.java 102 is FieldType.Reference -> this[fieldType.name].cls.java 103 is FieldType.Nested -> this[fieldType.name].cls.java 104 is FieldType.Opaque -> Class.forName(fieldType.name) 105 is FieldType.Nullable -> fieldTypeAsClass(fieldType.itemFieldType) 106 is FieldType.Tuple -> 107 // TODO(b/208662121): Tuples could be android.util.Pair or kotlin.Pair (or similar) 108 throw IllegalArgumentException("Tuple is too ambiguous to return a field type.") 109 } 110 } 111 112 override fun toSet(): Set<DataTypeDescriptor> = dtds 113 } 114