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

org.jetbrains.kotlinx.jupyter.api.VariableState.kt Maven / Gradle / Ivy

package org.jetbrains.kotlinx.jupyter.api

import kotlin.reflect.KProperty
import kotlin.reflect.KProperty1
import kotlin.reflect.jvm.isAccessible

interface VariableState {
    val property: KProperty<*>
    val scriptInstance: Any?
    val stringValue: String?
    val value: Result
}

data class VariableStateImpl(
    override val property: KProperty1,
    override val scriptInstance: Any,
) : VariableState {
    private val stringCache = VariableStateCache {
        value.getOrNull()?.let { value ->
            try {
                value.toString()
            } catch (e: Throwable) {
                "${value::class.simpleName}: [exception thrown: $e]"
            }
        }
    }

    private val valCache = VariableStateCache>(
        { oldValue, newValue ->
            oldValue.getOrNull() !== newValue.getOrNull()
        },
        {
            property.asAccessible { prop ->
                try {
                    Result.success(prop.get(scriptInstance))
                } catch (ex: Throwable) {
                    Result.failure(ex)
                }
            }
        },
    )

    fun update(): Boolean {
        return (valCache.forceUpdate()).also { isChanged ->
            if (isChanged) stringCache.update()
        }
    }

    override val stringValue: String? get() = stringCache.get()

    override val value: Result get() = valCache.get()

    companion object {
        private fun , R> T.asAccessible(action: (T) -> R): R {
            val wasAccessible = isAccessible
            isAccessible = true
            val res = action(this)
            isAccessible = wasAccessible
            return res
        }
    }
}

private class VariableStateCache(
    val equalityChecker: (T, T) -> Boolean = { x, y -> x == y },
    val calculate: (T?) -> T,
) {
    private var cachedVal: T? = null
    private var shouldRenew: Boolean = true

    fun getOrNull(): T? {
        return if (shouldRenew) {
            calculate(cachedVal).also {
                cachedVal = it
                shouldRenew = false
            }
        } else {
            cachedVal
        }
    }

    fun get(): T = getOrNull()!!

    fun update() {
        shouldRenew = true
    }

    fun forceUpdate(): Boolean {
        val oldVal = getOrNull()
        update()
        val newVal = get()
        return oldVal != null && equalityChecker(oldVal, newVal)
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy