diff --git a/Sources/SwiftProtobuf/BinaryEncoder.swift b/Sources/SwiftProtobuf/BinaryEncoder.swift index 9fe6e7158..bdf04a0ec 100644 --- a/Sources/SwiftProtobuf/BinaryEncoder.swift +++ b/Sources/SwiftProtobuf/BinaryEncoder.swift @@ -39,12 +39,14 @@ internal struct BinaryEncoder { } } - private mutating func append(contentsOf bufferPointer: UnsafeRawBufferPointer) { + @discardableResult + private mutating func append(contentsOf bufferPointer: UnsafeRawBufferPointer) -> Int { let count = bufferPointer.count if let baseAddress = bufferPointer.baseAddress, count > 0 { memcpy(pointer, baseAddress, count) } pointer = pointer.advanced(by: count) + return count } func distance(pointer: UnsafeMutableRawPointer) -> Int { @@ -125,11 +127,19 @@ internal struct BinaryEncoder { // Write a string field, including the leading index/tag value. mutating func putStringValue(value: String) { - let count = value.utf8.count - putVarInt(value: count) - for b in value.utf8 { - pointer.storeBytes(of: b, as: UInt8.self) - pointer = pointer.advanced(by: 1) + // If the String does not support an internal representation in a form + // of contiguous storage, body is not called and nil is returned. + let isAvailable = value.utf8.withContiguousStorageIfAvailable { (body: UnsafeBufferPointer) -> Int in + putVarInt(value: body.count) + return append(contentsOf: UnsafeRawBufferPointer(body)) + } + if isAvailable == nil { + let count = value.utf8.count + putVarInt(value: count) + for b in value.utf8 { + pointer.storeBytes(of: b, as: UInt8.self) + pointer = pointer.advanced(by: 1) + } } }