import Foundation final class PeerChatInterfaceStateTable: Table { static func tableSpec(_ id: Int32) -> ValueBoxTable { return ValueBoxTable(id: id, keyType: .int64, compactValuesOnCreation: false) } private var states: [PeerId: PeerChatInterfaceState?] = [:] private var peerIdsWithUpdatedStates = Set() private let sharedKey = ValueBoxKey(length: 8) private func key(_ peerId: PeerId, sharedKey: ValueBoxKey = ValueBoxKey(length: 8)) -> ValueBoxKey { sharedKey.setInt64(0, value: peerId.toInt64()) return sharedKey } func get(_ peerId: PeerId) -> PeerChatInterfaceState? { if let cachedValue = self.states[peerId] { return cachedValue } else if let value = self.valueBox.get(self.table, key: self.key(peerId, sharedKey: self.sharedKey)), let state = PostboxDecoder(buffer: value).decodeRootObject() as? PeerChatInterfaceState { self.states[peerId] = state return state } else { self.states[peerId] = nil return nil } } func set(_ peerId: PeerId, state: PeerChatInterfaceState?) -> (updated: Bool, updatedEmbeddedState: Bool) { let currentState = self.get(peerId) var updated = false var updatedEmbeddedState = false if let currentState = currentState, let state = state { if !currentState.isEqual(to: state) { updated = true if let currentEmbeddedState = currentState.chatListEmbeddedState, let embeddedState = state.chatListEmbeddedState { if !currentEmbeddedState.isEqual(to: embeddedState) { updatedEmbeddedState = true } } else if (currentState.chatListEmbeddedState != nil) != (state.chatListEmbeddedState != nil) { updatedEmbeddedState = true } } } else if (currentState != nil) != (state != nil) { updated = true updatedEmbeddedState = true } if updated { self.states[peerId] = state self.peerIdsWithUpdatedStates.insert(peerId) } return (updated, updatedEmbeddedState) } override func clearMemoryCache() { self.states.removeAll() self.peerIdsWithUpdatedStates.removeAll() } override func beforeCommit() { if !self.peerIdsWithUpdatedStates.isEmpty { let sharedEncoder = PostboxEncoder() for peerId in self.peerIdsWithUpdatedStates { if let state = self.states[peerId] { if let state = state { sharedEncoder.reset() sharedEncoder.encodeRootObject(state) self.valueBox.set(self.table, key: self.key(peerId, sharedKey: self.sharedKey), value: sharedEncoder.readBufferNoCopy()) } else { self.valueBox.remove(self.table, key: self.key(peerId, sharedKey: self.sharedKey), secure: false) } } } self.peerIdsWithUpdatedStates.removeAll() } } }