[kotlin-tooling-core] Implement ExtrasProperty

KT-55189
This commit is contained in:
Sebastian Sellmair
2022-12-01 11:48:42 +01:00
committed by Space Team
parent 02ec4cb1b5
commit a23e4a1048
3 changed files with 207 additions and 0 deletions
@@ -0,0 +1,92 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.tooling.core
import kotlin.properties.ReadOnlyProperty
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
interface ExtrasProperty<T : Any> {
val key: Extras.Key<T>
}
val <T : Any> Extras.Key<T>.readProperty get() = extrasReadProperty(this)
val <T : Any> Extras.Key<T>.readWriteProperty get() = extrasReadWriteProperty(this)
fun <T : Any> Extras.Key<T>.factoryProperty(factory: () -> T) = extrasFactoryProperty(this, factory)
fun <T : Any> extrasReadProperty(key: Extras.Key<T>): ExtrasReadOnlyProperty<T> = object : ExtrasReadOnlyProperty<T> {
override val key: Extras.Key<T> = key
}
fun <T : Any> extrasReadWriteProperty(key: Extras.Key<T>): ExtrasReadWriteProperty<T> = object : ExtrasReadWriteProperty<T> {
override val key: Extras.Key<T> = key
}
fun <T : Any> extrasFactoryProperty(key: Extras.Key<T>, factory: () -> T) = object : ExtrasFactoryProperty<T> {
override val key: Extras.Key<T> = key
override val factory: () -> T = factory
}
interface ExtrasReadOnlyProperty<T : Any> : ExtrasProperty<T>, ReadOnlyProperty<HasExtras, T?> {
override fun getValue(thisRef: HasExtras, property: KProperty<*>): T? {
return thisRef.extras[key]
}
fun notNull(defaultValue: T): NotNullExtrasReadOnlyProperty<T> = object : NotNullExtrasReadOnlyProperty<T> {
override val defaultValue: T = defaultValue
override val key: Extras.Key<T> = this@ExtrasReadOnlyProperty.key
}
}
interface NotNullExtrasReadOnlyProperty<T : Any> : ExtrasProperty<T>, ReadOnlyProperty<HasExtras, T> {
val defaultValue: T
override fun getValue(thisRef: HasExtras, property: KProperty<*>): T {
return thisRef.extras[key] ?: defaultValue
}
}
interface ExtrasReadWriteProperty<T : Any> : ExtrasProperty<T>, ReadWriteProperty<HasMutableExtras, T?> {
override fun getValue(thisRef: HasMutableExtras, property: KProperty<*>): T? {
return thisRef.extras[key]
}
override fun setValue(thisRef: HasMutableExtras, property: KProperty<*>, value: T?) {
if (value != null) thisRef.extras[key] = value
else thisRef.extras.remove(key)
}
fun notNull(defaultValue: T): NotNullExtrasReadWriteProperty<T> = object : NotNullExtrasReadWriteProperty<T> {
override val defaultValue: T = defaultValue
override val key: Extras.Key<T> = this@ExtrasReadWriteProperty.key
}
}
interface NotNullExtrasReadWriteProperty<T : Any> : ExtrasProperty<T>, ReadWriteProperty<HasMutableExtras, T> {
val defaultValue: T
override fun getValue(thisRef: HasMutableExtras, property: KProperty<*>): T {
return thisRef.extras[key] ?: defaultValue
}
override fun setValue(thisRef: HasMutableExtras, property: KProperty<*>, value: T) {
thisRef.extras[key] = value
}
}
interface ExtrasFactoryProperty<T : Any> : ExtrasProperty<T>, ReadWriteProperty<HasMutableExtras, T> {
val factory: () -> T
override fun getValue(thisRef: HasMutableExtras, property: KProperty<*>): T {
return thisRef.extras.getOrPut(key, factory)
}
override fun setValue(thisRef: HasMutableExtras, property: KProperty<*>, value: T) {
thisRef.extras[key] = value
}
}
@@ -27,3 +27,5 @@ operator fun <T : Any> Extras.Key<T>.setValue(receiver: HasMutableExtras, proper
receiver.extras[this] = value
}
}
@@ -0,0 +1,113 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.tooling.core
import kotlin.test.*
class ExtrasPropertyTest {
class Subject : HasMutableExtras {
override val extras: MutableExtras = mutableExtrasOf()
}
class Dummy
private val keyA = extrasKeyOf<Int>("a")
private val keyB = extrasKeyOf<Int>("b")
private val Subject.readA: Int? by keyA.readProperty
private val Subject.readB: Int? by keyB.readProperty
private var Subject.readWriteA: Int? by keyA.readWriteProperty
private var Subject.readWriteB: Int? by keyB.readWriteProperty
private val Subject.notNullReadA: Int by keyA.readProperty.notNull(1)
private val Subject.notNullReadB: Int by keyB.readProperty.notNull(2)
private var Subject.notNullReadWriteA: Int by keyA.readWriteProperty.notNull(3)
private var Subject.notNullReadWriteB: Int by keyB.readWriteProperty.notNull(4)
private val keyList = extrasKeyOf<MutableList<Dummy>>()
private val Subject.factoryList: MutableList<Dummy> by keyList.factoryProperty { mutableListOf() }
@Test
fun `test - readOnlyProperty`() {
val subject = Subject()
assertNull(subject.readA)
assertNull(subject.readB)
subject.readWriteA = 1
assertEquals(1, subject.readA)
assertNull(subject.readB)
subject.readWriteB = 2
assertEquals(1, subject.readA)
assertEquals(2, subject.readB)
}
@Test
fun `test - readWriteProperty`() {
val subject = Subject()
assertNull(subject.readWriteA)
assertNull(subject.readWriteB)
subject.readWriteA = 1
assertEquals(1, subject.readWriteA)
assertNull(subject.readB)
subject.readWriteB = 2
assertEquals(1, subject.readWriteA)
assertEquals(2, subject.readWriteB)
}
@Test
fun `test - readOnlyProperty - notNull`() {
val subject = Subject()
assertEquals(1, subject.notNullReadA)
assertEquals(2, subject.notNullReadB)
subject.readWriteA = -1
assertEquals(-1, subject.notNullReadA)
assertEquals(2, subject.notNullReadB)
subject.readWriteB = -2
assertEquals(-1, subject.notNullReadA)
assertEquals(-2, subject.notNullReadB)
}
@Test
fun `test - readWriteProperty - notNull`() {
val subject = Subject()
assertEquals(3, subject.notNullReadWriteA)
assertEquals(4, subject.notNullReadWriteB)
subject.notNullReadWriteA = -1
assertEquals(-1, subject.notNullReadWriteA)
assertEquals(4, subject.notNullReadWriteB)
subject.notNullReadWriteB = -2
assertEquals(-1, subject.notNullReadWriteA)
assertEquals(-2, subject.notNullReadWriteB)
}
@Test
fun `test - factoryProperty`() {
run {
val subject = Subject()
assertNotNull(subject.factoryList)
assertSame(subject.factoryList, subject.factoryList)
assertSame(subject.extras[keyList], subject.factoryList)
}
run {
val subject = Subject()
val list = mutableListOf(Dummy())
subject.extras[keyList] = list
assertSame(list, subject.factoryList)
}
}
}