semin-alx / SAN_Protobuffer

Protocol buffers library for Delphi
MIT License
2 stars 1 forks source link

oneof fields support #3

Closed randydom closed 1 month ago

randydom commented 1 month ago

Please are oneof fields supported ? :

message SampleMessage {
  oneof test_oneof {
    string foo = 1;
    string bar = 2;
  }
}

If yes please can you tell how to Serialize and Deserialize that in Delphi .

Thank you

semin-alx commented 1 month ago

OneOf is not explicitly supported yet, but this problem is easily circumvented. Your message can be represented as (see https://protobuf.dev/programming-guides/encoding/#oneofs)

message SampleMessage {
  string foo = 1;
  string bar = 2;
}

But with one restriction, you can only set the value for one field. The example below will better explain my point:

procedure SerializeSampleMessage(fooValue, barValue: string);
var
  SampleMessageType: TsanPBMessageType;
  SampleMessageObj: TsanPBMessage;
begin

   SampleMessageType:= TsanPBMessageType.Create(nil, 'SampleMessage');
   SampleMessageType.AddFieldDef(ftoOptional, ftString, nil, 'foo', 1);
   SampleMessageType.AddFieldDef(ftoOptional, ftString, nil, 'bar', 2);

   SampleMessageObj:= SampleMessageType.CreateInstance;

   try

     if (fooValue <> '') and (barValue <> '') then begin
       raise Exception.Create('Error: Only one field can have a value');
     end;

     if fooValue <> '' then begin
       SampleMessageObj.FieldByName('foo').AppendValueAsString(fooValue);
     end;

     if barValue <> '' then begin
       SampleMessageObj.FieldByName('bar').AppendValueAsString(barValue);
     end;

     SampleMessageObj.SaveToFile('test.bin');

   finally
     SampleMessageObj.Free;
     SampleMessageType.Free;
   end;

end;
randydom commented 1 month ago

OneOf is not explicitly supported yet, but this problem is easily circumvented. Your message can be represented as (see protobuf.dev/programming-guides/encoding#oneofs)

message SampleMessage {
  string foo = 1;
  string bar = 2;
}

But with one restriction, you can only set the value for one field. The example below will better explain my point:

procedure SerializeSampleMessage(fooValue, barValue: string);
var
  SampleMessageType: TsanPBMessageType;
  SampleMessageObj: TsanPBMessage;
begin

   SampleMessageType:= TsanPBMessageType.Create(nil, 'SampleMessage');
   SampleMessageType.AddFieldDef(ftoOptional, ftString, nil, 'foo', 1);
   SampleMessageType.AddFieldDef(ftoOptional, ftString, nil, 'bar', 2);

   SampleMessageObj:= SampleMessageType.CreateInstance;

   try

     if (fooValue <> '') and (barValue <> '') then begin
       raise Exception.Create('Error: Only one field can have a value');
     end;

     if fooValue <> '' then begin
       SampleMessageObj.FieldByName('foo').AppendValueAsString(fooValue);
     end;

     if barValue <> '' then begin
       SampleMessageObj.FieldByName('bar').AppendValueAsString(barValue);
     end;

     SampleMessageObj.SaveToFile('test.bin');

   finally
     SampleMessageObj.Free;
     SampleMessageType.Free;
   end;

end;

Meaning : manual handling !!

semin-alx commented 1 month ago

I'm working on it.

randydom commented 1 month ago

I'm working on it.

Many thanks