2022-10-14 01:21:57 +04:00

400 lines
11 KiB
Swift

import Foundation
public struct PeerId: Hashable, CustomStringConvertible, Comparable, Codable {
enum CodingKeys: String, CodingKey {
case internalValue = "iv"
}
public struct Namespace: Comparable, Hashable, Codable, CustomStringConvertible {
public static var max: Namespace {
return Namespace(rawValue: 0x7)
}
fileprivate var rawValue: UInt32
var predecessor: Namespace {
if self.rawValue != 0 {
return Namespace(rawValue: self.rawValue - 1)
} else {
return self
}
}
var successor: Namespace {
if self.rawValue != Namespace.max.rawValue {
return Namespace(rawValue: self.rawValue + 1)
} else {
return self
}
}
public var description: String {
return "\(self.rawValue)"
}
fileprivate init(rawValue: UInt32) {
precondition((rawValue | 0x7) == 0x7)
self.rawValue = rawValue
}
public static func _internalFromInt32Value(_ value: Int32) -> Namespace {
return Namespace(rawValue: UInt32(bitPattern: value))
}
public func _internalGetInt32Value() -> Int32 {
return Int32(bitPattern: self.rawValue)
}
public static func <(lhs: Namespace, rhs: Namespace) -> Bool {
return lhs.rawValue < rhs.rawValue
}
}
public struct Id: Comparable, Hashable, Codable {
public static var min: Id {
return Id(rawValue: 0)
}
public static var max: Id {
return Id(rawValue: 0x000000007fffffff)
}
fileprivate var rawValue: Int64
var predecessor: Id {
if self.rawValue != 0 {
return Id(rawValue: self.rawValue - 1)
} else {
return self
}
}
var successor: Id {
if self.rawValue != Id.max.rawValue {
return Id(rawValue: self.rawValue + 1)
} else {
return self
}
}
public var description: String {
return "\(self.rawValue)"
}
fileprivate init(rawValue: Int64) {
if rawValue < 0 {
assert(abs(rawValue) == (abs(rawValue) & 0x007fffffffffffff))
} else {
assert(abs(rawValue) == (abs(rawValue) & 0x00ffffffffffffff))
}
self.rawValue = rawValue
}
public static func _internalFromInt64Value(_ value: Int64) -> Id {
return Id(rawValue: value)
}
public func _internalGetInt64Value() -> Int64 {
return self.rawValue
}
public static func <(lhs: Id, rhs: Id) -> Bool {
return lhs.rawValue < rhs.rawValue
}
}
public static var max: PeerId {
return PeerId(namespace: .max, id: .max)
}
public let namespace: Namespace
public let id: Id
var predecessor: PeerId {
let previousId = self.id.predecessor
if previousId != self.id {
return PeerId(namespace: self.namespace, id: previousId)
} else {
let previousNamespace = self.namespace.predecessor
if previousNamespace != self.namespace {
return PeerId(namespace: previousNamespace, id: .max)
} else {
return self
}
}
}
var successor: PeerId {
let nextId = self.id.successor
if nextId != self.id {
return PeerId(namespace: self.namespace, id: nextId)
} else {
let nextNamespace = self.namespace.successor
if nextNamespace != self.namespace {
return PeerId(namespace: nextNamespace, id: .min)
} else {
return self
}
}
}
public init(namespace: Namespace, id: Id) {
self.namespace = namespace
self.id = id
}
public init(_ n: Int64) {
let data = UInt64(bitPattern: n)
// Bits: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// |___________________________|__| |______________________________|
// id high bits (29) ns id low bits (32)
let legacyNamespaceBits = ((data >> 32) & 0xffffffff)
let idLowBits = data & 0xffffffff
if legacyNamespaceBits == 0x7fffffff && idLowBits == 0 {
self.namespace = .max
self.id = Id(rawValue: Int64(bitPattern: UInt64(clamping: idLowBits)))
} else {
// 0x7 == 0b111
let namespaceBits = ((data >> 32) & 0x7)
self.namespace = Namespace(rawValue: UInt32(namespaceBits))
let offsetIdHighBits = (data >> (32 + 3)) & 0xffffffff
let idHighBits = offsetIdHighBits << 32
if idHighBits == 0 && namespaceBits == 3 {
if let uint32Value = UInt32(exactly: idLowBits) {
self.id = Id(rawValue: Int64(Int32(bitPattern: uint32Value)))
} else {
preconditionFailure()
}
} else {
let idAbs: UInt64 = idHighBits | idLowBits
self.id = Id(rawValue: Int64(bitPattern: idAbs))
}
}
assert(self._toInt64() == n)
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let value = try container.decode(Int64.self, forKey: .internalValue)
self.init(value)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.toInt64(), forKey: .internalValue)
}
public func toInt64() -> Int64 {
let result = self._toInt64()
assert(PeerId(result) == self)
return result
}
private func _toInt64() -> Int64 {
let data: UInt64
if self.id.rawValue < 0 {
if let int32Value = Int32(exactly: self.id.rawValue) {
data = UInt64(UInt32(bitPattern: int32Value))
} else {
preconditionFailure()
}
} else {
data = UInt64(bitPattern: self.id.rawValue)
}
let idLowBits = data & 0xffffffff
let idHighBits = (data >> 32) & 0xffffffff
let result: Int64
if self.namespace == .max && self.id.rawValue == 0 {
var data: UInt64 = 0
let namespaceBits: UInt64 = 0x7fffffff
data |= namespaceBits << 32
data |= idLowBits
result = Int64(bitPattern: data)
} else {
var data: UInt64 = 0
assert(self.namespace.rawValue & 0x7 == self.namespace.rawValue)
let offsetIdHighBits = idHighBits << (32 + 3)
data |= UInt64(self.namespace.rawValue & 0x7) << 32
data |= offsetIdHighBits
data |= idLowBits
result = Int64(bitPattern: data)
}
return result
}
public static func encodeArrayToBuffer(_ array: [PeerId], buffer: WriteBuffer) {
var length: Int32 = Int32(array.count)
buffer.write(&length, offset: 0, length: 4)
for id in array {
var value = id.toInt64()
buffer.write(&value, offset: 0, length: 8)
}
}
public static func decodeArrayFromBuffer(_ buffer: ReadBuffer) -> [PeerId] {
var length: Int32 = 0
memcpy(&length, buffer.memory, 4)
buffer.offset += 4
var i = 0
var array: [PeerId] = []
array.reserveCapacity(Int(length))
while i < Int(length) {
var value: Int64 = 0
buffer.read(&value, offset: 0, length: 8)
array.append(PeerId(value))
i += 1
}
return array
}
public var description: String {
get {
return "\(namespace):\(id)"
}
}
/*public init(_ buffer: ReadBuffer) {
var value: Int64 = 0
memcpy(&value, buffer.memory, 8)
buffer.offset += 8
self.init(value)
}*/
public func encodeToBuffer(_ buffer: WriteBuffer) {
var value = self.toInt64()
buffer.write(&value, offset: 0, length: 8);
}
public static func <(lhs: PeerId, rhs: PeerId) -> Bool {
if lhs.namespace != rhs.namespace {
return lhs.namespace < rhs.namespace
}
if lhs.id != rhs.id {
return lhs.id < rhs.id
}
return false
}
}
public protocol Peer: AnyObject, PostboxCoding {
var id: PeerId { get }
var indexName: PeerIndexNameRepresentation { get }
var associatedPeerId: PeerId? { get }
var notificationSettingsPeerId: PeerId? { get }
var associatedMediaIds: [MediaId]? { get }
var timeoutAttribute: UInt32? { get }
func isEqual(_ other: Peer) -> Bool
}
public func arePeersEqual(_ lhs: Peer?, _ rhs: Peer?) -> Bool {
if let lhs = lhs, let rhs = rhs {
return lhs.isEqual(rhs)
} else {
return (lhs != nil) == (rhs != nil)
}
}
public func arePeerArraysEqual(_ lhs: [Peer], _ rhs: [Peer]) -> Bool {
if lhs.count != rhs.count {
return false
}
for i in 0 ..< lhs.count {
if !lhs[i].isEqual(rhs[i]) {
return false
}
}
return true
}
public func arePeerDictionariesEqual(_ lhs: SimpleDictionary<PeerId, Peer>, _ rhs: SimpleDictionary<PeerId, Peer>) -> Bool {
if lhs.count != rhs.count {
return false
}
for (id, lhsPeer) in lhs {
if let rhsPeer = rhs[id] {
if !lhsPeer.isEqual(rhsPeer) {
return false
}
} else {
return false
}
}
return true
}
public func arePeerDictionariesEqual(_ lhs: [PeerId: Peer], _ rhs: [PeerId: Peer]) -> Bool {
if lhs.count != rhs.count {
return false
}
for (id, lhsPeer) in lhs {
if let rhsPeer = rhs[id] {
if !lhsPeer.isEqual(rhsPeer) {
return false
}
} else {
return false
}
}
return true
}
public struct PeerSummaryCounterData: Equatable {
public var tags: PeerSummaryCounterTags
public var usesThreadSummary: Bool
public init(tags: PeerSummaryCounterTags, usesThreadSummary: Bool) {
self.tags = tags
self.usesThreadSummary = usesThreadSummary
}
}
public struct PeerSummaryCounterTags: OptionSet, Sequence, Hashable {
public var rawValue: Int32
public init(rawValue: Int32) {
self.rawValue = rawValue
}
public init() {
self.rawValue = 0
}
public func makeIterator() -> AnyIterator<PeerSummaryCounterTags> {
var index = 0
return AnyIterator { () -> PeerSummaryCounterTags? in
while index < 31 {
let currentTags = self.rawValue >> UInt32(index)
let tag = PeerSummaryCounterTags(rawValue: 1 << UInt32(index))
index += 1
if currentTags == 0 {
break
}
if (currentTags & 1) != 0 {
return tag
}
}
return nil
}
}
}