Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Swift 5: adopt new Data.withUnsafeBytes API #843

Merged
merged 1 commit into from Apr 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
36 changes: 20 additions & 16 deletions Sources/SwiftProtobuf/AnyMessageStorage.swift
Expand Up @@ -66,22 +66,26 @@ fileprivate func unpack(contentJSON: Data,
}

var value = String()
try contentJSON.withUnsafeBytes { (bytes:UnsafePointer<UInt8>) in
let buffer = UnsafeBufferPointer(start: bytes, count: contentJSON.count)
var scanner = JSONScanner(source: buffer,
messageDepthLimit: options.messageDepthLimit,
ignoreUnknownFields: options.ignoreUnknownFields)
let key = try scanner.nextQuotedString()
if key != "value" {
// The only thing within a WKT should be "value".
throw AnyUnpackError.malformedWellKnownTypeJSON
}
try scanner.skipRequiredColon() // Can't fail
value = try scanner.skip()
if !scanner.complete {
// If that wasn't the end, then there was another key,
// and WKTs should only have the one.
throw AnyUnpackError.malformedWellKnownTypeJSON
try contentJSON.withUnsafeBytes { (body: UnsafeRawBufferPointer) in
if let baseAddress = body.baseAddress, body.count > 0 {
let bytes = baseAddress.assumingMemoryBound(to: UInt8.self)

let buffer = UnsafeBufferPointer(start: bytes, count: body.count)
var scanner = JSONScanner(source: buffer,
messageDepthLimit: options.messageDepthLimit,
ignoreUnknownFields: options.ignoreUnknownFields)
let key = try scanner.nextQuotedString()
if key != "value" {
// The only thing within a WKT should be "value".
throw AnyUnpackError.malformedWellKnownTypeJSON
}
try scanner.skipRequiredColon() // Can't fail
value = try scanner.skip()
if !scanner.complete {
// If that wasn't the end, then there was another key,
// and WKTs should only have the one.
throw AnyUnpackError.malformedWellKnownTypeJSON
}
}
}
return try messageType.init(jsonString: value, options: options)
Expand Down
17 changes: 13 additions & 4 deletions Sources/SwiftProtobuf/BinaryDecoder.swift
Expand Up @@ -876,13 +876,16 @@ internal struct BinaryDecoder: Decoder {
}
let fieldSize = Varint.encodedSize(of: fieldTag.rawValue) + Varint.encodedSize(of: Int64(bodySize)) + bodySize
var field = Data(count: fieldSize)
field.withUnsafeMutableBytes { (pointer: UnsafeMutablePointer<UInt8>) in
field.withUnsafeMutableBytes { (body: UnsafeMutableRawBufferPointer) in
if let baseAddress = body.baseAddress, body.count > 0 {
let pointer = baseAddress.assumingMemoryBound(to: UInt8.self)
var encoder = BinaryEncoder(forWritingInto: pointer)
encoder.startField(tag: fieldTag)
encoder.putVarInt(value: Int64(bodySize))
for v in extras {
encoder.putVarInt(value: Int64(v))
}
}
}
unknownOverride = field
}
Expand Down Expand Up @@ -1204,9 +1207,11 @@ internal struct BinaryDecoder: Decoder {
// If there already was fieldData, decode it.
if let data = fieldData {
var wasDecoded = false
try data.withUnsafeBytes { (pointer: UnsafePointer<UInt8>) in
try data.withUnsafeBytes { (body: UnsafeRawBufferPointer) in
if let baseAddress = body.baseAddress, body.count > 0 {
let pointer = baseAddress.assumingMemoryBound(to: UInt8.self)
var extDecoder = BinaryDecoder(forReadingFrom: pointer,
count: data.count,
count: body.count,
parent: self)
// Prime the decode to be correct.
extDecoder.consumed = false
Expand All @@ -1216,6 +1221,7 @@ internal struct BinaryDecoder: Decoder {
fieldNumber: fieldNumber,
messageExtension: ext)
wasDecoded = extDecoder.consumed
}
}
if !wasDecoded {
return .malformed
Expand Down Expand Up @@ -1245,9 +1251,12 @@ internal struct BinaryDecoder: Decoder {
// Save it as length delimited
let payloadSize = Varint.encodedSize(of: Int64(data.count)) + data.count
var payload = Data(count: payloadSize)
payload.withUnsafeMutableBytes { (pointer: UnsafeMutablePointer<UInt8>) in
payload.withUnsafeMutableBytes { (body: UnsafeMutableRawBufferPointer) in
if let baseAddress = body.baseAddress, body.count > 0 {
let pointer = baseAddress.assumingMemoryBound(to: UInt8.self)
var encoder = BinaryEncoder(forWritingInto: pointer)
encoder.putBytesValue(value: data)
}
}
fieldData = payload
} else {
Expand Down
23 changes: 16 additions & 7 deletions Sources/SwiftProtobuf/BinaryDelimited.swift
Expand Up @@ -55,14 +55,20 @@ public enum BinaryDelimited {
let serialized = try message.serializedData(partial: partial)
let totalSize = Varint.encodedSize(of: UInt64(serialized.count)) + serialized.count
var data = Data(count: totalSize)
data.withUnsafeMutableBytes { (pointer: UnsafeMutablePointer<UInt8>) in
var encoder = BinaryEncoder(forWritingInto: pointer)
encoder.putBytesValue(value: serialized)
data.withUnsafeMutableBytes { (body: UnsafeMutableRawBufferPointer) in
if let baseAddress = body.baseAddress, body.count > 0 {
let pointer = baseAddress.assumingMemoryBound(to: UInt8.self)
var encoder = BinaryEncoder(forWritingInto: pointer)
encoder.putBytesValue(value: serialized)
}
}

var written: Int = 0
data.withUnsafeBytes { (pointer: UnsafePointer<UInt8>) in
written = stream.write(pointer, maxLength: totalSize)
data.withUnsafeBytes { (body: UnsafeRawBufferPointer) in
if let baseAddress = body.baseAddress, body.count > 0 {
let pointer = baseAddress.assumingMemoryBound(to: UInt8.self)
written = stream.write(pointer, maxLength: totalSize)
}
}

if written != totalSize {
Expand Down Expand Up @@ -154,8 +160,11 @@ public enum BinaryDelimited {

var data = Data(count: length)
var bytesRead: Int = 0
data.withUnsafeMutableBytes { (pointer: UnsafeMutablePointer<UInt8>) in
bytesRead = stream.read(pointer, maxLength: length)
data.withUnsafeMutableBytes { (body: UnsafeMutableRawBufferPointer) in
if let baseAddress = body.baseAddress, body.count > 0 {
let pointer = baseAddress.assumingMemoryBound(to: UInt8.self)
bytesRead = stream.read(pointer, maxLength: length)
}
}

if bytesRead != length {
Expand Down
33 changes: 33 additions & 0 deletions Sources/SwiftProtobuf/Data+Extensions.swift
@@ -0,0 +1,33 @@
// Sources/SwiftProtobuf/Data+Extensions.swift - Extension exposing new Data API
//
// Copyright (c) 2014 - 2019 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Extension exposing new Data API to Swift versions < 5.0.
///
// -----------------------------------------------------------------------------

import Foundation

#if !swift(>=5.0)
internal extension Data {
func withUnsafeBytes<T>(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T {
let c = count
return try withUnsafeBytes { (p: UnsafePointer<UInt8>) throws -> T in
try body(UnsafeRawBufferPointer(start: p, count: c))
}
}

mutating func withUnsafeMutableBytes<T>(_ body: (UnsafeMutableRawBufferPointer) throws -> T) rethrows -> T {
let c = count
return try withUnsafeMutableBytes { (p: UnsafeMutablePointer<UInt8>) throws -> T in
try body(UnsafeMutableRawBufferPointer(start: p, count: c))
}
}
}
#endif
22 changes: 13 additions & 9 deletions Sources/SwiftProtobuf/Google_Protobuf_Any+Extensions.swift
Expand Up @@ -66,15 +66,19 @@ extension Google_Protobuf_Any {
self.init()
if !textFormatString.isEmpty {
if let data = textFormatString.data(using: String.Encoding.utf8) {
try data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) in
var textDecoder = try TextFormatDecoder(
messageType: Google_Protobuf_Any.self,
utf8Pointer: bytes,
count: data.count,
extensions: extensions)
try decodeTextFormat(decoder: &textDecoder)
if !textDecoder.complete {
throw TextFormatDecodingError.trailingGarbage
try data.withUnsafeBytes { (body: UnsafeRawBufferPointer) in
if let baseAddress = body.baseAddress, body.count > 0 {
let bytes = baseAddress.assumingMemoryBound(to: UInt8.self)

var textDecoder = try TextFormatDecoder(
messageType: Google_Protobuf_Any.self,
utf8Pointer: bytes,
count: body.count,
extensions: extensions)
try decodeTextFormat(decoder: &textDecoder)
if !textDecoder.complete {
throw TextFormatDecodingError.trailingGarbage
}
}
}
}
Expand Down
8 changes: 6 additions & 2 deletions Sources/SwiftProtobuf/JSONEncoder.swift
Expand Up @@ -333,10 +333,13 @@ internal struct JSONEncoder {
internal mutating func putBytesValue(value: Data) {
data.append(asciiDoubleQuote)
if value.count > 0 {
value.withUnsafeBytes { (p: UnsafePointer<UInt8>) in
value.withUnsafeBytes { (body: UnsafeRawBufferPointer) in
if let baseAddress = body.baseAddress, body.count > 0 {
let p = baseAddress.assumingMemoryBound(to: UInt8.self)

var t: Int = 0
var bytesInGroup: Int = 0
for i in 0..<value.count {
for i in 0..<body.count {
if bytesInGroup == 3 {
data.append(base64Digits[(t >> 18) & 63])
data.append(base64Digits[(t >> 12) & 63])
Expand Down Expand Up @@ -369,6 +372,7 @@ internal struct JSONEncoder {
default:
break
}
}
}
}
data.append(asciiDoubleQuote)
Expand Down
95 changes: 54 additions & 41 deletions Sources/SwiftProtobuf/JSONScanner.swift
Expand Up @@ -190,8 +190,9 @@ private func parseBytes(
// a closing double quote.
index = digitsStart
try value.withUnsafeMutableBytes {
(dataPointer: UnsafeMutablePointer<UInt8>) in
var p = dataPointer
(body: UnsafeMutableRawBufferPointer) in
if let baseAddress = body.baseAddress, body.count > 0 {
tbkka marked this conversation as resolved.
Show resolved Hide resolved
var p = baseAddress.assumingMemoryBound(to: UInt8.self)
var n = 0
var chars = 0 // # chars in current group
var padding = 0 // # padding '=' chars
Expand All @@ -201,7 +202,6 @@ private func parseBytes(
if k < 0 {
switch digit {
case asciiDoubleQuote:
source.formIndex(after: &index)
break digits
case asciiBackslash:
source.formIndex(after: &index)
Expand All @@ -221,7 +221,6 @@ private func parseBytes(
while true {
switch source[index] {
case asciiDoubleQuote:
source.formIndex(after: &index)
break digits
case asciiSpace:
break
Expand Down Expand Up @@ -269,7 +268,9 @@ private func parseBytes(
break
}
throw JSONDecodingError.malformedString
}
}
source.formIndex(after: &index)
return value
}

Expand Down Expand Up @@ -848,15 +849,18 @@ internal struct JSONScanner {
let s = try nextQuotedString()
let raw = s.data(using: String.Encoding.utf8)!
let n = try raw.withUnsafeBytes {
(bytes: UnsafePointer<UInt8>) -> UInt64? in
let buffer = UnsafeBufferPointer(start: bytes, count: raw.count)
var index = buffer.startIndex
let end = buffer.endIndex
if let u = try parseBareUInt64(source: buffer,
index: &index,
end: end) {
if index == end {
return u
(body: UnsafeRawBufferPointer) -> UInt64? in
if let baseAddress = body.baseAddress, body.count > 0 {
let bytes = baseAddress.assumingMemoryBound(to: UInt8.self)
let buffer = UnsafeBufferPointer(start: bytes, count: body.count)
var index = buffer.startIndex
let end = buffer.endIndex
if let u = try parseBareUInt64(source: buffer,
index: &index,
end: end) {
if index == end {
return u
}
}
}
return nil
Expand Down Expand Up @@ -907,15 +911,18 @@ internal struct JSONScanner {
let s = try nextQuotedString()
let raw = s.data(using: String.Encoding.utf8)!
let n = try raw.withUnsafeBytes {
(bytes: UnsafePointer<UInt8>) -> Int64? in
let buffer = UnsafeBufferPointer(start: bytes, count: raw.count)
var index = buffer.startIndex
let end = buffer.endIndex
if let s = try parseBareSInt64(source: buffer,
index: &index,
end: end) {
if index == end {
return s
(body: UnsafeRawBufferPointer) -> Int64? in
if let baseAddress = body.baseAddress, body.count > 0 {
let bytes = baseAddress.assumingMemoryBound(to: UInt8.self)
let buffer = UnsafeBufferPointer(start: bytes, count: body.count)
var index = buffer.startIndex
let end = buffer.endIndex
if let s = try parseBareSInt64(source: buffer,
index: &index,
end: end) {
if index == end {
return s
}
}
}
return nil
Expand Down Expand Up @@ -971,16 +978,19 @@ internal struct JSONScanner {
default:
let raw = s.data(using: String.Encoding.utf8)!
let n = try raw.withUnsafeBytes {
(bytes: UnsafePointer<UInt8>) -> Float? in
let buffer = UnsafeBufferPointer(start: bytes, count: raw.count)
var index = buffer.startIndex
let end = buffer.endIndex
if let d = try parseBareDouble(source: buffer,
index: &index,
end: end) {
let f = Float(d)
if index == end && f.isFinite {
return f
(body: UnsafeRawBufferPointer) -> Float? in
if let baseAddress = body.baseAddress, body.count > 0 {
let bytes = baseAddress.assumingMemoryBound(to: UInt8.self)
let buffer = UnsafeBufferPointer(start: bytes, count: body.count)
var index = buffer.startIndex
let end = buffer.endIndex
if let d = try parseBareDouble(source: buffer,
index: &index,
end: end) {
let f = Float(d)
if index == end && f.isFinite {
return f
}
}
}
return nil
Expand Down Expand Up @@ -1042,15 +1052,18 @@ internal struct JSONScanner {
default:
let raw = s.data(using: String.Encoding.utf8)!
let n = try raw.withUnsafeBytes {
(bytes: UnsafePointer<UInt8>) -> Double? in
let buffer = UnsafeBufferPointer(start: bytes, count: raw.count)
var index = buffer.startIndex
let end = buffer.endIndex
if let d = try parseBareDouble(source: buffer,
index: &index,
end: end) {
if index == end {
return d
(body: UnsafeRawBufferPointer) -> Double? in
if let baseAddress = body.baseAddress, body.count > 0 {
let bytes = baseAddress.assumingMemoryBound(to: UInt8.self)
let buffer = UnsafeBufferPointer(start: bytes, count: body.count)
var index = buffer.startIndex
let end = buffer.endIndex
if let d = try parseBareDouble(source: buffer,
index: &index,
end: end) {
if index == end {
return d
}
}
}
return nil
Expand Down