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: 1.0.7
Show newest version
package kotlin.properties

import java.util.NoSuchElementException
import kotlin.reflect.KProperty

/**
 * Standard property delegates.
 */
public object Delegates {
    /**
     * Returns a property delegate for a read/write property with a non-`null` value that is initialized not during
     * object construction time but at a later time. Trying to read the property before the initial value has been
     * assigned results in an exception.
     */
    public fun  notNull(): ReadWriteProperty = NotNullVar()

    /**
     * Returns a property delegate for a read/write property that calls a specified callback function when changed.
     * @param initialValue the initial value of the property.
     * @param onChange the callback which is called after the change of the property is made. The value of the property
     *  has already been changed when this callback is invoked.
     */
    public inline fun  observable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Unit):
        ReadWriteProperty = object : ObservableProperty(initialValue) {
            override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) = onChange(property, oldValue, newValue)
        }

    /**
     * Returns a property delegate for a read/write property that calls a specified callback function when changed,
     * allowing the callback to veto the modification.
     * @param initialValue the initial value of the property.
     * @param onChange the callback which is called before a change to the property value is attempted.
     *  The value of the property hasn't been changed yet, when this callback is invoked.
     *  If the callback returns `true` the value of the property is being set to the new value,
     *  and if the callback returns `false` the new value is discarded and the property remains its old value.
     */
    public inline fun  vetoable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Boolean):
        ReadWriteProperty = object : ObservableProperty(initialValue) {
            override fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = onChange(property, oldValue, newValue)
        }

    /**
     * Returns a property delegate for a read/write property that stores its value in a map, using the property name
     * as a key.
     * @param map the map where the property values are stored.
     */
    @Deprecated("Delegate property to the map itself without creating a wrapper.", ReplaceWith("map"))
    public fun  mapVar(map: MutableMap): ReadWriteProperty {
        return FixedMapVar(map, propertyNameSelector, throwKeyNotFound)
    }

    /**
     * Returns a property delegate for a read/write property that stores its value in a map, using the property name
     * as a key.
     * @param map the map where the property values are stored.
     * @param default the function returning the value of the property for a given object if it's missing from the given map.
     */
    @Deprecated("Complex scenarios of delegation to map are deprecated. Delegate to map itself.")
    public fun  mapVar(map: MutableMap,
                             default: (thisRef: R, propertyName: String) -> T): ReadWriteProperty {
        return FixedMapVar(map, propertyNameSelector, default)
    }

    /**
     * Returns a property delegate for a read-only property that takes its value from a map, using the property name
     * as a key.
     * @param map the map where the property values are stored.
     */
    @Deprecated("Delegate property to the map itself without creating a wrapper.", ReplaceWith("map"))
    public fun  mapVal(map: Map): ReadOnlyProperty {
        return FixedMapVal(map, propertyNameSelector, throwKeyNotFound)
    }

    /**
     * Returns a property delegate for a read-only property that takes its value from a map, using the property name
     * as a key.
     * @param map the map where the property values are stored.
     * @param default the function returning the value of the property for a given object if it's missing from the given map.
     */
    @Deprecated("Complex scenarios of delegation to map are deprecated. Delegate to map itself.")
    public fun  mapVal(map: Map,
                             default: (thisRef: R, propertyName: String) -> T): ReadOnlyProperty {
        return FixedMapVal(map, propertyNameSelector, default)
    }
}


private class NotNullVar() : ReadWriteProperty {
    private var value: T? = null

    public override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return value ?: throw IllegalStateException("Property ${property.name} should be initialized before get.")
    }

    public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        this.value = value
    }
}

/**
 * Implements the core logic of a property delegate for a read/write property that calls callback functions when changed.
 * @param initialValue the initial value of the property.
 */
public abstract class ObservableProperty(initialValue: T) : ReadWriteProperty {
    private var value = initialValue

    /**
     *  The callback which is called before a change to the property value is attempted.
     *  The value of the property hasn't been changed yet, when this callback is invoked.
     *  If the callback returns `true` the value of the property is being set to the new value,
     *  and if the callback returns `false` the new value is discarded and the property remains its old value.
     */
    protected open fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = true

    /**
     * The callback which is called after the change of the property is made. The value of the property
     * has already been changed when this callback is invoked.
     */
    protected open fun afterChange (property: KProperty<*>, oldValue: T, newValue: T): Unit {}

    public override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return value
    }

    public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        val oldValue = this.value
        if (!beforeChange(property, oldValue, value)) {
            return
        }
        this.value = value
        afterChange(property, oldValue, value)
    }
}

/**
 * Implements the core logic for a property delegate that stores property values in a map.
 * @param T the type of the object that owns the delegated property.
 * @param K the type of key in the map.
 * @param V the type of the property value.
 */
@Deprecated("Complex scenarios of delegation to map are deprecated. Delegate to map itself.")
public abstract class MapVal() : ReadOnlyProperty {
    /**
     * Returns the map used to store the values of the properties of the given object instance.
     * @param ref the object instance for which the map is requested.
     */
    protected abstract fun map(ref: T): Map

    /**
     * Returns the map key used to store the values of the given property.
     * @param property the property for which the key is requested.
     */
    protected abstract fun key(property: KProperty<*>): K

    /**
     * Returns the property value to be used when the map does not contain the corresponding key.
     * @param ref the object instance for which the value was requested.
     * @param property the property for which the value was requested.
     */
    protected open fun default(ref: T, property: KProperty<*>): V {
        throw NoSuchElementException("The value for property ${property.name} is missing in $ref.")
    }

    public override fun getValue(thisRef: T, property: KProperty<*>) : V {
        val map = map(thisRef)
        val key = key(property)
        return map.getOrElse(key, { default(thisRef, property) }) as V
    }
}

/**
 * Implements the core logic for a read/write property delegate that stores property values in a map.
 * @param T the type of the object that owns the delegated property.
 * @param K the type of key in the map.
 * @param V the type of the property value.
 */
@Deprecated("Complex scenarios of delegation to map are deprecated. Delegate to map itself.")
public abstract class MapVar() : MapVal(), ReadWriteProperty {
    protected abstract override fun map(ref: T): MutableMap

    public override fun setValue(thisRef: T, property: KProperty<*>, value: V) {
        val map = map(thisRef)
        map.put(key(property), value)
    }

    override fun getValue(thisRef: T, property: KProperty<*>): V {
        return super.getValue(thisRef, property)
    }
}

private val propertyNameSelector: (KProperty<*>) -> String = {it.name}
private val throwKeyNotFound: (Any?, Any?) -> Nothing = {thisRef, key -> throw NoSuchElementException("The value for key $key is missing from $thisRef.") }

/**
 * Implements a read-only property delegate that stores the property values in a given map instance and uses the given
 * callback functions for calculating the key and the default value for each property.
 * @param map the map used to store the values.
 * @param key the function to calculate the map key from a property metadata object.
 * @param default the function returning the value of the property for a given object if it's missing from the given map.
 */
@Deprecated("Complex scenarios of delegation to map are deprecated. Delegate to map itself.")
public open class FixedMapVal(
        private val map: Map,
        private val key: (KProperty<*>) -> K,
        private val default: (ref: T, key: K) -> V = throwKeyNotFound
) : MapVal() {
    protected override fun map(ref: T): Map {
        return map
    }

    protected override fun key(property: KProperty<*>): K {
        return (key)(property)
    }

    protected override fun default(ref: T, property: KProperty<*>): V {
        return (default)(ref, key(property))
    }
}

/**
 * Implements a read/write property delegate that stores the property values in a given map instance and uses the given
 * callback functions for calculating the key and the default value for each property.
 * @param map the map used to store the values.
 * @param key the function to calculate the map key from a property metadata object.
 * @param default the function returning the value of the property for a given object if it's missing from the given map.
 */
@Deprecated("Complex scenarios of delegation to map are deprecated. Delegate to map itself.")
public open class FixedMapVar(
        private val map: MutableMap,
        private val key: (KProperty<*>) -> K,
        private val default: (ref: T, key: K) -> V = throwKeyNotFound
) : MapVar() {
    protected override fun map(ref: T): MutableMap {
        return map
    }

    protected override fun key(property: KProperty<*>): K {
        return (key)(property)
    }

    protected override fun default(ref: T, property: KProperty<*>): V {
        return (default)(ref, key(property))
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy