1 /* 2 * Copyright (C) 2024 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.tools.metalava.model 18 19 import kotlin.reflect.KClass 20 import kotlin.reflect.cast 21 22 /** 23 * A type safe, immutable set of model options. 24 * 25 * Used to allow a user of a model to pass model specific options through to a model. 26 */ 27 class ModelOptions 28 private constructor( 29 /** Description of the model options. */ 30 private val description: String, 31 /** The option settings. */ 32 private val settings: Map<Key<*>, Any>, 33 ) { 34 /** Get an option value using the type safe [Key]. */ getnull35 operator fun <T : Any> get(key: Key<T>): T { 36 return settings[key]?.let { key.kClass.cast(it) } ?: key.default 37 } 38 toStringnull39 override fun toString(): String { 40 return description 41 } 42 isEmptynull43 fun isEmpty(): Boolean { 44 return settings.isEmpty() 45 } 46 47 /** Builder for [ModelOptionsBuilder]. */ 48 class ModelOptionsBuilder internal constructor() { 49 /** The option settings. */ 50 internal val settings = mutableMapOf<Key<*>, Any>() 51 52 /** 53 * Map from [Key.name] to the [Key] used within this set of options. This is used to ensure 54 * that two keys with the same name cannot be used within the same set of options. 55 */ 56 private val keys = mutableMapOf<String, Key<*>>() 57 58 /** Set an option value using the type safe [Key]. */ setnull59 operator fun <T : Any> set(key: Key<T>, value: T) { 60 val existingKey = keys.put(key.name, key) 61 if (existingKey != null) 62 throw IllegalStateException( 63 "Duplicate keys with the same name $key and $existingKey" 64 ) 65 66 settings[key] = value 67 } 68 } 69 70 companion object { 71 val empty = ModelOptions("empty", emptyMap()) 72 73 /** Build a [ModelOptions]. */ buildnull74 fun build(description: String, block: ModelOptionsBuilder.() -> Unit): ModelOptions { 75 val builder = ModelOptionsBuilder() 76 builder.block() 77 return ModelOptions(description, builder.settings.toMap()) 78 } 79 } 80 81 /** A type safe opaque key. */ 82 class Key<T : Any> 83 @PublishedApi 84 internal constructor( 85 internal val name: String, 86 internal val default: T, 87 internal val kClass: KClass<T> 88 ) { 89 toStringnull90 override fun toString() = "Key($name, $default, $kClass)" 91 92 companion object { 93 /** 94 * Create a type safe key. 95 * 96 * @param name the name of the key, this should be unique across all key names to allow 97 * multiple different options from different models to be set together without 98 * conflict. It is recommended to prefix the name with the name of the model, e.g. 99 * `model.option`. 100 * @param default the default value of the key. 101 */ 102 inline fun <reified T : Any> of(name: String, default: T): Key<T> { 103 return Key(name, default, T::class) 104 } 105 } 106 } 107 } 108