How can I pass data to a protobuf oneof in tonic?
oneof
I couldn't find any instruction or example in the docs.
Tonic should generate an enum and corresponding type for each oneof variant. You'll have to match on that.
enum
I'm assuming tonic = "0.4.3" and prost = "0.7.0" or higher for this answer. Let's use the following .proto definition as an example:
tonic = "0.4.3"
prost = "0.7.0"
.proto
syntax = "proto3"; package stack_overflow; service StackOverflow { rpc Question (HelpRequest) returns (HelpResponse); } message HelpRequest { oneof foo { FroozleType froozle = 1; FrobnikType frobnik = 2; } } message FroozleType { int32 value = 1; } message FrobnikType {} message HelpResponse { oneof bar { QuxType qux = 1; BazType baz = 2; } } message QuxType { int32 answer = 1; } message BazType { string comment = 1; }
When built, this generates the following types and traits. For the service:
stack_overflow_server::StackOverflow
For the requests:
HelpRequest
help_request::Foo
oneof foo
Froozle
Frobnik
FroozleType
FrobnikType
For the replies:
HelpResponse
help_response::Bar
oneof bar
Qux
Baz
QuxType
BazType
For example, the HelpRequest struct and help_request::Foo enum are defined as such:
#[derive(Clone, PartialEq, ::prost::Message)] pub struct HelpRequest { #[prost(oneof = "help_request::Foo", tags = "1, 2")] pub foo: ::core::option::Option<help_request::Foo>, } /// Nested message and enum types in `HelpRequest`. pub mod help_request { #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum Foo { #[prost(message, tag = "1")] Froozle(super::FroozleType), #[prost(message, tag = "2")] Frobnik(super::FrobnikType), } }
Sticking it all together, an example implementation of the above service could look like this:
use tonic::{Request, Response, Status}; mod grpc { tonic::include_proto!("stack_overflow"); } #[derive(Debug)] pub struct StackOverflowService {} #[tonic::async_trait] impl grpc::stack_overflow_server::StackOverflow for StackOverflowService { async fn question( &self, request: Request<grpc::HelpRequest>, ) -> Result<Response<grpc::HelpResponse>, Status> { let request = request.into_inner(); let bar = match request.foo { Some(grpc::help_request::Foo::Froozle(froozle)) => { Some(grpc::help_response::Bar::Qux(grpc::QuxType { answer: froozle.value + 42, })) } Some(grpc::help_request::Foo::Frobnik(_)) => { Some(grpc::help_response::Bar::Baz(grpc::BazType { comment: "forty-two".into(), })) } None => None, }; let reply = grpc::HelpResponse { bar }; return Ok(Response::new(reply)); } }
Tonic should generate an
enum
and corresponding type for eachoneof
variant. You'll have to match on that.I'm assuming
tonic = "0.4.3"
andprost = "0.7.0"
or higher for this answer. Let's use the following.proto
definition as an example:When built, this generates the following types and traits. For the service:
stack_overflow_server::StackOverflow
: the server traitFor the requests:
HelpRequest
: the struct for the request messagehelp_request::Foo
: an enum for theoneof foo
in the request having anFroozle
and aFrobnik
variantFroozleType
: the struct of theFroozleType
messageFrobnikType
: the struct of theFrobnikType
messageFor the replies:
HelpResponse
: the struct for the response messagehelp_response::Bar
: an enum for theoneof bar
in the response having anQux
and aBaz
variantQuxType
: the struct of theQuxType
messageBazType
: the struct of theBazType
messageFor example, the
HelpRequest
struct andhelp_request::Foo
enum are defined as such:Sticking it all together, an example implementation of the above service could look like this: