diff --git a/Sources/Concordium/Domain/Contract.swift b/Sources/Concordium/Domain/Contract.swift index 4765535..10cdc7e 100644 --- a/Sources/Concordium/Domain/Contract.swift +++ b/Sources/Concordium/Domain/Contract.swift @@ -851,6 +851,11 @@ public extension ContractSerialize { contractSerialize(into: &buf) return Data(buffer: buf) } + + /// Static version of ``self.serialize(into: inout ByteBuffer) + static func contractSerialize(_ value: Self, _ buffer: inout ByteBuffer) -> Int { + value.contractSerialize(into: &buffer) + } } public extension Array where Element: ContractSerialize { @@ -860,12 +865,7 @@ public extension Array where Element: ContractSerialize { /// - elements: The serializable elements to write /// - _: the integer size used to describe the number of elements serialized. func contractSerialize(into buffer: inout NIOCore.ByteBuffer, prefixLength _: P.Type) -> Int { - var res = 0 - res += buffer.writeInteger(P(count), endianness: .little) - for item in self { - res += item.contractSerialize(into: &buffer) - } - return res + buffer.writeSerializable(list: self, prefixLength: P.self, prefixEndianness: .little, with: Element.contractSerialize) } /// Serializes the list with the number of elements prefixed @@ -902,14 +902,61 @@ extension Array where Element: ContractDeserialize { /// - data: The data to deserialize /// - _: the integer size used to describe the number of elements serialized. static func contractDeserialize(_ data: inout Cursor, prefixLength _: P.Type) -> [Element]? { - guard let length = data.parseUInt(P.self, endianness: .little) else { return nil } + data.contractDeserialize(listOf: Element.self, prefixLength: P.self) + } +} - var list: [Element] = [] - for _ in 0 ..< Int(length) { - guard let s = Element.contractDeserialize(&data) else { return nil } - list.append(s) - } - return list +public extension Cursor { + /// Deserialize a deserializable type from the inner data. + mutating func contractDeserialize(_ _: T) -> T? { + deserialize(with: T.contractDeserialize) + } + + /// Deserialize a list of deserializable types. This will completely exhaust the data in the cursor. + mutating func contractDeserialize(listOf _: T.Type) -> [T]? { + deserialize(listOf: T.self, with: T.contractDeserialize) + } + + /// Deserialize a list of deserializable types, prefixed with an associated length from the inner data. + mutating func contractDeserialize(listOf _: T.Type, prefixLength _: UInt.Type) -> [T]? { + deserialize(listOf: T.self, prefixLength: UInt.self, prefixEndianness: .little, with: T.contractDeserialize) + } + + /// Deserialize a list of deserializable types, prefixed with an associated length from the inner data. + mutating func contractDeserialize(mapOf _: V.Type, keys _: K.Type) -> [K: V]? { + deserialize(mapOf: V.self, keys: K.self, deserializeKey: K.contractDeserialize, deserializeValue: V.contractDeserialize) + } + + /// Deserialize a list of deserializable types, prefixed with an associated length from the inner data. + mutating func contractDeserialize(mapOf _: V.Type, keys _: K.Type, prefixLength _: UInt.Type) -> [K: V]? { + deserialize(mapOf: V.self, keys: K.self, prefixLength: UInt.self, prefixEndianness: .little, deserializeKey: K.contractDeserialize, deserializeValue: V.contractDeserialize) + } +} + +extension ByteBuffer { + /// Writes a ``ContractSerialize`` type into the buffer, returning the number of bytes written. + @discardableResult mutating func writeContractSerializable(_ value: T) -> Int { + writeSerializable(value, with: T.contractSerialize) + } + + /// Writes a list of ``ContractSerialize`` type into the buffer, returning the number of bytes written. + @discardableResult mutating func writeContractSerializable(list: [T]) -> Int { + writeSerializable(list: list, with: T.contractSerialize) + } + + /// Writes a map of ``ContractSerialize`` type into the buffer, returning the number of bytes written. + @discardableResult mutating func writeContractSerializable(map: [K: V]) -> Int { + writeSerializable(map: map, serializeKey: K.contractSerialize, serializeValue: V.contractSerialize) + } + + /// Writes a list of ``ContractSerialize`` type into the buffer, returning the number of bytes written. + @discardableResult mutating func writeContractSerializable(list: [T], prefixLength _: P.Type) -> Int { + writeSerializable(list: list, prefixLength: P.self, prefixEndianness: .little, with: T.contractSerialize) + } + + /// Writes a map of ``ContractSerialize`` type into the buffer, returning the number of bytes written. + @discardableResult mutating func writeContractSerializable(map: [K: V], prefixLength _: P.Type) -> Int { + writeSerializable(map: map, prefixLength: P.self, prefixEndianness: .little, serializeKey: K.contractSerialize, serializeValue: V.contractSerialize) } } diff --git a/Sources/Concordium/Serial.swift b/Sources/Concordium/Serial.swift index 4db1673..16e1754 100644 --- a/Sources/Concordium/Serial.swift +++ b/Sources/Concordium/Serial.swift @@ -14,6 +14,11 @@ public extension Serialize { serialize(into: &buf) return Data(buffer: buf) } + + /// Static version of ``self.serialize(into: inout ByteBuffer) + static func serialize(_ value: Self, _ buffer: inout ByteBuffer) -> Int { + value.serialize(into: &buffer) + } } /// A wrapper around ``Data`` useful for deserializing the inner data in a sequence of steps. @@ -67,49 +72,49 @@ public struct Cursor { } /// Deserialize a deserializable type from the inner data. - public mutating func deserialize(_ _: T) -> T? { - T.deserialize(&self) + public mutating func deserialize(with deserializer: (_: inout Cursor) -> T?) -> T? { + deserializer(&self) } /// Deserialize a list of deserializable types. This will completely exhaust the data in the cursor. - public mutating func deserialize(listOf _: T.Type) -> [T]? { + public mutating func deserialize(listOf _: T.Type, with deserializer: (_: inout Cursor) -> T?) -> [T]? { var list: [T] = [] while !empty { - guard let s = T.deserialize(&self) else { return nil } + guard let s = deserializer(&self) else { return nil } list.append(s) } return list } /// Deserialize a list of deserializable types, prefixed with an associated length from the inner data. - public mutating func deserialize(listOf _: T.Type, prefixLength _: UInt.Type, prefixEndianness: Endianness = .big) -> [T]? { + public mutating func deserialize(listOf _: T.Type, prefixLength _: UInt.Type, prefixEndianness: Endianness = .big, with deserializer: (_: inout Cursor) -> T?) -> [T]? { guard let length = parseUInt(UInt.self, endianness: prefixEndianness) else { return nil } var list: [T] = [] for _ in 0 ..< Int(length) { - guard let s = T.deserialize(&self) else { return nil } + guard let s = deserializer(&self) else { return nil } list.append(s) } return list } /// Deserialize a list of deserializable types, prefixed with an associated length from the inner data. - public mutating func deserialize(mapOf _: V.Type, keys _: K.Type) -> [K: V]? { + public mutating func deserialize(mapOf _: V.Type, keys _: K.Type, deserializeKey: (_: inout Cursor) -> K?, deserializeValue: (_: inout Cursor) -> V?) -> [K: V]? { var map: [K: V] = [:] while !empty { - guard let k = K.deserialize(&self), let v = V.deserialize(&self) else { return nil } + guard let k = deserializeKey(&self), let v = deserializeValue(&self) else { return nil } map[k] = v } return map } /// Deserialize a list of deserializable types, prefixed with an associated length from the inner data. - public mutating func deserialize(mapOf _: V.Type, keys _: K.Type, prefixLength _: UInt.Type, prefixEndianness: Endianness = .big) -> [K: V]? { + public mutating func deserialize(mapOf _: V.Type, keys _: K.Type, prefixLength _: UInt.Type, prefixEndianness: Endianness = .big, deserializeKey: (_: inout Cursor) -> K?, deserializeValue: (_: inout Cursor) -> V?) -> [K: V]? { guard let length = parseUInt(UInt.self, endianness: prefixEndianness) else { return nil } var map: [K: V] = [:] for _ in 0 ..< Int(length) { - guard let k = K.deserialize(&self), let v = V.deserialize(&self) else { return nil } + guard let k = deserializeKey(&self), let v = deserializeValue(&self) else { return nil } map[k] = v } return map @@ -124,6 +129,33 @@ public struct Cursor { public var empty: Bool { data.count == 0 } } +public extension Cursor { + /// Deserialize a deserializable type from the inner data. + mutating func deserialize(_ _: T) -> T? { + deserialize(with: T.deserialize) + } + + /// Deserialize a list of deserializable types. This will completely exhaust the data in the cursor. + mutating func deserialize(listOf _: T.Type) -> [T]? { + deserialize(listOf: T.self, with: T.deserialize) + } + + /// Deserialize a list of deserializable types, prefixed with an associated length from the inner data. + mutating func deserialize(listOf _: T.Type, prefixLength _: UInt.Type, prefixEndianness: Endianness = .big) -> [T]? { + deserialize(listOf: T.self, prefixLength: UInt.self, prefixEndianness: prefixEndianness, with: T.deserialize) + } + + /// Deserialize a list of deserializable types, prefixed with an associated length from the inner data. + mutating func deserialize(mapOf _: V.Type, keys _: K.Type) -> [K: V]? { + deserialize(mapOf: V.self, keys: K.self, deserializeKey: K.deserialize, deserializeValue: V.deserialize) + } + + /// Deserialize a list of deserializable types, prefixed with an associated length from the inner data. + mutating func deserialize(mapOf _: V.Type, keys _: K.Type, prefixLength _: UInt.Type, prefixEndianness: Endianness = .big) -> [K: V]? { + deserialize(mapOf: V.self, keys: K.self, prefixLength: UInt.self, prefixEndianness: prefixEndianness, deserializeKey: K.deserialize, deserializeValue: V.deserialize) + } +} + /// Used to represent an error happening when deserializing from byte format. public struct DeserializeError: Error { /// The type attempted to deserialize @@ -195,43 +227,43 @@ extension UInt64: Serialize, Deserialize { } extension ByteBuffer { - /// Writes a ``Serializable`` type into the buffer, returning the number of bytes written. - @discardableResult mutating func writeSerializable(_ value: T) -> Int { - value.serialize(into: &self) + /// Writes some type into the buffer, returning the number of bytes written. + @discardableResult mutating func writeSerializable(_ value: T, with serializer: (_: T, _: inout ByteBuffer) -> Int) -> Int { + serializer(value, &self) } - /// Writes a list of ``Serializable`` type into the buffer, returning the number of bytes written. - @discardableResult mutating func writeSerializable(list: [T]) -> Int { + /// Writes a list of some type into the buffer, returning the number of bytes written. + @discardableResult mutating func writeSerializable(list: [T], with serializer: (_: T, _: inout ByteBuffer) -> Int) -> Int { var res = 0 for item in list { - res += writeSerializable(item) + res += writeSerializable(item, with: serializer) } return res } - /// Writes a map of ``Serializable`` type into the buffer, returning the number of bytes written. - @discardableResult mutating func writeSerializable(map: [K: V]) -> Int { + /// Writes a map of some type into the buffer, returning the number of bytes written. + @discardableResult mutating func writeSerializable(map: [K: V], serializeKey: (_: K, _: inout ByteBuffer) -> Int, serializeValue: (_: V, _: inout ByteBuffer) -> Int) -> Int { var res = 0 for (key, value) in map { - res += writeSerializable(key) - res += writeSerializable(value) + res += writeSerializable(key, with: serializeKey) + res += writeSerializable(value, with: serializeValue) } return res } - /// Writes a list of ``Serializable`` type into the buffer, returning the number of bytes written. - @discardableResult mutating func writeSerializable(list: [T], prefixLength _: P.Type, prefixEndianness: Endianness = .big) -> Int { + /// Writes a list of some type into the buffer, returning the number of bytes written. + @discardableResult mutating func writeSerializable(list: [T], prefixLength _: P.Type, prefixEndianness: Endianness = .big, with serializer: (_: T, _: inout ByteBuffer) -> Int) -> Int { var res = 0 res += writeInteger(P(list.count), endianness: prefixEndianness) - res += writeSerializable(list: list) + res += writeSerializable(list: list, with: serializer) return res } - /// Writes a map of ``Serializable`` type into the buffer, returning the number of bytes written. - @discardableResult mutating func writeSerializable(map: [K: V], prefixLength _: P.Type, prefixEndianness: Endianness = .big) -> Int { + /// Writes a map of some type into the buffer, returning the number of bytes written. + @discardableResult mutating func writeSerializable(map: [K: V], prefixLength _: P.Type, prefixEndianness: Endianness = .big, serializeKey: (_: K, _: inout ByteBuffer) -> Int, serializeValue: (_: V, _: inout ByteBuffer) -> Int) -> Int { var res = 0 res += writeInteger(P(map.count), endianness: prefixEndianness) - res += writeSerializable(map: map) + res += writeSerializable(map: map, serializeKey: serializeKey, serializeValue: serializeValue) return res } @@ -257,6 +289,33 @@ extension ByteBuffer { } } +extension ByteBuffer { + /// Writes a ``Serialize`` type into the buffer, returning the number of bytes written. + @discardableResult mutating func writeSerializable(_ value: T) -> Int { + writeSerializable(value, with: T.serialize) + } + + /// Writes a list of ``Serialize`` type into the buffer, returning the number of bytes written. + @discardableResult mutating func writeSerializable(list: [T]) -> Int { + writeSerializable(list: list, with: T.serialize) + } + + /// Writes a map of ``Serializa`` type into the buffer, returning the number of bytes written. + @discardableResult mutating func writeSerializable(map: [K: V]) -> Int { + writeSerializable(map: map, serializeKey: K.serialize, serializeValue: V.serialize) + } + + /// Writes a list of ``Serialize`` type into the buffer, returning the number of bytes written. + @discardableResult mutating func writeSerializable(list: [T], prefixLength _: P.Type, prefixEndianness: Endianness = .big) -> Int { + writeSerializable(list: list, prefixLength: P.self, prefixEndianness: prefixEndianness, with: T.serialize) + } + + /// Writes a map of ``Serialize`` type into the buffer, returning the number of bytes written. + @discardableResult mutating func writeSerializable(map: [K: V], prefixLength _: P.Type, prefixEndianness: Endianness = .big) -> Int { + writeSerializable(map: map, prefixLength: P.self, prefixEndianness: prefixEndianness, serializeKey: K.serialize, serializeValue: V.serialize) + } +} + public extension Array where Element: Serialize { /// Serialize list elements func serialize() -> Data { @@ -267,7 +326,7 @@ public extension Array where Element: Serialize { /// Serialize list elements into the buffer func serialize(into buffer: inout NIOCore.ByteBuffer) -> Int { - buffer.writeSerializable(list: self) + buffer.writeSerializable(list: self, with: Element.serialize) } /// Serializes the list with the number of elements prefixed into the buffer @@ -276,7 +335,7 @@ public extension Array where Element: Serialize { /// - elements: The serializable elements to write /// - _: the integer size used to describe the number of elements serialized. func serialize(into buffer: inout NIOCore.ByteBuffer, prefixLength _: P.Type) -> Int { - buffer.writeSerializable(list: self, prefixLength: P.self) + buffer.writeSerializable(list: self, prefixLength: P.self, with: Element.serialize) } /// Serializes the list with the number of elements prefixed @@ -304,7 +363,7 @@ public extension Array where Element: Deserialize { /// - Parameter data: the data to deserialize /// - Returns the list or nil if not enough data was available to deserialize the a list of ``Element``s static func deserialize(_ data: inout Cursor) -> [Element]? { - data.deserialize(listOf: Element.self) + data.deserialize(listOf: Element.self, with: Element.deserialize) } /// Deserialize data into a list of ``Element``s @@ -312,7 +371,7 @@ public extension Array where Element: Deserialize { /// - data: The data to deserialize /// - _: the integer size used to describe the number of elements serialized. static func deserialize(_ data: inout Cursor, prefixLength _: P.Type) -> [Element]? { - data.deserialize(listOf: Element.self, prefixLength: P.self) + data.deserialize(listOf: Element.self, prefixLength: P.self, with: Element.deserialize) } /// Deserialize data into a list of ``Element``s @@ -336,7 +395,7 @@ public extension Dictionary where Key: Serialize, Value: Serialize { /// Serialize dictionary into the supplied buffer func serialize(into buffer: inout NIOCore.ByteBuffer) -> Int { - buffer.writeSerializable(map: self) + buffer.writeSerializable(map: self, serializeKey: Key.serialize, serializeValue: Value.serialize) } /// Serializes the dictionary with the number of pairs prefixed into the buffer @@ -345,7 +404,7 @@ public extension Dictionary where Key: Serialize, Value: Serialize { /// - elements: The serializable elements to write /// - _: the integer size used to describe the number of pairs serialized. func serialize(into buffer: inout NIOCore.ByteBuffer, prefixLength _: P.Type) -> Int { - buffer.writeSerializable(map: self, prefixLength: P.self) + buffer.writeSerializable(map: self, prefixLength: P.self, serializeKey: Key.serialize, serializeValue: Value.serialize) } /// Serializes the dictionary with the number of pairs prefixed @@ -373,7 +432,7 @@ public extension Dictionary where Key: Deserialize, Value: Deserialize { /// - Parameter data: the data to deserialize /// - Returns the list or nil if not enough data was available to deserialize the a list of ``Element``s static func deserialize(_ data: inout Cursor) -> [Key: Value]? { - data.deserialize(mapOf: Value.self, keys: Key.self) + data.deserialize(mapOf: Value.self, keys: Key.self, deserializeKey: Key.deserialize, deserializeValue: Value.deserialize) } /// Deserialize data into a ``[Key:Value]`` @@ -381,7 +440,7 @@ public extension Dictionary where Key: Deserialize, Value: Deserialize { /// - data: The data to deserialize /// - _: the integer size used to describe the number of pairs serialized. static func deserialize(_ data: inout Cursor, prefixLength _: P.Type) -> [Key: Value]? { - data.deserialize(mapOf: Value.self, keys: Key.self, prefixLength: P.self) + data.deserialize(mapOf: Value.self, keys: Key.self, prefixLength: P.self, deserializeKey: Key.deserialize, deserializeValue: Value.deserialize) } /// Deserialize data into a ``[Key:Value]``