Serialization.swift 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /*
  2. * Copyright 2020, gRPC Authors All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. import NIOCore
  17. import NIOFoundationCompat
  18. import SwiftProtobuf
  19. import struct Foundation.Data
  20. public protocol MessageSerializer {
  21. associatedtype Input
  22. /// Serializes `input` into a `ByteBuffer` allocated using the provided `allocator`.
  23. ///
  24. /// - Parameters:
  25. /// - input: The element to serialize.
  26. /// - allocator: A `ByteBufferAllocator`.
  27. @inlinable
  28. func serialize(_ input: Input, allocator: ByteBufferAllocator) throws -> ByteBuffer
  29. }
  30. public protocol MessageDeserializer {
  31. associatedtype Output
  32. /// Deserializes `byteBuffer` to produce a single `Output`.
  33. ///
  34. /// - Parameter byteBuffer: The `ByteBuffer` to deserialize.
  35. @inlinable
  36. func deserialize(byteBuffer: ByteBuffer) throws -> Output
  37. }
  38. // MARK: Protobuf
  39. public struct ProtobufSerializer<Message: SwiftProtobuf.Message>: MessageSerializer {
  40. @inlinable
  41. public init() {}
  42. @inlinable
  43. public func serialize(_ message: Message, allocator: ByteBufferAllocator) throws -> ByteBuffer {
  44. // Serialize the message.
  45. let serialized = try message.serializedData()
  46. // Allocate enough space and an extra 5 leading bytes. This a minor optimisation win: the length
  47. // prefixed message writer can re-use the leading 5 bytes without needing to allocate a new
  48. // buffer and copy over the serialized message.
  49. var buffer = allocator.buffer(capacity: serialized.count + 5)
  50. buffer.writeRepeatingByte(0, count: 5)
  51. buffer.moveReaderIndex(forwardBy: 5)
  52. // Now write the serialized message.
  53. buffer.writeContiguousBytes(serialized)
  54. return buffer
  55. }
  56. }
  57. public struct ProtobufDeserializer<Message: SwiftProtobuf.Message>: MessageDeserializer {
  58. @inlinable
  59. public init() {}
  60. @inlinable
  61. public func deserialize(byteBuffer: ByteBuffer) throws -> Message {
  62. var buffer = byteBuffer
  63. // '!' is okay; we can always read 'readableBytes'.
  64. let data = buffer.readData(length: buffer.readableBytes)!
  65. return try Message(serializedBytes: data)
  66. }
  67. }
  68. // MARK: GRPCPayload
  69. public struct GRPCPayloadSerializer<Message: GRPCPayload>: MessageSerializer {
  70. @inlinable
  71. public init() {}
  72. @inlinable
  73. public func serialize(_ message: Message, allocator: ByteBufferAllocator) throws -> ByteBuffer {
  74. // Reserve 5 leading bytes. This a minor optimisation win: the length prefixed message writer
  75. // can re-use the leading 5 bytes without needing to allocate a new buffer and copy over the
  76. // serialized message.
  77. var buffer = allocator.buffer(repeating: 0, count: 5)
  78. let readerIndex = buffer.readerIndex
  79. let writerIndex = buffer.writerIndex
  80. // Serialize the payload into the buffer.
  81. try message.serialize(into: &buffer)
  82. // Ensure 'serialize(into:)' didn't do anything strange.
  83. assert(buffer.readerIndex == readerIndex, "serialize(into:) must not move the readerIndex")
  84. assert(
  85. buffer.writerIndex >= writerIndex,
  86. "serialize(into:) must not move the writerIndex backwards"
  87. )
  88. assert(
  89. buffer.getBytes(at: readerIndex, length: 5) == Array(repeating: 0, count: 5),
  90. "serialize(into:) must not write over existing written bytes"
  91. )
  92. // 'read' the first 5 bytes so that the buffer's readable bytes are only the bytes of the
  93. // serialized message.
  94. buffer.moveReaderIndex(forwardBy: 5)
  95. return buffer
  96. }
  97. }
  98. public struct GRPCPayloadDeserializer<Message: GRPCPayload>: MessageDeserializer {
  99. @inlinable
  100. public init() {}
  101. @inlinable
  102. public func deserialize(byteBuffer: ByteBuffer) throws -> Message {
  103. var buffer = byteBuffer
  104. return try Message(serializedByteBuffer: &buffer)
  105. }
  106. }
  107. // MARK: - Any Serializer/Deserializer
  108. internal struct AnySerializer<Input>: MessageSerializer {
  109. private let _serialize: (Input, ByteBufferAllocator) throws -> ByteBuffer
  110. init<Serializer: MessageSerializer>(wrapping other: Serializer) where Serializer.Input == Input {
  111. self._serialize = other.serialize(_:allocator:)
  112. }
  113. internal func serialize(_ input: Input, allocator: ByteBufferAllocator) throws -> ByteBuffer {
  114. return try self._serialize(input, allocator)
  115. }
  116. }
  117. internal struct AnyDeserializer<Output>: MessageDeserializer {
  118. private let _deserialize: (ByteBuffer) throws -> Output
  119. init<Deserializer: MessageDeserializer>(
  120. wrapping other: Deserializer
  121. ) where Deserializer.Output == Output {
  122. self._deserialize = other.deserialize(byteBuffer:)
  123. }
  124. internal func deserialize(byteBuffer: ByteBuffer) throws -> Output {
  125. return try self._deserialize(byteBuffer)
  126. }
  127. }