c++protocol-buffersgrpc-c++

how to set oneof field in c++ grpc server and read from client


I have come across the oneof field concept while building grpc services definition (C++ server/client). However, in gRPC web page, I couldn't find proper documentation of oneof usage (write and read operation), any lead on this will be really helpful.

Looking at grpc generated code for Services.proto, it's hard to understand which are usable public methods. Although, I could find - set_status() is there for setting StatusCode.status field and but couldn't find similar set_myfoo() or set_mybar() methods.

Service.proto

message Foo {
   required uint32 id = 1;
}

message Bar {
   required uint32 aID = 1;
   required bytes metadata = 3;
   required bytes payload = 4;
}

message ServiceMessageRequest {
    required uint32 status = 1;

    oneof data {
        Foo myfoo = 2;
        Bar mybar = 3;
    }
}

how these oneof fields - ServiceMessageRequest.data.myfoo and ServiceMessageRequest.data.mybar and thier metadata/payload field can be set?


Solution

  • Short Answer :

    1. when using set_allocated_* then memory management should be handled by developer and memory should be dynamically allocated on heap (local variables cause double free and segmentation issues) - check this answer
    2. when using mutable_* then gRPC will take care of memory management. Thus, it's an easier and preferred option. - check this answer

    Detailed Explanation :

    For better understanding, assume a simple string type str is added in ServiceMessageRequest (from original question) : [Now it has both basic and complex types in oneof data]

    message ServiceMessageRequest {
        required uint32 status = 1;
    
        oneof data {
            string str = 2;
            Foo myfoo = 3;
            Bar mybar = 4;
        }
    }
    

    Setting oneof fields can be straight forward (as below), if they are simple types - integer/string etc. protobuff compiler generates the respective setter/getter for it.

    ServiceMessageRequest msg;
    msg.set_status(1);
    msg.set_str("string");   //setting oneof field
    

    However, if oneof fields have sub structures (or some may call "sub-messages"), then they are set slightly differently (as below) :

    ServiceMessageRequest msg;
    msg.set_status(10);
    msg.set_str("oneof string");   //setting oneof field
    
    // there is no need to release myfoo, it will be released by gRPC.    
    Foo* myfoo = msg.mutable_myfoo();   //set oneof as myfoo
    myfoo->set_id(20);                   //set the sub-message params
    

    Do remember :

    if several oneof fields are set in sequence, only the last oneof will be consider as final set value.

    Reference :