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.api
18
19 import kotlin.reflect.KClass
20
21 /**
22 * Builds a [DataTypeDescriptor] from the given [name] and using the supplied [block].
23 *
24 * Example:
25 *
26 * ```kotlin
27 * val myType = dataTypeDescriptor("Person", Person::class) {
28 * "name" to FieldType.String
29 * "age" to FieldType.Short
30 * "father" to FieldType.Reference("Person")
31 * "pet" to dataTypeDescriptor("Dog", Dog::class) { }
32 * }
33 * ```
34 */
35 @ChronicleDsl
dataTypeDescriptornull36 fun dataTypeDescriptor(
37 name: String,
38 cls: KClass<*>,
39 block: DataTypeDescriptor.Builder.() -> Unit = {}
40 ): DataTypeDescriptor {
41 return DataTypeDescriptor.Builder(name, cls).apply(block).build()
42 }
43
44 /**
45 * Defines a Chronicle-managed data type. A [DataTypeDescriptor] allows Chronicle to perform
46 * field-by-field data flow analysis for policy enforcement.
47 */
48 data class DataTypeDescriptor(
49 val name: String,
50 val fields: Map<String, FieldType>,
51 val innerTypes: Set<DataTypeDescriptor> = emptySet(),
52 val cls: KClass<*>
53 ) {
54 class Builder(val name: String, val cls: KClass<*>) {
55 private val fields = mutableMapOf<String, FieldType>()
56 private val innerTypes = mutableSetOf<DataTypeDescriptor>()
57
58 /** Adds a field to the [DataTypeDescriptor] being built. */
tonull59 infix fun String.to(type: FieldType) {
60 fields[this] = type
61 }
62
63 /**
64 * Constructs a nested [DataTypeDescriptor] and returns it as a [FieldType.Nested] which can be
65 * used along with [to] to map it to a field name.
66 */
67 @ChronicleDsl
dataTypeDescriptornull68 fun dataTypeDescriptor(
69 name: String,
70 cls: KClass<*>,
71 block: Builder.() -> Unit = {},
72 ): FieldType {
73 val dtd = Builder(name, cls).apply(block).build()
<lambda>null74 require(innerTypes.none { it.name == dtd.name && it != dtd }) {
75 "Duplicate inner type declared with name: ${dtd.name} and different contents"
76 }
77 innerTypes.add(dtd)
78 return FieldType.Nested(dtd.name)
79 }
80
81 /** Builds a [DataTypeDescriptor] from the current state of the [Builder]. */
buildnull82 fun build(): DataTypeDescriptor = DataTypeDescriptor(name, fields, innerTypes, cls)
83 }
84 }
85
86 /** Sealed class of options for field values in [DataTypeDescriptor]s. */
87 sealed class FieldType {
88 /** Represents a field value as a [Boolean] primitive. */
89 object Boolean : FieldType()
90
91 /** Represents a field value as a [Byte] primitive. */
92 object Byte : FieldType()
93
94 /** Represents a field value as a [ByteArray] primitive. */
95 object ByteArray : FieldType()
96
97 /** Represents a field value as a [Short] primitive. */
98 object Short : FieldType()
99
100 /** Represents a field value as a [Integer] primitive. */
101 object Integer : FieldType()
102
103 /** Represents a field value as a [Long] primitive. */
104 object Long : FieldType()
105
106 /** Represents a field value as a [Float] primitive. */
107 object Float : FieldType()
108
109 /** Represents a field value as a [Double] primitive. */
110 object Double : FieldType()
111
112 /** Represents a field value as a [String] primitive. */
113 object String : FieldType()
114
115 /** Represents a field value as a [Char] primitive. */
116 object Char : FieldType()
117
118 /** Represents a field value as a [java.time.Instant]. */
119 object Instant : FieldType()
120
121 /** Represents a field value as a [java.time.Duration]. */
122 object Duration : FieldType()
123
124 /** Represents a field value as an [Enum] object. */
125 data class Enum(
126 val name: kotlin.String,
127 val possibleValues: kotlin.collections.List<kotlin.String>
128 ) : FieldType()
129
130 /** Represents a field value as an array of [itemFieldType] -typed objects. */
131 data class Array(val itemFieldType: FieldType) : FieldType()
132
133 /** Represents a field value as a list of [itemFieldType] -typed objects. */
134 data class List(val itemFieldType: FieldType) : FieldType()
135
136 /**
137 * Represents a field value as a non-primitive value, another [DataTypeDescriptor]-defined type.
138 */
139 data class Nested(val name: kotlin.String) : FieldType()
140
141 /**
142 * Represents a field value as a nullable potentially containing a [itemFieldType]-typed object.
143 */
144 data class Nullable(val itemFieldType: FieldType) : FieldType()
145
146 /**
147 * Represents a field value as a reference to a non-primitive value, another [DataTypeDescriptor]
148 * -defined type.
149 */
150 data class Reference(val name: kotlin.String) : FieldType()
151
152 /**
153 * Represents a field value as a given opaque type, belonging to a small, predetermined set of
154 * possible opaque types. Only the fully-qualified name is used to define the type, with no
155 * [DataTypeDescriptor] definition.
156 */
157 data class Opaque(val name: kotlin.String) : FieldType()
158
159 /** Represents a field value as a tuple with [itemFieldTypes] -typed objects. */
160 data class Tuple(val itemFieldTypes: kotlin.collections.List<FieldType>) : FieldType()
161 }
162