All Downloads are FREE. Search and download functionalities are using the official Maven repository.

kotlin.properties.Delegation.kt Maven / Gradle / Ivy

There is a newer version: 2.1.0-Beta1
Show newest version
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))
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy