Skip to content

Conversation

@stefanadranca
Copy link
Collaborator

Motivation:

In the generated code we are specifying types for a serializer and deserializer. As we want to support SwiftProtobuf, we need to implement the generic serializer and deserializer for Protobuf messages, which will be the default if the user doesn't specify other IDL serializer and deserializer.

Modifications:

Created the serializer and deserializer structs conforming to GRPCCore.MessageSerializer and GRPCCOre.MessageDeserializer respectively and implemented their serialize() and deserialize() functions. Added tests for them.

Result:

The generated code can reference protobuf serializer and deserializer types, as they will be supported in GRPC.

Motivation:

In the generated code we are specifying types for a serializer and deserializer. As we want to support SwiftProtobuf, we need to implement the generic serializer and deserializer for Protobuf messages, which will be the default if the user doesn't specify other IDL serializer and deserializer.

Modifications:

Created the serializer and deserializer structs conforming to `GRPCCore.MessageSerializer` and `GRPCCOre.MessageDeserializer` respectively and implemented their serialize and deserialize functions. Added tests for them.

Result:

The generated code can reference protobuf serializer and deserializer types, as they will be supported in GRPC.
Comment on lines 51 to 53
let data = Data(serializedMessageBytes)
let message = try Message(serializedData: data)
return message
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can use the contiguous bytes init for Message and skip Data entirely: let message = try Message(contiguousBytes: serializedMessageBytes)

Package.swift Outdated
dependencies: [
.grpcCore,
.grpcProtobuf,
.echoModel
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need this dependency

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But we do need a .protobuf dependency

import SwiftProtobuf
import XCTest

final class CodingTests: XCTestCase {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: these names are used in test output, use ProtobufCodingTests instead

Comment on lines 78 to 111
struct TestMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase {

var text: String = ""
var unknownFields = SwiftProtobuf.UnknownStorage()
static var protoMessageName: String = "Test" + ".ServiceRequest"
init() {}

mutating func decodeMessage<D>(decoder: inout D) throws where D: SwiftProtobuf.Decoder {
while let fieldNumber = try decoder.nextFieldNumber() {
switch fieldNumber {
case 1: try { try decoder.decodeSingularStringField(value: &self.text) }()
default: break
}
}
}

func traverse<V>(visitor: inout V) throws where V: SwiftProtobuf.Visitor {
if !self.text.isEmpty {
try visitor.visitSingularStringField(value: self.text, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}

public static func == (lhs: TestMessage, rhs: TestMessage) -> Bool {
if lhs.text != rhs.text { return false }
if lhs.unknownFields != rhs.unknownFields { return false }
return true
}

public var isInitialized: Bool {
if self.text.isEmpty { return false }
return true
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to create a message, SwiftProtobuf includes a number of "well known" messages, e.g. https://github.com/apple/swift-protobuf/blob/2540c49bd8b8ab33a4603ce1ae1c33db6e54365b/Sources/SwiftProtobuf/timestamp.pb.swift#L141

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've created it because I needed to override the "isInitialized" var so there is a time when it is false, in order to have a message that can't be serialised. And since I had to implement the struct for one case, I thought I can use it for all of them.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right I see, in that case can we take a slightly different approach by using an existing message type for the round-trip test and then having this test message being the bare minimum implementation of SwiftProtobuf.Message which where decode and traverse only throw an error?

Comment on lines 58 to 59
let invalidData = "%%%%%££££".data(using: .utf8)
let bytes = [UInt8](invalidData!)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can just do let bytes = Array("%%%%%££££".utf8)

* limitations under the License.
*/

import EchoModel
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need this import

}
}

public init() {}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Normal style is for the init() to come before other methods (usually it's: properties, init, methods)

} catch let error {
throw RPCError(
code: .invalidArgument,
message: "The message could not be serialized.",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, we can bit a bit more specific and add the type of the message:

Suggested change
message: "The message could not be serialized.",
message: "Can't serialize message of type \(type(of: message).",

} catch let error {
throw RPCError(
code: .invalidArgument,
message: "The data could not be deserialized into a Message.",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, we can be a bit more specific: "Can't deserialize to message of type \(Message.self)"

@glbrntt glbrntt added the version/v2 Relates to v2 label Jan 19, 2024
}
}

struct TestMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_MessageImplementationBase is prefixed with an underscore which means it's not part of the public API so you shouldn't be using it

@stefanadranca stefanadranca requested a review from glbrntt January 19, 2024 17:25
Copy link
Collaborator

@glbrntt glbrntt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two tiny nits but looks good otherwise

@glbrntt glbrntt enabled auto-merge (squash) January 22, 2024 10:07
@glbrntt glbrntt merged commit 1e36bdc into grpc:main Jan 22, 2024
glbrntt pushed a commit to glbrntt/grpc-swift that referenced this pull request Feb 5, 2024
…1764)

Motivation:

In the generated code we are specifying types for a serializer and deserializer. As we want to support SwiftProtobuf, we need to implement the generic serializer and deserializer for Protobuf messages, which will be the default if the user doesn't specify other IDL serializer and deserializer.

Modifications:

Created the serializer and deserializer structs conforming to `GRPCCore.MessageSerializer` and `GRPCCOre.MessageDeserializer` respectively and implemented their serialize and deserialize functions. Added tests for them.

Result:

The generated code can reference protobuf serializer and deserializer types, as they will be supported in GRPC.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

version/v2 Relates to v2

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants