microsoft / bond

Bond is a cross-platform framework for working with schematized data. It supports cross-language de/serialization and powerful generic mechanisms for efficiently manipulating data. Bond is broadly used at Microsoft in high scale services.
MIT License
2.61k stars 321 forks source link

In C# implementation, how to parse to structs separated by BT_STOP_BASE #1162

Closed dend closed 2 years ago

dend commented 2 years ago

Let's say I have an example, where I have a BT_STRUCT with field ID 0, with data (which in turn comes with field IDs of 0, 1, and 2). I then encounter a BT_STOP_BASE and there is a new struct, also with field ID 0, with its own nested data (set of fields, with IDs of 0, 1, and 2).

Given that the structs themselves are not part of a specific field, and are sequential - what is the way to represent that in a C# class, so that I can deserialize/serialize the data? I am assuming some kind of entity with nested sub-classes, but so far I have been unsuccessful at replicating this.

Tagging @chwarr since he helped with some previous questions related to this (https://github.com/microsoft/bond/issues/74#issuecomment-1023699659).

chwarr commented 2 years ago

BT_STOP_BASE is used to delimit where a base class ends when inheritance is used.

The following Bond

struct Foo
{
    0: string foo_string;
}

struct Bar : Foo
{
    0: string bar_string;
}

gets turned into C# that looks roughly like this:

class Foo
{
    public string foo_string { get; set; }
}

class Bar : Foo
{
    public string bar_string { get; set; }
}

Say you serialize one of these to Compact Binary v1:

var obj = new Bar { foo_string = "foo", bar_string = "bar" };

var output = new OutputBuffer();
var writer = new CompactBinaryWriter<OutputBuffer>(output);
Serialize.To(writer, src);

The Compact Binary payload would be, in pseudo payload:

  1. BT_STRING { id: 0, length: 3 }
  2. foo
  3. BT_STOP_BASE
  4. BT_STRING { id: 0, length: 3 }
  5. bar
  6. BT_STOP

If you added another layer, struct Baz : Bar { 0: string baz_string; }, there would be two BT_STOP_BASE tokens, one after the Foo and one after the Bar:

  1. BT_STRING { id: 0, length: 3 }
  2. foo
  3. BT_STOP_BASE
  4. BT_STRING { id: 0, length: 3 }
  5. bar
  6. BT_STOP_BASE
  7. BT_STRING { id: 0, length: 3 }
  8. baz
  9. BT_STOP
dend commented 2 years ago

@chwarr amazing - this works really well, thank you for a very thorough and concrete explanation!