Swiftgram/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxUnkeyedEncodingContainer.swift
2021-09-19 13:55:17 +03:00

185 lines
6.1 KiB
Swift

import Foundation
import MurMurHash32
extension _AdaptedPostboxEncoder {
final class UnkeyedContainer {
fileprivate enum Item {
case int32(Int32)
case int64(Int64)
case string(String)
case object(Data)
case data(Data)
}
let codingPath: [CodingKey]
let userInfo: [CodingUserInfoKey: Any]
fileprivate var items: [Item] = []
var count: Int {
return self.items.count
}
init(codingPath: [CodingKey], userInfo: [CodingUserInfoKey : Any]) {
self.codingPath = codingPath
self.userInfo = userInfo
}
func makeData(addHeader: Bool, isDictionary: Bool) -> (Data, ValueType) {
precondition(addHeader)
if self.items.isEmpty {
let buffer = WriteBuffer()
var length: Int32 = Int32(self.items.count)
buffer.write(&length, offset: 0, length: 4)
return (buffer.makeData(), .Int32Array)
} else if self.items.allSatisfy({ if case .int32 = $0 { return true } else { return false } }) {
let buffer = WriteBuffer()
var length: Int32 = Int32(self.items.count)
buffer.write(&length, offset: 0, length: 4)
for case .int32(var value) in self.items {
buffer.write(&value, offset: 0, length: 4)
}
return (buffer.makeData(), .Int32Array)
} else if self.items.allSatisfy({ if case .int64 = $0 { return true } else { return false } }) {
let buffer = WriteBuffer()
var length: Int32 = Int32(self.items.count)
buffer.write(&length, offset: 0, length: 4)
for case .int64(var value) in self.items {
buffer.write(&value, offset: 0, length: 8)
}
return (buffer.makeData(), .Int64Array)
} else if self.items.allSatisfy({ if case .string = $0 { return true } else { return false } }) {
let buffer = WriteBuffer()
var length: Int32 = Int32(self.items.count)
buffer.write(&length, offset: 0, length: 4)
for case .string(let value) in self.items {
let data = value.data(using: .utf8, allowLossyConversion: true) ?? (String("").data(using: .utf8)!)
var valueLength: Int32 = Int32(data.count)
buffer.write(&valueLength, offset: 0, length: 4)
buffer.write(data)
}
return (buffer.makeData(), .StringArray)
} else if self.items.allSatisfy({ if case .object = $0 { return true } else { return false } }) {
let buffer = WriteBuffer()
var length: Int32 = Int32(self.items.count)
if isDictionary {
precondition(length % 2 == 0)
length /= 2
}
buffer.write(&length, offset: 0, length: 4)
for case .object(let data) in self.items {
buffer.write(data)
}
return (buffer.makeData(), isDictionary ? .ObjectDictionary : .ObjectArray)
} else if self.items.allSatisfy({ if case .data = $0 { return true } else { return false } }) {
let buffer = WriteBuffer()
var length: Int32 = Int32(self.items.count)
buffer.write(&length, offset: 0, length: 4)
for case .data(let data) in self.items {
var valueLength: Int32 = Int32(data.count)
buffer.write(&valueLength, offset: 0, length: 4)
buffer.write(data)
}
return (buffer.makeData(), .BytesArray)
} else {
preconditionFailure()
}
}
}
}
extension _AdaptedPostboxEncoder.UnkeyedContainer: UnkeyedEncodingContainer {
func encodeNil() throws {
preconditionFailure()
}
func encode<T>(_ value: T) throws where T : Encodable {
if value is Int32 {
try self.encode(value as! Int32)
} else if value is Int64 {
try self.encode(value as! Int64)
} else if value is String {
try self.encode(value as! String)
} else if value is Data {
try self.encode(value as! Data)
} else if let value = value as? AdaptedPostboxEncoder.RawObjectData {
let buffer = WriteBuffer()
var typeHash: Int32 = value.typeHash
buffer.write(&typeHash, offset: 0, length: 4)
var length: Int32 = Int32(value.data.count)
buffer.write(&length, offset: 0, length: 4)
buffer.write(value.data)
self.items.append(.object(buffer.makeData()))
} else {
let typeHash: Int32 = murMurHashString32("\(type(of: value))")
let innerEncoder = _AdaptedPostboxEncoder(typeHash: typeHash)
try! value.encode(to: innerEncoder)
let (data, _) = innerEncoder.makeData(addHeader: true, isDictionary: false)
let buffer = WriteBuffer()
buffer.write(data)
self.items.append(.object(buffer.makeData()))
}
}
func encode(_ value: Int32) throws {
self.items.append(.int32(value))
}
func encode(_ value: Int64) throws {
self.items.append(.int64(value))
}
func encode(_ value: String) throws {
self.items.append(.string(value))
}
func encode(_ value: Data) throws {
self.items.append(.data(value))
}
func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer<NestedKey> where NestedKey : CodingKey {
preconditionFailure()
}
func nestedUnkeyedContainer() -> UnkeyedEncodingContainer {
preconditionFailure()
}
func superEncoder() -> Encoder {
preconditionFailure()
}
}
extension _AdaptedPostboxEncoder.UnkeyedContainer: AdaptedPostboxEncodingContainer {
func makeData() -> Data {
preconditionFailure()
}
}