Closed
Description
The logic to generate support for oneofs are a significant source of complexity:
- It is complexity to maintain in the generator.
- It is complexity in the generated code.
- It is complexity in the
proto
package as the generated code depends on the following types, functions, variables, and constants:Buffer
,SizeVarint
,ErrInternalBadWireType
,WireBytes
,WireEndGroup
,WireFixed
,WireStartGroup
, andWireVarint
. - It exposes a pseudo-internal method
XXX_OneofFuncs
.
However, this does not need to be the case:
- The
proto
runtime, since switching to the table-driven approach, usesXXX_OneofFuncs
in marshal and unmarshal only to obtain type information about the wrappers.
Since the type information is the only information needed, we can accomplish this in a cleaner way. Instead of adding the method, we add an unexported, zero-length field with all the wrapper types:
type FooMessage struct {
// other fields of FooMessage as usual
xxx_oneofWrappers [0]struct{
Oneof_F_Bool
Oneof_F_Int32
Oneof_F_Int64
Oneof_F_Fixed32
Oneof_F_Fixed64
Oneof_F_Uint32
Oneof_F_Uint64
Oneof_F_Float
Oneof_F_Double
Oneof_F_String
Oneof_F_Bytes
Oneof_F_Sint32
Oneof_F_Sint64
Oneof_F_Enum
Oneof_F_Message
Oneof_FGroup
Oneof_F_Largest_Tag
Oneof_Value
}
}
This has the following properties:
- It removes the need for the exported XXX method (see protoc-gen-go: unexport XXX_ fields from generated types #276). In fact, this approach keeps all of the type information hidden. Using Go reflection, you can obtain a list of all the oneof wrappers types from the type information in the message alone (no need to dynamically call methods).
- It simplifies the implementation of
proto
since we don't have to type assert for a method with a relatively complex signature. unsafe.Sizeof(FooMessage{})
remains unchanged- The generated code is significantly simpler.
\cc @neild
Metadata
Metadata
Assignees
Labels
No labels