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

Adopt new serializer protocols #29

Merged
merged 2 commits into from
Jan 17, 2025
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions Sources/GRPCProtobuf/Coding.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ public struct ProtobufSerializer<Message: SwiftProtobuf.Message>: GRPCCore.Messa
///
/// - Parameter message: The message to serialize.
/// - Returns: An array of serialized bytes representing the message.
public func serialize(_ message: Message) throws -> [UInt8] {
@inlinable
public func serialize<Bytes: GRPCContiguousBytes>(_ message: Message) throws -> Bytes {
do {
return try message.serializedBytes()
let adapter = try message.serializedBytes() as ContiguousBytesAdapter<Bytes>
return adapter.bytes
} catch let error {
throw RPCError(
code: .invalidArgument,
Expand All @@ -46,14 +48,17 @@ public struct ProtobufDeserializer<Message: SwiftProtobuf.Message>: GRPCCore.Mes
///
/// - Parameter serializedMessageBytes: The array of bytes to deserialize.
/// - Returns: The deserialized message.
public func deserialize(_ serializedMessageBytes: [UInt8]) throws -> Message {
@inlinable
public func deserialize<Bytes: GRPCContiguousBytes>(
_ serializedMessageBytes: Bytes
) throws -> Message {
do {
let message = try Message(serializedBytes: serializedMessageBytes)
let message = try Message(serializedBytes: ContiguousBytesAdapter(serializedMessageBytes))
return message
} catch let error {
throw RPCError(
code: .invalidArgument,
message: "Can't deserialize to message of type \(Message.self)",
message: "Can't deserialize to message of type \(Message.self).",
cause: error
)
}
Expand Down
64 changes: 64 additions & 0 deletions Sources/GRPCProtobuf/ContiguousBytesAdapter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 2025, gRPC Authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

public import GRPCCore // internal but @usableFromInline
public import SwiftProtobuf // internal but @usableFromInline
gjcairo marked this conversation as resolved.
Show resolved Hide resolved

/// Brides between `GRPCContiguousBytes` and `SwiftProtobufContiguousBytes` which have the same
/// requirements.
///
/// This is necessary as `SwiftProtobufContiguousBytes` can't be the protocol in the gRPC API (as
/// it'd require a dependency on Protobuf in the core package), and `GRPCContiguousBytes` can't
/// refine `SwiftProtobufContiguousBytes` for the same reason.
@usableFromInline
struct ContiguousBytesAdapter<
Bytes: GRPCContiguousBytes
>: GRPCContiguousBytes, SwiftProtobufContiguousBytes {
@usableFromInline
var bytes: Bytes

@inlinable
init(_ bytes: Bytes) {
self.bytes = bytes
}

@inlinable
init(repeating: UInt8, count: Int) {
self.bytes = Bytes(repeating: repeating, count: count)
}

@inlinable
init(_ sequence: some Sequence<UInt8>) {
self.bytes = Bytes(sequence)
}

@inlinable
var count: Int {
self.bytes.count
}

@inlinable
func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R {
try self.bytes.withUnsafeBytes(body)
}

@inlinable
mutating func withUnsafeMutableBytes<R>(
_ body: (UnsafeMutableRawBufferPointer) throws -> R
) rethrows -> R {
try self.bytes.withUnsafeMutableBytes(body)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ struct ProtobufCodeGeneratorTests {

// Default implementation of 'registerMethods(with:)'.
extension Test_TestService.StreamingServiceProtocol {
\(access) func registerMethods(with router: inout GRPCCore.RPCRouter) {
\(access) func registerMethods<Transport>(with router: inout GRPCCore.RPCRouter<Transport>) where Transport: GRPCCore.ServerTransport {
router.registerHandler(
forMethod: Test_TestService.Method.Unary.descriptor,
deserializer: GRPCProtobuf.ProtobufDeserializer<Test_TestInput>(),
Expand Down Expand Up @@ -666,14 +666,14 @@ struct ProtobufCodeGeneratorTests {
/// > Source IDL Documentation:
/// >
/// > Service docs.
\(access) struct Client: ClientProtocol {
private let client: GRPCCore.GRPCClient
\(access) struct Client<Transport>: ClientProtocol where Transport: GRPCCore.ClientTransport {
private let client: GRPCCore.GRPCClient<Transport>

/// Creates a new client wrapping the provided `GRPCCore.GRPCClient`.
///
/// - Parameters:
/// - client: A `GRPCCore.GRPCClient` providing a communication channel to the service.
\(access) init(wrapping client: GRPCCore.GRPCClient) {
\(access) init(wrapping client: GRPCCore.GRPCClient<Transport>) {
self.client = client
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ extension ErrorService {

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

/// Creates a new client wrapping the provided `GRPCCore.GRPCClient`.
///
/// - Parameters:
/// - client: A `GRPCCore.GRPCClient` providing a communication channel to the service.
internal init(wrapping client: GRPCCore.GRPCClient) {
internal init(wrapping client: GRPCCore.GRPCClient<Transport>) {
self.client = client
}

Expand Down
6 changes: 3 additions & 3 deletions Tests/GRPCProtobufTests/ProtobufCodingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ final class ProtobufCodingTests: XCTestCase {
let serializer = ProtobufSerializer<Google_Protobuf_Timestamp>()
let deserializer = ProtobufDeserializer<Google_Protobuf_Timestamp>()

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

XCTAssertThrowsError(
try serializer.serialize(message)
try serializer.serialize(message) as [UInt8]
) { error in
XCTAssertEqual(
error as? RPCError,
Expand All @@ -65,7 +65,7 @@ final class ProtobufCodingTests: XCTestCase {
code: .invalidArgument,
message:
"""
Can't deserialize to message of type TestMessage
Can't deserialize to message of type TestMessage.
"""
)
)
Expand Down
Loading