mirror of
https://github.com/divkit/divkit.git
synced 2026-06-06 20:07:59 +00:00
stop generating expression resolvers outside RuntimeStore
commit_hash:bd6db1f47f1cf7b663f3b6b69526fab5dc32b125
This commit is contained in:
+31
-2
@@ -2,6 +2,7 @@ package com.yandex.div.core.expression
|
||||
|
||||
import com.yandex.div.core.Disposable
|
||||
import com.yandex.div.core.ObserverList
|
||||
import com.yandex.div.core.expression.local.RuntimeStore
|
||||
import com.yandex.div.core.expression.variables.ConstantsProvider
|
||||
import com.yandex.div.core.expression.variables.VariableAndConstantController
|
||||
import com.yandex.div.core.expression.variables.VariableController
|
||||
@@ -26,10 +27,15 @@ import com.yandex.div.json.typeMismatch
|
||||
import org.json.JSONObject
|
||||
|
||||
internal class ExpressionResolverImpl(
|
||||
/**
|
||||
* Unique path by which resolver could be found at [RuntimeStore].
|
||||
*/
|
||||
internal val path: String,
|
||||
internal val runtimeStore: RuntimeStore,
|
||||
private val variableController: VariableController,
|
||||
private val evaluator: Evaluator,
|
||||
private val errorCollector: ErrorCollector,
|
||||
private val onCreateCallback: OnCreateCallback
|
||||
private val onCreateCallback: OnCreateCallback,
|
||||
) : ExpressionResolver {
|
||||
|
||||
private val evaluationsCache = mutableMapOf<String, Any>()
|
||||
@@ -230,9 +236,12 @@ internal class ExpressionResolverImpl(
|
||||
}
|
||||
}
|
||||
|
||||
operator fun plus(constants: ConstantsProvider): ExpressionResolverImpl {
|
||||
internal fun withConstants(pathSegment: String,
|
||||
constants: ConstantsProvider): ExpressionResolverImpl {
|
||||
val variableAndConstantController = VariableAndConstantController(variableController, constants)
|
||||
return ExpressionResolverImpl(
|
||||
path = this.path + "/" + pathSegment,
|
||||
runtimeStore = this.runtimeStore,
|
||||
variableController = variableAndConstantController,
|
||||
evaluator = Evaluator(
|
||||
evaluationContext = EvaluationContext(
|
||||
@@ -254,6 +263,26 @@ internal class ExpressionResolverImpl(
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (other !is ExpressionResolverImpl) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (this.runtimeStore !== other.runtimeStore) {
|
||||
return false
|
||||
}
|
||||
|
||||
return path == other.path
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return 31 * path.hashCode() + runtimeStore.hashCode()
|
||||
}
|
||||
|
||||
/**
|
||||
* ExpressionResolverImpl may create new instance in 'plus' operator.
|
||||
* To be able to registrate all created resolvers and their variables controllers
|
||||
|
||||
+2
-7
@@ -4,17 +4,14 @@ import com.yandex.div.core.DivViewFacade
|
||||
import com.yandex.div.core.expression.local.RuntimeStore
|
||||
import com.yandex.div.core.expression.triggers.TriggersController
|
||||
import com.yandex.div.core.expression.variables.VariableController
|
||||
import com.yandex.div.internal.Assert
|
||||
import com.yandex.div.json.expressions.ExpressionResolver
|
||||
|
||||
internal class ExpressionsRuntime(
|
||||
val expressionResolver: ExpressionResolver,
|
||||
val expressionResolver: ExpressionResolverImpl,
|
||||
val variableController: VariableController,
|
||||
val triggersController: TriggersController? = null,
|
||||
val functionProvider: FunctionProviderDecorator,
|
||||
val runtimeStore: RuntimeStore,
|
||||
) {
|
||||
private val expressionResolverImpl get() = expressionResolver as? ExpressionResolverImpl
|
||||
private var unsubscribed = true
|
||||
|
||||
fun clearBinding() {
|
||||
@@ -28,9 +25,7 @@ internal class ExpressionsRuntime(
|
||||
fun updateSubscriptions() {
|
||||
if (unsubscribed) {
|
||||
unsubscribed = false
|
||||
expressionResolverImpl?.subscribeOnVariables() ?: run {
|
||||
Assert.fail("ExpressionRuntime must have ExpressionResolverImpl as expressionResolver.")
|
||||
}
|
||||
expressionResolver.subscribeOnVariables()
|
||||
variableController.restoreSubscriptions()
|
||||
}
|
||||
}
|
||||
|
||||
+6
-4
@@ -147,10 +147,12 @@ internal class ExpressionsRuntimeProvider @Inject constructor(
|
||||
}
|
||||
|
||||
val expressionResolver = ExpressionResolverImpl(
|
||||
variableController,
|
||||
evaluator,
|
||||
errorCollector,
|
||||
callback,
|
||||
path = "dataTag: '${tag.id}'",
|
||||
runtimeStore = runtimeStore,
|
||||
variableController = variableController,
|
||||
evaluator = evaluator,
|
||||
errorCollector = errorCollector,
|
||||
onCreateCallback = callback,
|
||||
)
|
||||
|
||||
val triggersController = TriggersController(
|
||||
|
||||
+7
-5
@@ -98,7 +98,7 @@ internal class RuntimeStore(
|
||||
|
||||
internal fun resolveRuntimeWith(
|
||||
path: String,
|
||||
div: Div,
|
||||
div: Div?,
|
||||
resolver: ExpressionResolver,
|
||||
parentResolver: ExpressionResolver?,
|
||||
): ExpressionsRuntime? {
|
||||
@@ -157,6 +157,8 @@ internal class RuntimeStore(
|
||||
|
||||
val evaluator = Evaluator(evaluationContext)
|
||||
val resolver = ExpressionResolverImpl(
|
||||
path = path + "/" + (baseRuntime.expressionResolver as? ExpressionResolverImpl)?.path,
|
||||
runtimeStore = this,
|
||||
variableController = localVariableController,
|
||||
evaluator = evaluator,
|
||||
errorCollector = errorCollector,
|
||||
@@ -185,7 +187,7 @@ internal class RuntimeStore(
|
||||
|
||||
private fun getRuntimeOrCreateChild(
|
||||
path: String,
|
||||
div: Div,
|
||||
div: Div?,
|
||||
existingRuntime: ExpressionsRuntime? = null,
|
||||
parentResolver: ExpressionResolver? = null,
|
||||
parentRuntime: ExpressionsRuntime? = null,
|
||||
@@ -201,9 +203,9 @@ internal class RuntimeStore(
|
||||
|
||||
val parentRuntime = parentRuntime ?: parentResolver?.let { getRuntimeWithOrNull(it) }
|
||||
|
||||
val variables = div.value().variables?.toVariables()
|
||||
val variableTriggers = div.value().variableTriggers
|
||||
val functions = div.value().functions
|
||||
val variables = div?.value()?.variables?.toVariables()
|
||||
val variableTriggers = div?.value()?.variableTriggers
|
||||
val functions = div?.value()?.functions
|
||||
|
||||
if (needLocalRuntime(variables, variableTriggers, functions)) {
|
||||
return createChildRuntime(runtime, parentRuntime, path, variables, variableTriggers, functions)
|
||||
|
||||
+15
-1
@@ -3,6 +3,7 @@ package com.yandex.div.internal.core
|
||||
import com.yandex.div.core.annotations.InternalApi
|
||||
import com.yandex.div.core.expression.ExpressionResolverImpl
|
||||
import com.yandex.div.core.expression.variables.ConstantsProvider
|
||||
import com.yandex.div.internal.Assert
|
||||
import com.yandex.div.internal.util.forEach
|
||||
import com.yandex.div.internal.util.mapIndexedNotNull
|
||||
import com.yandex.div.json.expressions.ExpressionResolver
|
||||
@@ -69,7 +70,20 @@ private fun DivCollectionItemBuilder.getItemResolver(
|
||||
dataElementName to validElement,
|
||||
INDEX_VARIABLE_NAME to index.toLong()
|
||||
))
|
||||
return resolverImpl + localDataProvider
|
||||
|
||||
val itemResolver = resolverImpl.withConstants(
|
||||
pathSegment = "${dataElement}:$index", localDataProvider)
|
||||
val runtime = resolverImpl.runtimeStore.resolveRuntimeWith(
|
||||
itemResolver.path,
|
||||
div = null,
|
||||
resolver = itemResolver,
|
||||
parentResolver = resolverImpl,
|
||||
)
|
||||
return runtime?.expressionResolver ?: run {
|
||||
Assert.fail(
|
||||
"Failed to acquire ExpressionResolver from store! This may lead to leaks and errors!")
|
||||
itemResolver
|
||||
}
|
||||
}
|
||||
|
||||
private fun Div.copy(id: String? = value().id): Div {
|
||||
|
||||
+4
@@ -81,6 +81,8 @@ class ExpressionResolverImplTest {
|
||||
)
|
||||
|
||||
private val underTest = ExpressionResolverImpl(
|
||||
"",
|
||||
mock(),
|
||||
externalVariables,
|
||||
Evaluator(evaluationContext),
|
||||
mock()
|
||||
@@ -88,6 +90,8 @@ class ExpressionResolverImplTest {
|
||||
|
||||
private val withFuncGetCallback = { callback: () -> Unit ->
|
||||
ExpressionResolverImpl(
|
||||
"",
|
||||
mock(),
|
||||
VariableControllerImpl(),
|
||||
Evaluator(
|
||||
EvaluationContext(
|
||||
|
||||
+8
-8
@@ -51,14 +51,14 @@ class RuntimeStoreTest {
|
||||
underTest.putRuntime(runtimeFromCallback!!)
|
||||
}
|
||||
|
||||
private val resolver = ExpressionResolverImpl(mock(), evaluator, errorCollector, callback)
|
||||
private val resolver = ExpressionResolverImpl("", mock(), mock(), evaluator, errorCollector, callback)
|
||||
private val rootVariableController: VariableController = mock<VariableController>()
|
||||
private val functionProvider = mock<FunctionProviderDecorator>()
|
||||
private val divBase = mock<DivBase>()
|
||||
private val div = mock<Div> {
|
||||
on { value() } doReturn divBase
|
||||
}
|
||||
private val rootResolver = ExpressionResolverImpl(rootVariableController, evaluator, errorCollector, callback)
|
||||
private val rootResolver = ExpressionResolverImpl("", mock(), rootVariableController, evaluator, errorCollector, callback)
|
||||
private val rootRuntime: ExpressionsRuntime =
|
||||
ExpressionsRuntime(rootResolver, rootVariableController, null, functionProvider, underTest)
|
||||
|
||||
@@ -74,7 +74,7 @@ class RuntimeStoreTest {
|
||||
|
||||
@Test
|
||||
fun `setPathToRuntimeWith links path to created runtime`() {
|
||||
val newResolver = ExpressionResolverImpl(mock(), evaluator, errorCollector, callback)
|
||||
val newResolver = ExpressionResolverImpl("", mock(), mock(), evaluator, errorCollector, callback)
|
||||
underTest.resolveRuntimeWith(path.fullPath, div, newResolver, newResolver)
|
||||
|
||||
Assert.assertNotNull(underTest.getRuntimeWithOrNull(newResolver))
|
||||
@@ -99,7 +99,7 @@ class RuntimeStoreTest {
|
||||
|
||||
@Test
|
||||
fun `getOrCreateRuntime returns runtime for path if exist`() {
|
||||
val resolver = ExpressionResolverImpl(mock(), evaluator, errorCollector, callback)
|
||||
val resolver = ExpressionResolverImpl("", mock(), mock(), evaluator, errorCollector, callback)
|
||||
val runtime = ExpressionsRuntime(resolver, mock(), null, functionProvider, underTest)
|
||||
underTest.putRuntime(runtime, PATH, rootRuntime)
|
||||
|
||||
@@ -110,7 +110,7 @@ class RuntimeStoreTest {
|
||||
|
||||
@Test
|
||||
fun `getOrCreateRuntime returns parent runtime for path if no variables provided`() {
|
||||
val resolver = ExpressionResolverImpl(mock(), evaluator, errorCollector, callback)
|
||||
val resolver = ExpressionResolverImpl("", mock(), mock(), evaluator, errorCollector, callback)
|
||||
val parentVariableController = mock<VariableController>()
|
||||
val runtime = ExpressionsRuntime(resolver, parentVariableController, null, functionProvider, underTest)
|
||||
underTest.putRuntime(runtime, PARENT_PATH, rootRuntime)
|
||||
@@ -121,7 +121,7 @@ class RuntimeStoreTest {
|
||||
|
||||
@Test
|
||||
fun `getOrCreateRuntime returns wrapped parent runtime with new variables if new variables provided`() {
|
||||
val resolver = ExpressionResolverImpl(mock(), evaluator, errorCollector, callback)
|
||||
val resolver = ExpressionResolverImpl("", mock(), mock(), evaluator, errorCollector, callback)
|
||||
val parentVariableController = mock<VariableController> {
|
||||
on { getMutableVariable(PARENT_VARIABLE) } doReturn Variable.StringVariable(PARENT_VARIABLE, "123")
|
||||
}
|
||||
@@ -153,7 +153,7 @@ class RuntimeStoreTest {
|
||||
|
||||
@Test
|
||||
fun `setPathToRuntimeWith links path to runtime`() {
|
||||
val resolver = ExpressionResolverImpl(mock(), evaluator, errorCollector, callback)
|
||||
val resolver = ExpressionResolverImpl("", mock(), mock(), evaluator, errorCollector, callback)
|
||||
underTest.resolveRuntimeWith(path.fullPath, div, resolver, resolver)
|
||||
|
||||
Assert.assertNotNull(runtimeFromCallback)
|
||||
@@ -174,7 +174,7 @@ class RuntimeStoreTest {
|
||||
on { getMutableVariable(PARENT_VARIABLE) } doReturn Variable.StringVariable(PARENT_VARIABLE, "123")
|
||||
}
|
||||
val resolver = ExpressionResolverImpl(
|
||||
parentVariableController, evaluator, errorCollector, callback
|
||||
"", mock(), parentVariableController, evaluator, errorCollector, callback
|
||||
)
|
||||
|
||||
underTest.resolveRuntimeWith(path.fullPath, div, resolver, resolver)
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ class TwoWayVariableBinderTest {
|
||||
private val evaluator = mock<Evaluator> {
|
||||
on { evaluationContext } doReturn evaluationContext
|
||||
}
|
||||
private val expressionResolver = ExpressionResolverImpl(mock(), evaluator, mock(), mock())
|
||||
private val expressionResolver = ExpressionResolverImpl("", mock(), mock(), evaluator, mock(), mock())
|
||||
private val expressionsRuntime = ExpressionsRuntime(expressionResolver, variableController, mock(), mock(), store)
|
||||
private val expressionsRuntimeProvider = mock<ExpressionsRuntimeProvider> {
|
||||
on { getOrCreate(any(), any(), any()) } doReturn expressionsRuntime
|
||||
|
||||
Reference in New Issue
Block a user