kotlin.properties.Delegation.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlin-stdlib Show documentation
Show all versions of kotlin-stdlib Show documentation
Kotlin Standard Library for JVM
package kotlin.properties
public trait ReadOnlyProperty {
public fun get(thisRef: R, desc: PropertyMetadata): T
}
public trait ReadWriteProperty {
public fun get(thisRef: R, desc: PropertyMetadata): T
public fun set(thisRef: R, desc: PropertyMetadata, value: T)
}
public object Delegates {
public fun notNull(): ReadWriteProperty = NotNullVar()
public fun lazy(initializer: () -> T): ReadOnlyProperty = LazyVal(initializer)
public fun blockingLazy(lock: Any? = null, initializer: () -> T): ReadOnlyProperty = BlockingLazyVal(lock, initializer)
public fun observable(initial: T, onChange: (desc: PropertyMetadata, oldValue: T, newValue: T) -> Unit): ReadWriteProperty {
return ObservableProperty(initial) { (desc, old, new) ->
onChange(desc, old, new)
true
}
}
public fun vetoable(initial: T, onChange: (desc: PropertyMetadata, oldValue: T, newValue: T) -> Boolean): ReadWriteProperty {
return ObservableProperty(initial, onChange)
}
public fun mapVar(map: MutableMap,
default: (thisRef: Any?, desc: String) -> T = defaultValueProvider): ReadWriteProperty {
return FixedMapVar(map, defaultKeyProvider, default)
}
public fun mapVal(map: Map,
default: (thisRef: Any?, desc: String) -> T = defaultValueProvider): ReadOnlyProperty {
return FixedMapVal(map, defaultKeyProvider, default)
}
}
private class NotNullVar() : ReadWriteProperty {
private var value: T? = null
public override fun get(thisRef: Any?, desc: PropertyMetadata): T {
return value ?: throw IllegalStateException("Property ${desc.name} should be initialized before get")
}
public override fun set(thisRef: Any?, desc: PropertyMetadata, value: T) {
this.value = value
}
}
class ObservableProperty(initialValue: T, val onChange: (name: PropertyMetadata, oldValue: T, newValue: T) -> Boolean): ReadWriteProperty {
private var value = initialValue
public override fun get(thisRef: Any?, desc: PropertyMetadata): T {
return value
}
public override fun set(thisRef: Any?, desc: PropertyMetadata, value: T) {
if (onChange(desc, this.value, value)) {
this.value = value
}
}
}
private val NULL_VALUE: Any = Any()
private fun escape(value: Any?): Any {
return value ?: NULL_VALUE
}
private fun unescape(value: Any?): Any? {
return if (value == NULL_VALUE) null else value
}
private class LazyVal(private val initializer: () -> T) : ReadOnlyProperty {
private var value: Any? = null
public override fun get(thisRef: Any?, desc: PropertyMetadata): T {
if (value == null) {
value = escape(initializer())
}
return unescape(value) as T
}
}
private class BlockingLazyVal(lock: Any?, private val initializer: () -> T) : ReadOnlyProperty {
private val lock = lock ?: this
private volatile var value: Any? = null
public override fun get(thisRef: Any?, desc: PropertyMetadata): T {
val _v1 = value
if (_v1 != null) {
return unescape(_v1) as T
}
return synchronized(lock) {
val _v2 = value
if (_v2 != null) {
unescape(_v2) as T
}
else {
val typedValue = initializer()
value = escape(typedValue)
typedValue
}
}
}
}
public class KeyMissingException(message: String): RuntimeException(message)
public abstract class MapVal() : ReadOnlyProperty {
protected abstract fun map(ref: T): Map
protected abstract fun key(desc: PropertyMetadata): K
protected open fun default(ref: T, desc: PropertyMetadata): V {
throw KeyMissingException("Key $desc is missing in $ref")
}
public override fun get(thisRef: T, desc: PropertyMetadata) : V {
val map = map(thisRef)
val key = key(desc)
if (!map.containsKey(key)) {
return default(thisRef, desc)
}
return map[key] as V
}
}
public abstract class MapVar() : MapVal(), ReadWriteProperty {
protected abstract override fun map(ref: T): MutableMap
public override fun set(thisRef: T, desc: PropertyMetadata, value: V) {
val map = map(thisRef)
map.put(key(desc), value)
}
}
private val defaultKeyProvider:(PropertyMetadata) -> String = {it.name}
private val defaultValueProvider:(Any?, Any?) -> Nothing = {(thisRef, key) -> throw KeyMissingException("$key is missing from $thisRef")}
public open class FixedMapVal(private val map: Map,
private val key: (PropertyMetadata) -> K,
private val default: (ref: T, key: K) -> V = defaultValueProvider) : MapVal() {
protected override fun map(ref: T): Map {
return map
}
protected override fun key(desc: PropertyMetadata): K {
return (key)(desc)
}
protected override fun default(ref: T, desc: PropertyMetadata): V {
return (default)(ref, key(desc))
}
}
public open class FixedMapVar(private val map: MutableMap,
private val key: (PropertyMetadata) -> K,
private val default: (ref: T, key: K) -> V = defaultValueProvider) : MapVar() {
protected override fun map(ref: T): MutableMap {
return map
}
protected override fun key(desc: PropertyMetadata): K {
return (key)(desc)
}
protected override fun default(ref: T, desc: PropertyMetadata): V {
return (default)(ref, key(desc))
}
}