Skip to content

Commit 768985a

Browse files
authored
Adopt new serializer protocols (#29)
Motivation: The core package made a few changes allowing for transport to define an associated bag-of-bytes types so that they can avoid copying to and from `[UInt8]`. This also came with changes to the serialization protocols. Modifications: - Add a thin adapter type to bridge between gRPC and Protobuf contiguous bytes - Adopt new protocols Result: Builds again
1 parent be41136 commit 768985a

File tree

5 files changed

+85
-16
lines changed

5 files changed

+85
-16
lines changed

Sources/GRPCProtobuf/Coding.swift

+10-5
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@ public struct ProtobufSerializer<Message: SwiftProtobuf.Message>: GRPCCore.Messa
2525
///
2626
/// - Parameter message: The message to serialize.
2727
/// - Returns: An array of serialized bytes representing the message.
28-
public func serialize(_ message: Message) throws -> [UInt8] {
28+
@inlinable
29+
public func serialize<Bytes: GRPCContiguousBytes>(_ message: Message) throws -> Bytes {
2930
do {
30-
return try message.serializedBytes()
31+
let adapter = try message.serializedBytes() as ContiguousBytesAdapter<Bytes>
32+
return adapter.bytes
3133
} catch let error {
3234
throw RPCError(
3335
code: .invalidArgument,
@@ -46,14 +48,17 @@ public struct ProtobufDeserializer<Message: SwiftProtobuf.Message>: GRPCCore.Mes
4648
///
4749
/// - Parameter serializedMessageBytes: The array of bytes to deserialize.
4850
/// - Returns: The deserialized message.
49-
public func deserialize(_ serializedMessageBytes: [UInt8]) throws -> Message {
51+
@inlinable
52+
public func deserialize<Bytes: GRPCContiguousBytes>(
53+
_ serializedMessageBytes: Bytes
54+
) throws -> Message {
5055
do {
51-
let message = try Message(serializedBytes: serializedMessageBytes)
56+
let message = try Message(serializedBytes: ContiguousBytesAdapter(serializedMessageBytes))
5257
return message
5358
} catch let error {
5459
throw RPCError(
5560
code: .invalidArgument,
56-
message: "Can't deserialize to message of type \(Message.self)",
61+
message: "Can't deserialize to message of type \(Message.self).",
5762
cause: error
5863
)
5964
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright 2025, 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+
17+
public import GRPCCore // internal but @usableFromInline
18+
public import SwiftProtobuf // internal but @usableFromInline
19+
20+
/// Brides between `GRPCContiguousBytes` and `SwiftProtobufContiguousBytes` which have the same
21+
/// requirements.
22+
///
23+
/// This is necessary as `SwiftProtobufContiguousBytes` can't be the protocol in the gRPC API (as
24+
/// it'd require a dependency on Protobuf in the core package), and `GRPCContiguousBytes` can't
25+
/// refine `SwiftProtobufContiguousBytes` for the same reason.
26+
@usableFromInline
27+
struct ContiguousBytesAdapter<
28+
Bytes: GRPCContiguousBytes
29+
>: GRPCContiguousBytes, SwiftProtobufContiguousBytes {
30+
@usableFromInline
31+
var bytes: Bytes
32+
33+
@inlinable
34+
init(_ bytes: Bytes) {
35+
self.bytes = bytes
36+
}
37+
38+
@inlinable
39+
init(repeating: UInt8, count: Int) {
40+
self.bytes = Bytes(repeating: repeating, count: count)
41+
}
42+
43+
@inlinable
44+
init(_ sequence: some Sequence<UInt8>) {
45+
self.bytes = Bytes(sequence)
46+
}
47+
48+
@inlinable
49+
var count: Int {
50+
self.bytes.count
51+
}
52+
53+
@inlinable
54+
func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R {
55+
try self.bytes.withUnsafeBytes(body)
56+
}
57+
58+
@inlinable
59+
mutating func withUnsafeMutableBytes<R>(
60+
_ body: (UnsafeMutableRawBufferPointer) throws -> R
61+
) rethrows -> R {
62+
try self.bytes.withUnsafeMutableBytes(body)
63+
}
64+
}

Tests/GRPCProtobufCodeGenTests/ProtobufCodeGeneratorTests.swift

+4-4
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ struct ProtobufCodeGeneratorTests {
405405
406406
// Default implementation of 'registerMethods(with:)'.
407407
extension Test_TestService.StreamingServiceProtocol {
408-
\(access) func registerMethods(with router: inout GRPCCore.RPCRouter) {
408+
\(access) func registerMethods<Transport>(with router: inout GRPCCore.RPCRouter<Transport>) where Transport: GRPCCore.ServerTransport {
409409
router.registerHandler(
410410
forMethod: Test_TestService.Method.Unary.descriptor,
411411
deserializer: GRPCProtobuf.ProtobufDeserializer<Test_TestInput>(),
@@ -666,14 +666,14 @@ struct ProtobufCodeGeneratorTests {
666666
/// > Source IDL Documentation:
667667
/// >
668668
/// > Service docs.
669-
\(access) struct Client: ClientProtocol {
670-
private let client: GRPCCore.GRPCClient
669+
\(access) struct Client<Transport>: ClientProtocol where Transport: GRPCCore.ClientTransport {
670+
private let client: GRPCCore.GRPCClient<Transport>
671671
672672
/// Creates a new client wrapping the provided `GRPCCore.GRPCClient`.
673673
///
674674
/// - Parameters:
675675
/// - client: A `GRPCCore.GRPCClient` providing a communication channel to the service.
676-
\(access) init(wrapping client: GRPCCore.GRPCClient) {
676+
\(access) init(wrapping client: GRPCCore.GRPCClient<Transport>) {
677677
self.client = client
678678
}
679679

Tests/GRPCProtobufTests/Errors/Generated/error-service.grpc.swift

+4-4
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ extension ErrorService {
134134

135135
// Default implementation of 'registerMethods(with:)'.
136136
extension ErrorService.StreamingServiceProtocol {
137-
internal func registerMethods(with router: inout GRPCCore.RPCRouter) {
137+
internal func registerMethods<Transport>(with router: inout GRPCCore.RPCRouter<Transport>) where Transport: GRPCCore.ServerTransport {
138138
router.registerHandler(
139139
forMethod: ErrorService.Method.ThrowError.descriptor,
140140
deserializer: GRPCProtobuf.ProtobufDeserializer<ThrowInput>(),
@@ -212,14 +212,14 @@ extension ErrorService {
212212
/// The ``Client`` provides an implementation of ``ClientProtocol`` which wraps
213213
/// a `GRPCCore.GRPCCClient`. The underlying `GRPCClient` provides the long-lived
214214
/// means of communication with the remote peer.
215-
internal struct Client: ClientProtocol {
216-
private let client: GRPCCore.GRPCClient
215+
internal struct Client<Transport>: ClientProtocol where Transport: GRPCCore.ClientTransport {
216+
private let client: GRPCCore.GRPCClient<Transport>
217217

218218
/// Creates a new client wrapping the provided `GRPCCore.GRPCClient`.
219219
///
220220
/// - Parameters:
221221
/// - client: A `GRPCCore.GRPCClient` providing a communication channel to the service.
222-
internal init(wrapping client: GRPCCore.GRPCClient) {
222+
internal init(wrapping client: GRPCCore.GRPCClient<Transport>) {
223223
self.client = client
224224
}
225225

Tests/GRPCProtobufTests/ProtobufCodingTests.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ final class ProtobufCodingTests: XCTestCase {
2828
let serializer = ProtobufSerializer<Google_Protobuf_Timestamp>()
2929
let deserializer = ProtobufDeserializer<Google_Protobuf_Timestamp>()
3030

31-
let bytes = try serializer.serialize(message)
31+
let bytes = try serializer.serialize(message) as [UInt8]
3232
let roundTrip = try deserializer.deserialize(bytes)
3333
XCTAssertEqual(roundTrip, message)
3434
}
@@ -38,7 +38,7 @@ final class ProtobufCodingTests: XCTestCase {
3838
let serializer = ProtobufSerializer<TestMessage>()
3939

4040
XCTAssertThrowsError(
41-
try serializer.serialize(message)
41+
try serializer.serialize(message) as [UInt8]
4242
) { error in
4343
XCTAssertEqual(
4444
error as? RPCError,
@@ -65,7 +65,7 @@ final class ProtobufCodingTests: XCTestCase {
6565
code: .invalidArgument,
6666
message:
6767
"""
68-
Can't deserialize to message of type TestMessage
68+
Can't deserialize to message of type TestMessage.
6969
"""
7070
)
7171
)

0 commit comments

Comments
 (0)