Files
burstein 5f25cac337 Supported functions in div-data
commit_hash:55b88f5c56de621d28103a3e1169ff8cea19aa71
2025-01-28 01:47:02 +03:00

119 lines
3.2 KiB
Swift

import LayoutKit
import VGSL
@_spi(Internal)
public final class DivFunctionsStorage {
private var functions: [CustomFunction.Signature: CustomFunction] = [:]
private var storages: [UIElementPath: DivFunctionsStorage] = [:]
private let reporter: DivReporter
private let lock = AllocatedUnfairLock()
let outerStorage: DivFunctionsStorage?
init(
outerStorage: DivFunctionsStorage? = DivFunctionsStorage(outerStorage: nil),
reporter: DivReporter = DefaultDivReporter()
) {
self.outerStorage = outerStorage
self.reporter = reporter
}
func set(cardId: DivCardID, functions: [DivFunction]) {
reset(cardId: cardId)
setIfNeeded(path: cardId.path, functions: functions)
}
func setIfNeeded(path: UIElementPath, functions: [DivFunction]) {
lock.withLock {
if storages[path] != nil {
return
}
let nearestStorage = getNearestStorage(path)
if functions.isEmpty {
storages[path] = nearestStorage
} else {
let storage = DivFunctionsStorage(outerStorage: nearestStorage)
for function in functions {
let signature = CustomFunction.Signature(
name: function.name,
arguments: function.arguments.map(\.type)
)
if storage.functions[signature] != nil {
reporter.asExpressionErrorTracker(cardId: path.cardId)(
ExpressionError(
makeErrorMessage(
name: function.name,
arguments: function.arguments.map(\.type.rawValue)
)
)
)
} else {
storage.functions[signature] = CustomFunction(
name: function.name,
arguments: function.arguments.compactMap { arg in
CustomFunction.Argument(name: arg.name, type: arg.type)
},
body: function.body,
returnType: function.returnType.systemType
)
}
}
storages[path] = storage
}
}
}
func getStorage(
path: UIElementPath,
contains name: String
) -> DivFunctionsStorage? {
lock.withLock {
var storage: DivFunctionsStorage? = getNearestStorage(path)
while storage != nil {
if storage?.functions.contains(where: { $0.key.name == name }) == true {
return storage
}
storage = storage?.outerStorage
}
return nil
}
}
func getFunctions(with name: String) -> [CustomFunction] {
functions.values.filter { $0.name == name }
}
func reset() {
lock.withLock {
storages.removeAll()
}
}
func reset(cardId: DivCardID) {
lock.withLock {
for path in storages.keys {
if path.cardId == cardId {
storages.removeValue(forKey: path)
}
}
}
}
func getNearestStorage(_ path: UIElementPath) -> DivFunctionsStorage? {
var currentPath: UIElementPath? = path
while let path = currentPath {
if let storage = storages[path] {
return storage
}
currentPath = path.parent
}
return outerStorage
}
}
private func makeErrorMessage(name: String, arguments: [String]) -> String {
"Function \(name)(\(arguments.joined(separator: ", "))) declared multiple times."
}