Skip to content

Instantly share code, notes, and snippets.

@anton-povarov
Created May 12, 2015 18:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anton-povarov/c485ded98b51cb6605a0 to your computer and use it in GitHub Desktop.
Save anton-povarov/c485ded98b51cb6605a0 to your computer and use it in GitHub Desktop.
gogo/protobuf pull #48 fix
diff --git a/plugin/unmarshal/unmarshal.go b/plugin/unmarshal/unmarshal.go
index ef232d0..ffafc65 100644
--- a/plugin/unmarshal/unmarshal.go
+++ b/plugin/unmarshal/unmarshal.go
@@ -685,24 +685,21 @@ func (p *unmarshal) Generate(file *generator.FileDescriptor) {
}
p.atleastOne = true
- // Count the required fields
- var rfList []string
+ // build a map required field_id -> bitmask offset
+ rfMap := make(map[int32]uint)
+ rfNextId := uint(0)
for _, field := range message.Field {
if field.IsRequired() {
- rfList = append(rfList, field.GetName())
+ rfMap[field.GetNumber()] = rfNextId
+ rfNextId++
}
}
+ rfCount := len(rfMap)
p.P(`func (m *`, ccTypeName, `) Unmarshal(data []byte) error {`)
p.In()
- if len(rfList) > 0 {
- p.P(`requiredFieldsPresent := map[string]bool{`)
- p.In()
- for _, fieldName := range rfList {
- p.P(`"`, fieldName, `": false,`)
- }
- p.Out()
- p.P(`}`)
+ if rfCount > 0 {
+ p.P(`var hasFields [`, strconv.Itoa(1+(rfCount-1)/64), `]uint64`)
}
p.P(`l := len(data)`)
p.P(`index := 0`)
@@ -759,7 +756,11 @@ func (p *unmarshal) Generate(file *generator.FileDescriptor) {
}
if field.IsRequired() {
- p.P(`requiredFieldsPresent["`, field.GetName(), `"] = true`)
+ fieldBit, ok := rfMap[field.GetNumber()]
+ if !ok {
+ panic("field is required, but no bit registered")
+ }
+ p.P(`hasFields[`, strconv.Itoa(int(fieldBit/64)), `] |= uint64(`, fmt.Sprintf("0x%08x", 1<<(fieldBit%64)), `)`)
}
}
p.Out()
@@ -848,14 +849,20 @@ func (p *unmarshal) Generate(file *generator.FileDescriptor) {
p.P(`}`)
p.Out()
p.P(`}`)
- if len(rfList) > 0 {
- p.P(`for fieldName, present := range requiredFieldsPresent {`)
- p.In()
- p.P(`if !present {`)
+
+ for _, field := range message.Field {
+ if !field.IsRequired() {
+ continue
+ }
+
+ fieldBit, ok := rfMap[field.GetNumber()]
+ if !ok {
+ panic("field is required, but no bit registered")
+ }
+
+ p.P(`if hasFields[`, strconv.Itoa(int(fieldBit/64)), `] & uint64(`, fmt.Sprintf("0x%08x", 1<<(fieldBit%64)), `) == 0 {`)
p.In()
- p.P(`return `, protoPkg.Use(), `.NewRequiredNotSetError(fieldName)`)
- p.Out()
- p.P(`}`)
+ p.P(`return `, protoPkg.Use(), `.NewRequiredNotSetError("`, field.GetName(), `")`)
p.Out()
p.P(`}`)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment