How can I pass data to a protobuf oneof in tonic?
I couldn't find any instruction or example in the docs.
How can I pass data to a protobuf oneof in tonic?
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.
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:
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: the server traitFor the requests:
HelpRequest: the struct for the request messagehelp_request::Foo: an enum for the oneof foo in the request having an Froozle and a Frobnik variantFroozleType: the struct of the FroozleType messageFrobnikType: the struct of the FrobnikType messageFor the replies:
HelpResponse: the struct for the response messagehelp_response::Bar: an enum for the oneof bar in the response having an Qux and a Baz variantQuxType: the struct of the QuxType messageBazType: the struct of the BazType messageFor 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));
    }
}