love.forte.simbot.Attribute.kt Maven / Gradle / Ivy
/*
* Copyright (c) 2021-2021 ForteScarlet
*
* 根据 Apache License 2.0 获得许可;
* 除非遵守许可,否则您不得使用此文件。
* 您可以在以下网址获取许可证副本:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* 有关许可证下的权限和限制的具体语言,请参见许可证。
*/
@file:JvmName("Attributes")
package love.forte.simbot
import kotlinx.serialization.Serializable
import love.forte.simbot.SimbotComponent.name
import kotlin.reflect.KClass
import kotlin.reflect.full.cast
import kotlin.reflect.full.safeCast
/*
* 参考自 gradle-7.1 代码 org.gradle.api.attributes.Attribute, 下述原文LICENSE
*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* 一个属性。
*
* 此类型通常使用在 [Component.attributes], 或者作为事件处理中的上下文使用。
*
* [Attribute] 拥有一个 [属性名][name] 和此属性对应的 [类型][type], 其中,
*
* 对于一个 [Attribute], 它的 [Attribute.hashcode] 将会直接与 [name] 一致,因此可以直接将 [Attribute] 作为一个 [Map] 的 Key.
*
* 但是在进行 [Attribute.equals] 比较的时候,会同时对 [name] 和 [type] 进行比较。
*
* @see AttributeMap
*
*/
@Serializable
public class Attribute private constructor(
public val name: String,
public val type: KClass
) {
private val hashcode: Int get() = name.hashCode()
override fun hashCode(): Int = hashcode
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Attribute<*>) return false
if (name != other.name) return false
return type == other.type
}
override fun toString(): String = name
public companion object {
@Api4J
@JvmStatic
public fun of(name: String, type: Class): Attribute = of(name, type.kotlin)
/**
* @see attribute
*/
@JvmSynthetic
public fun of(name: String, type: KClass): Attribute = Attribute(name, type)
}
}
@JvmSynthetic
public fun attribute(name: String, type: KClass): Attribute = Attribute.of(name, type)
public inline fun attribute(name: String): Attribute = attribute(name, T::class)
public inline fun attribute(): Attribute =
with(T::class) { attribute(qualifiedName ?: name, this) }
/**
* 一个通过 [Attribute] 作为键值来界定其元素类型的映射表。
*
* [AttributeMap]与名称字符串为键的映射表相比,其没有明确的值类型,取而代之的是通过 [Attribute] 来规定元素类型的。
*
*
* [AttributeMap] 中的Key即为 [Attribute], 并且以类型作为 [equals] 条件之一,
* 因此在使用 [AttributeMap] 的时候,应当避免出现相同 [Attribute.name] 但是 [Attribute.type] 不同的情况。
*
*
* [AttributeMap] 不允许存入null值。
*
*
* example:
* ```kotlin
* class Foo
*
* fun test() {
* val fooAttr = attribute("foo")
*
* val map = AttributeHashMap()
* val foo = Foo()
* map[fooAttr] = foo
* val foo1 = map[fooAttr]!!
* val foo2 = map[attribute("foo")]!! // by a new instance
*
* println(foo1 === foo2) // true
* }
* ```
*
* @see AttributeHashMap
*/
public interface AttributeMap {
/**
* 通过 [attribute] 得到对应的数据。
*
* @throws ClassCastException 如果存在对应名称但是类型不匹配的键与值。
*/
public operator fun get(attribute: Attribute): T?
/**
* 判断是否存在对应键名与类型的键。
*/
public fun contains(attribute: Attribute): Boolean
/**
* 数量
*/
public fun size(): Int
public object Empty : AttributeMap {
override fun get(attribute: Attribute): T? = null
override fun contains(attribute: Attribute): Boolean = false
override fun size(): Int = 0
}
}
/**
* [MutableAttributeMap] 是 [AttributeMap] 的子类型,代表一个允许变化的 [AttributeMap], 类似于 [Map] 与 [MutableMap] 之间的关系。
*/
public interface MutableAttributeMap : AttributeMap {
/**
* 存入一个值。
*
* @throws IllegalStateException 如果已经存在重名但是类型不同的键
*/
public fun put(attribute: Attribute, value: T): T?
/**
* 移除对应键名的值。
*
* @throws ClassCastException 如果类型不匹配
*/
public fun remove(attribute: Attribute): T?
}
public operator fun MutableAttributeMap.set(attribute: Attribute, value: T) {
put(attribute, value)
}
public class AttributeHashMap : MutableAttributeMap {
private val values = mutableMapOf, Any>()
public val entries: MutableSet, Any>>
get() = values.entries
override fun size(): Int = values.size
override fun get(attribute: Attribute): T? {
val got = values[attribute] ?: return null
return attribute.type.cast(got)
}
override fun put(attribute: Attribute, value: T): T? {
val type = attribute.type
val result = values.put(attribute, type.cast(value))
return type.safeCast(result)
}
override fun contains(attribute: Attribute): Boolean {
return attribute in values
}
override fun remove(attribute: Attribute): T? {
val removedValue = values.remove(attribute) ?: return null
return removedValue.let { attribute.type.safeCast(it) }
}
override fun toString(): String = values.toString()
}