Skip to content

Instantly share code, notes, and snippets.

@rlmark
Last active December 29, 2018 00:18
Show Gist options
  • Save rlmark/0bf0daf3c11543f4cebdff7a4394d495 to your computer and use it in GitHub Desktop.
Save rlmark/0bf0daf3c11543f4cebdff7a4394d495 to your computer and use it in GitHub Desktop.
ProtobufOneOfsInvestigation

Protobuf One-Ofs

Currently my implementation of code-gen from protobuf One-Ofs allows you to print valid Scala code from a proto file containing One-of (eithers/coproducts), but you cannot create a valid proto file back. Let’s say you have the following proto file

message Person {
 string name = 1;

 oneof avatar {
    string image_url = 2;
    bytes image_data = 3;
 }

}

This means that a person has a name and either an image url or an image data representing their avatar, not both.

If you put this proto file through Skeuomorph code, you should be able to get roughly the same thing printed back. However, what is returned is:

message Person {
  
  string name = 1 [deprecated = false];
  
oneof avatar {
  string image_url = 2;
  bytes image_data = 3;
}
       avatar = 999;
}

first we see the oneOf printed out correctly as the internal type of the field "avatar 999", but then we see the field name and position, which are not actually relevant for OneOf's at all. (999 is a placeholder numeric value because oneOf “fields” don’t have numeric values and I had to fill something in. )

This is because I wrote a natural transformation “Optimization” to re-interpret TOneOfs as Fields (the protobuf library does not create them as fields, instead putting them in a separate class altogether), so that they can be represented as valid Scala code inside their containing case class. The Scala code on the other hand looks generally okay. Though it depends if you wanted to persist the image_url or image_data names somehow. I've decided to render them as just their types.

@message final case class Person(name: String, avatar: Either[String, Array[Byte]])

This problem is similar in nature to the “Nested Fields” problem that the MuF Optimization file addresses, but I haven’t been able to massage my transformation or ADT’s into the right structure to facilitate both printing the proto one-ofs correctly and printing Scala code correctly.

Any thoughts?

Ideas

  • My initial idea for solving this was to represent different types of fields (some with names and positions, and others as just a variable type, A) as a separate ADT. This did not work with the @deriveTraverse annotation and would require changes to the MuF ADT. If we wanted to commit to this option, we might need to hand-code our traverse/functor instances. More exploration is needed to see if this would even work.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment