diff --git a/client/ios/DivKit/Core/PrototypesValueStorage.swift b/client/ios/DivKit/Core/PrototypesValueStorage.swift index 42c0ba612..ca00f5d6e 100644 --- a/client/ios/DivKit/Core/PrototypesValueStorage.swift +++ b/client/ios/DivKit/Core/PrototypesValueStorage.swift @@ -2,14 +2,9 @@ import Foundation final class PrototypesValueStorage { private final class Node { - let value: Character? var children: [Character: Node] = [:] var data: [String: AnyHashable] = [:] var isEndOfWord: Bool = false - - init(value: Character? = nil) { - self.value = value - } } private let root = Node() @@ -21,7 +16,7 @@ final class PrototypesValueStorage { if let child = node.children[char] { node = child } else { - let newNode = Node(value: char) + let newNode = Node() node.children[char] = newNode node = newNode } @@ -51,3 +46,22 @@ final class PrototypesValueStorage { return result } } + +extension PrototypesValueStorage { + func copy() -> PrototypesValueStorage { + let copiedStorage = PrototypesValueStorage() + copyNode(from: root, to: copiedStorage.root) + return copiedStorage + } + + private func copyNode(from sourceNode: Node, to destinationNode: Node) { + destinationNode.data = sourceNode.data + destinationNode.isEndOfWord = sourceNode.isEndOfWord + + for (char, childNode) in sourceNode.children { + let newChildNode = Node() + destinationNode.children[char] = newChildNode + copyNode(from: childNode, to: newChildNode) + } + } +} diff --git a/client/ios/DivKit/DivBlockModelingContext.swift b/client/ios/DivKit/DivBlockModelingContext.swift index 8ed84e4e1..8717b95fe 100644 --- a/client/ios/DivKit/DivBlockModelingContext.swift +++ b/client/ios/DivKit/DivBlockModelingContext.swift @@ -184,8 +184,9 @@ public struct DivBlockModelingContext { variablesStorage: variablesStorage ) functionsProvider = makeFunctionsProvider( + cardId: cardId, + variablesStorage: variablesStorage, variableTracker: variableTracker, - variableValueProvider: variableValueProvider, persistentValuesStorage: persistentValuesStorage ) expressionResolver = makeExpressionResolver( @@ -262,9 +263,12 @@ extension DivBlockModelingContext { let expressionResolver: ExpressionResolver let parentPath = parentPath ?? self.parentPath let errorsStorage = errorsStorage ?? self.errorsStorage - let prototypesStorage = self.prototypesStorage + let prototypesStorage: PrototypesValueStorage if let prototypesData { + prototypesStorage = self.prototypesStorage.copy() prototypesStorage.insert(prefix: prototypesData.0, data: prototypesData.1) + } else { + prototypesStorage = self.prototypesStorage } let variableValueProvider: AnyCalcExpression.ValueProvider let functionsProvider: FunctionsProvider @@ -279,8 +283,9 @@ extension DivBlockModelingContext { prototypesStorage: prototypesStorage ) functionsProvider = makeFunctionsProvider( + cardId: cardId, + variablesStorage: variablesStorage, variableTracker: variableTracker, - variableValueProvider: variableValueProvider, persistentValuesStorage: persistentValuesStorage, prototypesStorage: prototypesStorage ) diff --git a/client/ios/DivKit/Expressions/ValueProvidersFactory.swift b/client/ios/DivKit/Expressions/ValueProvidersFactory.swift index bdaf9dbbf..a59afea5b 100644 --- a/client/ios/DivKit/Expressions/ValueProvidersFactory.swift +++ b/client/ios/DivKit/Expressions/ValueProvidersFactory.swift @@ -15,8 +15,9 @@ func makeVariableValueProvider( } func makeFunctionsProvider( + cardId: DivCardID, + variablesStorage: DivVariablesStorage, variableTracker: @escaping ExpressionResolver.VariableTracker, - variableValueProvider: @escaping AnyCalcExpression.ValueProvider, persistentValuesStorage: DivPersistentValuesStorage, prototypesStorage: PrototypesValueStorage? = nil ) -> FunctionsProvider { @@ -26,7 +27,10 @@ func makeFunctionsProvider( return value } variableTracker([DivVariableName(rawValue: $0)]) - return variableValueProvider($0) + return variablesStorage.getVariableValue( + cardId: cardId, + name: DivVariableName(rawValue: $0) + ) }, persistentValuesStorage: persistentValuesStorage ) diff --git a/client/ios/DivKitTests/Expressions/FunctionProviderTests.swift b/client/ios/DivKitTests/Expressions/FunctionProviderTests.swift index 18f592e19..f911dee69 100644 --- a/client/ios/DivKitTests/Expressions/FunctionProviderTests.swift +++ b/client/ios/DivKitTests/Expressions/FunctionProviderTests.swift @@ -12,16 +12,13 @@ final class FunctionProviderTests: XCTestCase { cardId: cardId, variables: [DivVariableName(rawValue: "variable"): .string("value1")] ) - let variableValueProvider = makeVariableValueProvider( - cardId: cardId, - variablesStorage: variablesStorage - ) let prototypesData: (String, [String: AnyHashable]) = ("it.", ["variable": "value2"]) let prototypesStorage = PrototypesValueStorage() prototypesStorage.insert(prefix: prototypesData.0, data: prototypesData.1) let functionsProvider = makeFunctionsProvider( + cardId: cardId, + variablesStorage: variablesStorage, variableTracker: { self.trackedResult = Array($0.map(\.rawValue)) }, - variableValueProvider: variableValueProvider, persistentValuesStorage: DivPersistentValuesStorage(), prototypesStorage: prototypesStorage ) diff --git a/client/ios/DivKitTests/Expressions/PrototypesValueStorageTests.swift b/client/ios/DivKitTests/Expressions/PrototypesValueStorageTests.swift index e0871142c..9791cbd23 100644 --- a/client/ios/DivKitTests/Expressions/PrototypesValueStorageTests.swift +++ b/client/ios/DivKitTests/Expressions/PrototypesValueStorageTests.swift @@ -33,6 +33,14 @@ final class PrototypesValueStorageTests: XCTestCase { prototypesValueStorage.insert(prefix: "ab", data: dataAB) XCTAssertEqual(prototypesValueStorage.findValue(expression: "abc"), "value2") } + + func test_copyingPrototypesStorage() throws { + let storage = PrototypesValueStorage() + let storageCopy = storage.copy() + storageCopy.insert(prefix: "a.", data: ["b": "c"]) + XCTAssertNil(storage.findValue(expression: "a.b")) + XCTAssertEqual(storageCopy.findValue(expression: "a.b"), "c") + } } let prototypeData: [String: AnyHashable] = [