func TestClone(t *testing.T) { m := proto.Clone(cloneTestMessage).(*pb.MyMessage) if !proto.Equal(m, cloneTestMessage) { t.Errorf("Clone(%v) = %v", cloneTestMessage, m) } // Verify it was a deep copy. *m.Inner.Port++ if proto.Equal(m, cloneTestMessage) { t.Error("Mutating clone changed the original") } // Byte fields and repeated fields should be copied. if &m.Pet[0] == &cloneTestMessage.Pet[0] { t.Error("Pet: repeated field not copied") } if &m.Others[0] == &cloneTestMessage.Others[0] { t.Error("Others: repeated field not copied") } if &m.Others[0].Value[0] == &cloneTestMessage.Others[0].Value[0] { t.Error("Others[0].Value: bytes field not copied") } if &m.RepBytes[0] == &cloneTestMessage.RepBytes[0] { t.Error("RepBytes: repeated field not copied") } if &m.RepBytes[0][0] == &cloneTestMessage.RepBytes[0][0] { t.Error("RepBytes[0]: bytes field not copied") } }
func Generate(req *plugin.CodeGeneratorRequest) *plugin.CodeGeneratorResponse { // Begin by allocating a generator. The request and response structures are stored there // so we can do error handling easily - the response structure contains the field to // report failure. g := generator.New() g.Request = req g.CommandLineParameters(g.Request.GetParameter()) // Create a wrapped version of the Descriptors and EnumDescriptors that // point to the file that defines them. g.WrapTypes() g.SetPackageNames() g.BuildTypeNameMap() g.GenerateAllFiles() if err := goformat(g.Response); err != nil { g.Error(err) } testReq := proto.Clone(req).(*plugin.CodeGeneratorRequest) testResp := GeneratePlugin(testReq, testgen.NewPlugin(), "pb_test.go") for i := 0; i < len(testResp.File); i++ { if strings.Contains(*testResp.File[i].Content, `//These tests are generated by github.com/maditya/protobuf/plugin/testgen`) { g.Response.File = append(g.Response.File, testResp.File[i]) } } return g.Response }
func TestProto3SetDefaults(t *testing.T) { in := &pb.Message{ Terrain: map[string]*pb.Nested{ "meadow": new(pb.Nested), }, Proto2Field: new(tpb.SubDefaults), Proto2Value: map[string]*tpb.SubDefaults{ "badlands": new(tpb.SubDefaults), }, } got := proto.Clone(in).(*pb.Message) proto.SetDefaults(got) // There are no defaults in proto3. Everything should be the zero value, but // we need to remember to set defaults for nested proto2 messages. want := &pb.Message{ Terrain: map[string]*pb.Nested{ "meadow": new(pb.Nested), }, Proto2Field: &tpb.SubDefaults{N: proto.Int64(7)}, Proto2Value: map[string]*tpb.SubDefaults{ "badlands": {N: proto.Int64(7)}, }, } if !proto.Equal(got, want) { t.Errorf("with in = %v\nproto.SetDefaults(in) =>\ngot %v\nwant %v", in, got, want) } }
func TestMerge(t *testing.T) { for _, m := range mergeTests { got := proto.Clone(m.dst) proto.Merge(got, m.src) if !proto.Equal(got, m.want) { t.Errorf("Merge(%v, %v)\n got %v\nwant %v\n", m.dst, m.src, got, m.want) } } }
func (g *Generator) GetMapKeyField(field, keyField *descriptor.FieldDescriptorProto) *descriptor.FieldDescriptorProto { if !gogoproto.IsCastKey(field) { return keyField } keyField = proto.Clone(keyField).(*descriptor.FieldDescriptorProto) if keyField.Options == nil { keyField.Options = &descriptor.FieldOptions{} } keyType := gogoproto.GetCastKey(field) if err := proto.SetExtension(keyField.Options, gogoproto.E_Casttype, &keyType); err != nil { g.Fail(err.Error()) } return keyField }
func TestUnmarshalGolden(t *testing.T) { for _, tt := range goldenMessages { want := tt.m got := proto.Clone(tt.m) got.Reset() if err := proto.UnmarshalText(tt.t, got); err != nil { t.Errorf("failed to unmarshal\n%s\nerror: %v", tt.t, err) } if !anyEqual(got, want) { t.Errorf("message:\n%s\ngot:\n%s\nwant:\n%s", tt.t, got, want) } got.Reset() if err := proto.UnmarshalText(tt.c, got); err != nil { t.Errorf("failed to unmarshal\n%s\nerror: %v", tt.c, err) } if !anyEqual(got, want) { t.Errorf("message:\n%s\ngot:\n%s\nwant:\n%s", tt.c, got, want) } } }
func (g *Generator) GetMapValueField(field, valField *descriptor.FieldDescriptorProto) *descriptor.FieldDescriptorProto { if gogoproto.IsCustomType(field) && gogoproto.IsCastValue(field) { g.Fail("cannot have a customtype and casttype: ", field.String()) } valField = proto.Clone(valField).(*descriptor.FieldDescriptorProto) if valField.Options == nil { valField.Options = &descriptor.FieldOptions{} } stdtime := gogoproto.IsStdTime(field) if stdtime { if err := proto.SetExtension(valField.Options, gogoproto.E_Stdtime, &stdtime); err != nil { g.Fail(err.Error()) } } stddur := gogoproto.IsStdDuration(field) if stddur { if err := proto.SetExtension(valField.Options, gogoproto.E_Stdduration, &stddur); err != nil { g.Fail(err.Error()) } } if valType := gogoproto.GetCastValue(field); len(valType) > 0 { if err := proto.SetExtension(valField.Options, gogoproto.E_Casttype, &valType); err != nil { g.Fail(err.Error()) } } if valType := gogoproto.GetCustomType(field); len(valType) > 0 { if err := proto.SetExtension(valField.Options, gogoproto.E_Customtype, &valType); err != nil { g.Fail(err.Error()) } } nullable := gogoproto.IsNullable(field) if err := proto.SetExtension(valField.Options, gogoproto.E_Nullable, &nullable); err != nil { g.Fail(err.Error()) } return valField }
func (p *plugin) Generate(file *generator.FileDescriptor) { p.atleastOne = false p.PluginImports = generator.NewPluginImports(p.Generator) p.varGen = NewVarGen() proto3 := gogoproto.IsProto3(file.FileDescriptorProto) p.typesPkg = p.NewImport("github.com/maditya/protobuf/types") p.localName = generator.FileName(file) protoPkg := p.NewImport("github.com/maditya/protobuf/proto") if !gogoproto.ImportsGoGoProto(file.FileDescriptorProto) { protoPkg = p.NewImport("github.com/golang/protobuf/proto") } for _, message := range file.Messages() { if !gogoproto.HasPopulate(file.FileDescriptorProto, message.DescriptorProto) { continue } if message.DescriptorProto.GetOptions().GetMapEntry() { continue } p.atleastOne = true ccTypeName := generator.CamelCaseSlice(message.TypeName()) loopLevels := make([]int, len(message.Field)) maxLoopLevel := 0 for i, field := range message.Field { loopLevels[i] = p.loops(field, message) if loopLevels[i] > maxLoopLevel { maxLoopLevel = loopLevels[i] } } ranTotal := 0 for i := range loopLevels { ranTotal += int(math.Pow10(maxLoopLevel - loopLevels[i])) } p.P(`func NewPopulated`, ccTypeName, `(r randy`, p.localName, `, easy bool) *`, ccTypeName, ` {`) p.In() p.P(`this := &`, ccTypeName, `{}`) if gogoproto.IsUnion(message.File(), message.DescriptorProto) && len(message.Field) > 0 { p.P(`fieldNum := r.Intn(`, fmt.Sprintf("%d", ranTotal), `)`) p.P(`switch fieldNum {`) k := 0 for i, field := range message.Field { is := []string{} ran := int(math.Pow10(maxLoopLevel - loopLevels[i])) for j := 0; j < ran; j++ { is = append(is, fmt.Sprintf("%d", j+k)) } k += ran p.P(`case `, strings.Join(is, ","), `:`) p.In() p.GenerateField(file, message, field) p.Out() } p.P(`}`) } else { var maxFieldNumber int32 oneofs := make(map[string]struct{}) for fieldIndex, field := range message.Field { if field.GetNumber() > maxFieldNumber { maxFieldNumber = field.GetNumber() } oneof := field.OneofIndex != nil if !oneof { if field.IsRequired() || (!gogoproto.IsNullable(field) && !field.IsRepeated()) || (proto3 && !field.IsMessage()) { p.GenerateField(file, message, field) } else { if loopLevels[fieldIndex] > 0 { p.P(`if r.Intn(10) == 0 {`) } else { p.P(`if r.Intn(10) != 0 {`) } p.In() p.GenerateField(file, message, field) p.Out() p.P(`}`) } } else { fieldname := p.GetFieldName(message, field) if _, ok := oneofs[fieldname]; ok { continue } else { oneofs[fieldname] = struct{}{} } fieldNumbers := []int32{} for _, f := range message.Field { fname := p.GetFieldName(message, f) if fname == fieldname { fieldNumbers = append(fieldNumbers, f.GetNumber()) } } p.P(`oneofNumber_`, fieldname, ` := `, fmt.Sprintf("%#v", fieldNumbers), `[r.Intn(`, strconv.Itoa(len(fieldNumbers)), `)]`) p.P(`switch oneofNumber_`, fieldname, ` {`) for _, f := range message.Field { fname := p.GetFieldName(message, f) if fname != fieldname { continue } p.P(`case `, strconv.Itoa(int(f.GetNumber())), `:`) p.In() ccTypeName := p.OneOfTypeName(message, f) p.P(`this.`, fname, ` = NewPopulated`, ccTypeName, `(r, easy)`) p.Out() } p.P(`}`) } } if message.DescriptorProto.HasExtension() { p.P(`if !easy && r.Intn(10) != 0 {`) p.In() p.P(`l := r.Intn(5)`) p.P(`for i := 0; i < l; i++ {`) p.In() if len(message.DescriptorProto.GetExtensionRange()) > 1 { p.P(`eIndex := r.Intn(`, strconv.Itoa(len(message.DescriptorProto.GetExtensionRange())), `)`) p.P(`fieldNumber := 0`) p.P(`switch eIndex {`) for i, e := range message.DescriptorProto.GetExtensionRange() { p.P(`case `, strconv.Itoa(i), `:`) p.In() p.P(`fieldNumber = r.Intn(`, strconv.Itoa(int(e.GetEnd()-e.GetStart())), `) + `, strconv.Itoa(int(e.GetStart()))) p.Out() if e.GetEnd() > maxFieldNumber { maxFieldNumber = e.GetEnd() } } p.P(`}`) } else { e := message.DescriptorProto.GetExtensionRange()[0] p.P(`fieldNumber := r.Intn(`, strconv.Itoa(int(e.GetEnd()-e.GetStart())), `) + `, strconv.Itoa(int(e.GetStart()))) if e.GetEnd() > maxFieldNumber { maxFieldNumber = e.GetEnd() } } p.P(`wire := r.Intn(4)`) p.P(`if wire == 3 { wire = 5 }`) p.P(`data := randField`, p.localName, `(nil, r, fieldNumber, wire)`) p.P(protoPkg.Use(), `.SetRawExtension(this, int32(fieldNumber), data)`) p.Out() p.P(`}`) p.Out() p.P(`}`) } if maxFieldNumber < (1 << 10) { p.P(`if !easy && r.Intn(10) != 0 {`) p.In() if gogoproto.HasUnrecognized(file.FileDescriptorProto, message.DescriptorProto) { p.P(`this.XXX_unrecognized = randUnrecognized`, p.localName, `(r, `, strconv.Itoa(int(maxFieldNumber+1)), `)`) } p.Out() p.P(`}`) } } p.P(`return this`) p.Out() p.P(`}`) p.P(``) //Generate NewPopulated functions for oneof fields m := proto.Clone(message.DescriptorProto).(*descriptor.DescriptorProto) for _, f := range m.Field { oneof := f.OneofIndex != nil if !oneof { continue } ccTypeName := p.OneOfTypeName(message, f) p.P(`func NewPopulated`, ccTypeName, `(r randy`, p.localName, `, easy bool) *`, ccTypeName, ` {`) p.In() p.P(`this := &`, ccTypeName, `{}`) vanity.TurnOffNullableForNativeTypesWithoutDefaultsOnly(f) p.GenerateField(file, message, f) p.P(`return this`) p.Out() p.P(`}`) } } if !p.atleastOne { return } p.P(`type randy`, p.localName, ` interface {`) p.In() p.P(`Float32() float32`) p.P(`Float64() float64`) p.P(`Int63() int64`) p.P(`Int31() int32`) p.P(`Uint32() uint32`) p.P(`Intn(n int) int`) p.Out() p.P(`}`) p.P(`func randUTF8Rune`, p.localName, `(r randy`, p.localName, `) rune {`) p.In() p.P(`ru := r.Intn(62)`) p.P(`if ru < 10 {`) p.In() p.P(`return rune(ru+48)`) p.Out() p.P(`} else if ru < 36 {`) p.In() p.P(`return rune(ru+55)`) p.Out() p.P(`}`) p.P(`return rune(ru+61)`) p.Out() p.P(`}`) p.P(`func randString`, p.localName, `(r randy`, p.localName, `) string {`) p.In() p.P(p.varGen.Next(), ` := r.Intn(100)`) p.P(`tmps := make([]rune, `, p.varGen.Current(), `)`) p.P(`for i := 0; i < `, p.varGen.Current(), `; i++ {`) p.In() p.P(`tmps[i] = randUTF8Rune`, p.localName, `(r)`) p.Out() p.P(`}`) p.P(`return string(tmps)`) p.Out() p.P(`}`) p.P(`func randUnrecognized`, p.localName, `(r randy`, p.localName, `, maxFieldNumber int) (data []byte) {`) p.In() p.P(`l := r.Intn(5)`) p.P(`for i := 0; i < l; i++ {`) p.In() p.P(`wire := r.Intn(4)`) p.P(`if wire == 3 { wire = 5 }`) p.P(`fieldNumber := maxFieldNumber + r.Intn(100)`) p.P(`data = randField`, p.localName, `(data, r, fieldNumber, wire)`) p.Out() p.P(`}`) p.P(`return data`) p.Out() p.P(`}`) p.P(`func randField`, p.localName, `(data []byte, r randy`, p.localName, `, fieldNumber int, wire int) []byte {`) p.In() p.P(`key := uint32(fieldNumber)<<3 | uint32(wire)`) p.P(`switch wire {`) p.P(`case 0:`) p.In() p.P(`data = encodeVarintPopulate`, p.localName, `(data, uint64(key))`) p.P(p.varGen.Next(), ` := r.Int63()`) p.P(`if r.Intn(2) == 0 {`) p.In() p.P(p.varGen.Current(), ` *= -1`) p.Out() p.P(`}`) p.P(`data = encodeVarintPopulate`, p.localName, `(data, uint64(`, p.varGen.Current(), `))`) p.Out() p.P(`case 1:`) p.In() p.P(`data = encodeVarintPopulate`, p.localName, `(data, uint64(key))`) p.P(`data = append(data, byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)))`) p.Out() p.P(`case 2:`) p.In() p.P(`data = encodeVarintPopulate`, p.localName, `(data, uint64(key))`) p.P(`ll := r.Intn(100)`) p.P(`data = encodeVarintPopulate`, p.localName, `(data, uint64(ll))`) p.P(`for j := 0; j < ll; j++ {`) p.In() p.P(`data = append(data, byte(r.Intn(256)))`) p.Out() p.P(`}`) p.Out() p.P(`default:`) p.In() p.P(`data = encodeVarintPopulate`, p.localName, `(data, uint64(key))`) p.P(`data = append(data, byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)))`) p.Out() p.P(`}`) p.P(`return data`) p.Out() p.P(`}`) p.P(`func encodeVarintPopulate`, p.localName, `(data []byte, v uint64) []byte {`) p.In() p.P(`for v >= 1<<7 {`) p.In() p.P(`data = append(data, uint8(uint64(v)&0x7f|0x80))`) p.P(`v >>= 7`) p.Out() p.P(`}`) p.P(`data = append(data, uint8(v))`) p.P(`return data`) p.Out() p.P(`}`) }
func (p *size) Generate(file *generator.FileDescriptor) { p.PluginImports = generator.NewPluginImports(p.Generator) p.atleastOne = false p.localName = generator.FileName(file) p.typesPkg = p.NewImport("github.com/maditya/protobuf/types") protoPkg := p.NewImport("github.com/maditya/protobuf/proto") if !gogoproto.ImportsGoGoProto(file.FileDescriptorProto) { protoPkg = p.NewImport("github.com/golang/protobuf/proto") } for _, message := range file.Messages() { sizeName := "" if gogoproto.IsSizer(file.FileDescriptorProto, message.DescriptorProto) { sizeName = "Size" } else if gogoproto.IsProtoSizer(file.FileDescriptorProto, message.DescriptorProto) { sizeName = "ProtoSize" } else { continue } if message.DescriptorProto.GetOptions().GetMapEntry() { continue } p.atleastOne = true ccTypeName := generator.CamelCaseSlice(message.TypeName()) p.P(`func (m *`, ccTypeName, `) `, sizeName, `() (n int) {`) p.In() p.P(`var l int`) p.P(`_ = l`) oneofs := make(map[string]struct{}) for _, field := range message.Field { oneof := field.OneofIndex != nil if !oneof { proto3 := gogoproto.IsProto3(file.FileDescriptorProto) p.generateField(proto3, file, message, field, sizeName) } else { fieldname := p.GetFieldName(message, field) if _, ok := oneofs[fieldname]; ok { continue } else { oneofs[fieldname] = struct{}{} } p.P(`if m.`, fieldname, ` != nil {`) p.In() p.P(`n+=m.`, fieldname, `.`, sizeName, `()`) p.Out() p.P(`}`) } } if message.DescriptorProto.HasExtension() { if gogoproto.HasExtensionsMap(file.FileDescriptorProto, message.DescriptorProto) { p.P(`n += `, protoPkg.Use(), `.SizeOfInternalExtension(m)`) } else { p.P(`if m.XXX_extensions != nil {`) p.In() p.P(`n+=len(m.XXX_extensions)`) p.Out() p.P(`}`) } } if gogoproto.HasUnrecognized(file.FileDescriptorProto, message.DescriptorProto) { p.P(`if m.XXX_unrecognized != nil {`) p.In() p.P(`n+=len(m.XXX_unrecognized)`) p.Out() p.P(`}`) } p.P(`return n`) p.Out() p.P(`}`) p.P() //Generate Size methods for oneof fields m := proto.Clone(message.DescriptorProto).(*descriptor.DescriptorProto) for _, f := range m.Field { oneof := f.OneofIndex != nil if !oneof { continue } ccTypeName := p.OneOfTypeName(message, f) p.P(`func (m *`, ccTypeName, `) `, sizeName, `() (n int) {`) p.In() p.P(`var l int`) p.P(`_ = l`) vanity.TurnOffNullableForNativeTypesWithoutDefaultsOnly(f) p.generateField(false, file, message, f, sizeName) p.P(`return n`) p.Out() p.P(`}`) } } if !p.atleastOne { return } p.sizeVarint() p.sizeZigZag() }
func (p *marshalto) Generate(file *generator.FileDescriptor) { numGen := NewNumGen() p.PluginImports = generator.NewPluginImports(p.Generator) p.atleastOne = false p.localName = generator.FileName(file) p.mathPkg = p.NewImport("math") p.sortKeysPkg = p.NewImport("github.com/maditya/protobuf/sortkeys") p.protoPkg = p.NewImport("github.com/maditya/protobuf/proto") if !gogoproto.ImportsGoGoProto(file.FileDescriptorProto) { p.protoPkg = p.NewImport("github.com/golang/protobuf/proto") } p.unsafePkg = p.NewImport("unsafe") p.errorsPkg = p.NewImport("errors") p.typesPkg = p.NewImport("github.com/maditya/protobuf/types") for _, message := range file.Messages() { if message.DescriptorProto.GetOptions().GetMapEntry() { continue } ccTypeName := generator.CamelCaseSlice(message.TypeName()) if p.unsafe { if !gogoproto.IsUnsafeMarshaler(file.FileDescriptorProto, message.DescriptorProto) { continue } if gogoproto.IsMarshaler(file.FileDescriptorProto, message.DescriptorProto) { panic(fmt.Sprintf("unsafe_marshaler and marshalto enabled for %v", ccTypeName)) } } if !p.unsafe { if !gogoproto.IsMarshaler(file.FileDescriptorProto, message.DescriptorProto) { continue } if gogoproto.IsUnsafeMarshaler(file.FileDescriptorProto, message.DescriptorProto) { panic(fmt.Sprintf("unsafe_marshaler and marshalto enabled for %v", ccTypeName)) } } p.atleastOne = true p.P(`func (m *`, ccTypeName, `) Marshal() (data []byte, err error) {`) p.In() if gogoproto.IsProtoSizer(file.FileDescriptorProto, message.DescriptorProto) { p.P(`size := m.ProtoSize()`) } else { p.P(`size := m.Size()`) } p.P(`data = make([]byte, size)`) p.P(`n, err := m.MarshalTo(data)`) p.P(`if err != nil {`) p.In() p.P(`return nil, err`) p.Out() p.P(`}`) p.P(`return data[:n], nil`) p.Out() p.P(`}`) p.P(``) p.P(`func (m *`, ccTypeName, `) MarshalTo(data []byte) (int, error) {`) p.In() p.P(`var i int`) p.P(`_ = i`) p.P(`var l int`) p.P(`_ = l`) fields := orderFields(message.GetField()) sort.Sort(fields) oneofs := make(map[string]struct{}) for _, field := range message.Field { oneof := field.OneofIndex != nil if !oneof { proto3 := gogoproto.IsProto3(file.FileDescriptorProto) p.generateField(proto3, numGen, file, message, field) } else { fieldname := p.GetFieldName(message, field) if _, ok := oneofs[fieldname]; !ok { oneofs[fieldname] = struct{}{} p.P(`if m.`, fieldname, ` != nil {`) p.In() p.P(`nn`, numGen.Next(), `, err := m.`, fieldname, `.MarshalTo(data[i:])`) p.P(`if err != nil {`) p.In() p.P(`return 0, err`) p.Out() p.P(`}`) p.P(`i+=nn`, numGen.Current()) p.Out() p.P(`}`) } } } if message.DescriptorProto.HasExtension() { if gogoproto.HasExtensionsMap(file.FileDescriptorProto, message.DescriptorProto) { p.P(`n, err := `, p.protoPkg.Use(), `.EncodeInternalExtension(m, data[i:])`) p.P(`if err != nil {`) p.In() p.P(`return 0, err`) p.Out() p.P(`}`) p.P(`i+=n`) } else { p.P(`if m.XXX_extensions != nil {`) p.In() p.P(`i+=copy(data[i:], m.XXX_extensions)`) p.Out() p.P(`}`) } } if gogoproto.HasUnrecognized(file.FileDescriptorProto, message.DescriptorProto) { p.P(`if m.XXX_unrecognized != nil {`) p.In() p.P(`i+=copy(data[i:], m.XXX_unrecognized)`) p.Out() p.P(`}`) } p.P(`return i, nil`) p.Out() p.P(`}`) p.P() //Generate MarshalTo methods for oneof fields m := proto.Clone(message.DescriptorProto).(*descriptor.DescriptorProto) for _, field := range m.Field { oneof := field.OneofIndex != nil if !oneof { continue } ccTypeName := p.OneOfTypeName(message, field) p.P(`func (m *`, ccTypeName, `) MarshalTo(data []byte) (int, error) {`) p.In() p.P(`i := 0`) vanity.TurnOffNullableForNativeTypesWithoutDefaultsOnly(field) p.generateField(false, numGen, file, message, field) p.P(`return i, nil`) p.Out() p.P(`}`) } } if p.atleastOne { p.P(`func encodeFixed64`, p.localName, `(data []byte, offset int, v uint64) int {`) p.In() p.P(`data[offset] = uint8(v)`) p.P(`data[offset+1] = uint8(v >> 8)`) p.P(`data[offset+2] = uint8(v >> 16)`) p.P(`data[offset+3] = uint8(v >> 24)`) p.P(`data[offset+4] = uint8(v >> 32)`) p.P(`data[offset+5] = uint8(v >> 40)`) p.P(`data[offset+6] = uint8(v >> 48)`) p.P(`data[offset+7] = uint8(v >> 56)`) p.P(`return offset+8`) p.Out() p.P(`}`) p.P(`func encodeFixed32`, p.localName, `(data []byte, offset int, v uint32) int {`) p.In() p.P(`data[offset] = uint8(v)`) p.P(`data[offset+1] = uint8(v >> 8)`) p.P(`data[offset+2] = uint8(v >> 16)`) p.P(`data[offset+3] = uint8(v >> 24)`) p.P(`return offset+4`) p.Out() p.P(`}`) p.P(`func encodeVarint`, p.localName, `(data []byte, offset int, v uint64) int {`) p.In() p.P(`for v >= 1<<7 {`) p.In() p.P(`data[offset] = uint8(v&0x7f|0x80)`) p.P(`v >>= 7`) p.P(`offset++`) p.Out() p.P(`}`) p.P(`data[offset] = uint8(v)`) p.P(`return offset+1`) p.Out() p.P(`}`) } }
func (p *plugin) generateMessage(file *generator.FileDescriptor, message *generator.Descriptor) { ccTypeName := generator.CamelCaseSlice(message.TypeName()) p.P(`func (this *`, ccTypeName, `) Compare(that interface{}) int {`) p.In() p.generateMsgNullAndTypeCheck(ccTypeName) oneofs := make(map[string]struct{}) for _, field := range message.Field { oneof := field.OneofIndex != nil if oneof { fieldname := p.GetFieldName(message, field) if _, ok := oneofs[fieldname]; ok { continue } else { oneofs[fieldname] = struct{}{} } p.P(`if that1.`, fieldname, ` == nil {`) p.In() p.P(`if this.`, fieldname, ` != nil {`) p.In() p.P(`return 1`) p.Out() p.P(`}`) p.Out() p.P(`} else if this.`, fieldname, ` == nil {`) p.In() p.P(`return -1`) p.Out() p.P(`} else if c := this.`, fieldname, `.Compare(that1.`, fieldname, `); c != 0 {`) p.In() p.P(`return c`) p.Out() p.P(`}`) } else { p.generateField(file, message, field) } } if message.DescriptorProto.HasExtension() { if gogoproto.HasExtensionsMap(file.FileDescriptorProto, message.DescriptorProto) { p.P(`thismap := `, p.protoPkg.Use(), `.GetUnsafeExtensionsMap(this)`) p.P(`thatmap := `, p.protoPkg.Use(), `.GetUnsafeExtensionsMap(that1)`) p.P(`extkeys := make([]int32, 0, len(thismap)+len(thatmap))`) p.P(`for k, _ := range thismap {`) p.In() p.P(`extkeys = append(extkeys, k)`) p.Out() p.P(`}`) p.P(`for k, _ := range thatmap {`) p.In() p.P(`if _, ok := thismap[k]; !ok {`) p.In() p.P(`extkeys = append(extkeys, k)`) p.Out() p.P(`}`) p.Out() p.P(`}`) p.P(p.sortkeysPkg.Use(), `.Int32s(extkeys)`) p.P(`for _, k := range extkeys {`) p.In() p.P(`if v, ok := thismap[k]; ok {`) p.In() p.P(`if v2, ok := thatmap[k]; ok {`) p.In() p.P(`if c := v.Compare(&v2); c != 0 {`) p.In() p.P(`return c`) p.Out() p.P(`}`) p.Out() p.P(`} else {`) p.In() p.P(`return 1`) p.Out() p.P(`}`) p.Out() p.P(`} else {`) p.In() p.P(`return -1`) p.Out() p.P(`}`) p.Out() p.P(`}`) } else { fieldname := "XXX_extensions" p.P(`if c := `, p.bytesPkg.Use(), `.Compare(this.`, fieldname, `, that1.`, fieldname, `); c != 0 {`) p.In() p.P(`return c`) p.Out() p.P(`}`) } } if gogoproto.HasUnrecognized(file.FileDescriptorProto, message.DescriptorProto) { fieldname := "XXX_unrecognized" p.P(`if c := `, p.bytesPkg.Use(), `.Compare(this.`, fieldname, `, that1.`, fieldname, `); c != 0 {`) p.In() p.P(`return c`) p.Out() p.P(`}`) } p.P(`return 0`) p.Out() p.P(`}`) //Generate Compare methods for oneof fields m := proto.Clone(message.DescriptorProto).(*descriptor.DescriptorProto) for _, field := range m.Field { oneof := field.OneofIndex != nil if !oneof { continue } ccTypeName := p.OneOfTypeName(message, field) p.P(`func (this *`, ccTypeName, `) Compare(that interface{}) int {`) p.In() p.generateMsgNullAndTypeCheck(ccTypeName) vanity.TurnOffNullableForNativeTypesWithoutDefaultsOnly(field) p.generateField(file, message, field) p.P(`return 0`) p.Out() p.P(`}`) } }
func TestCloneNil(t *testing.T) { var m *pb.MyMessage if c := proto.Clone(m); !proto.Equal(m, c) { t.Errorf("Clone(%v) = %v", m, c) } }
func (p *plugin) generateMessage(file *generator.FileDescriptor, message *generator.Descriptor, verbose bool) { ccTypeName := generator.CamelCaseSlice(message.TypeName()) if verbose { p.P(`func (this *`, ccTypeName, `) VerboseEqual(that interface{}) error {`) } else { p.P(`func (this *`, ccTypeName, `) Equal(that interface{}) bool {`) } p.In() p.generateMsgNullAndTypeCheck(ccTypeName, verbose) oneofs := make(map[string]struct{}) for _, field := range message.Field { oneof := field.OneofIndex != nil if oneof { fieldname := p.GetFieldName(message, field) if _, ok := oneofs[fieldname]; ok { continue } else { oneofs[fieldname] = struct{}{} } p.P(`if that1.`, fieldname, ` == nil {`) p.In() p.P(`if this.`, fieldname, ` != nil {`) p.In() if verbose { p.P(`return `, p.fmtPkg.Use(), `.Errorf("this.`, fieldname, ` != nil && that1.`, fieldname, ` == nil")`) } else { p.P(`return false`) } p.Out() p.P(`}`) p.Out() p.P(`} else if this.`, fieldname, ` == nil {`) p.In() if verbose { p.P(`return `, p.fmtPkg.Use(), `.Errorf("this.`, fieldname, ` == nil && that1.`, fieldname, ` != nil")`) } else { p.P(`return false`) } p.Out() if verbose { p.P(`} else if err := this.`, fieldname, `.VerboseEqual(that1.`, fieldname, `); err != nil {`) } else { p.P(`} else if !this.`, fieldname, `.Equal(that1.`, fieldname, `) {`) } p.In() if verbose { p.P(`return err`) } else { p.P(`return false`) } p.Out() p.P(`}`) } else { p.generateField(file, message, field, verbose) } } if message.DescriptorProto.HasExtension() { if gogoproto.HasExtensionsMap(file.FileDescriptorProto, message.DescriptorProto) { fieldname := "XXX_InternalExtensions" p.P(`thismap := `, p.protoPkg.Use(), `.GetUnsafeExtensionsMap(this)`) p.P(`thatmap := `, p.protoPkg.Use(), `.GetUnsafeExtensionsMap(that1)`) p.P(`for k, v := range thismap {`) p.In() p.P(`if v2, ok := thatmap[k]; ok {`) p.In() p.P(`if !v.Equal(&v2) {`) p.In() if verbose { p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, ` this[%v](%v) Not Equal that[%v](%v)", k, thismap[k], k, thatmap[k])`) } else { p.P(`return false`) } p.Out() p.P(`}`) p.Out() p.P(`} else {`) p.In() if verbose { p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, `[%v] Not In that", k)`) } else { p.P(`return false`) } p.Out() p.P(`}`) p.Out() p.P(`}`) p.P(`for k, _ := range thatmap {`) p.In() p.P(`if _, ok := thismap[k]; !ok {`) p.In() if verbose { p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, `[%v] Not In this", k)`) } else { p.P(`return false`) } p.Out() p.P(`}`) p.Out() p.P(`}`) } else { fieldname := "XXX_extensions" p.P(`if !`, p.bytesPkg.Use(), `.Equal(this.`, fieldname, `, that1.`, fieldname, `) {`) p.In() if verbose { p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, ` this(%v) Not Equal that(%v)", this.`, fieldname, `, that1.`, fieldname, `)`) } else { p.P(`return false`) } p.Out() p.P(`}`) } } if gogoproto.HasUnrecognized(file.FileDescriptorProto, message.DescriptorProto) { fieldname := "XXX_unrecognized" p.P(`if !`, p.bytesPkg.Use(), `.Equal(this.`, fieldname, `, that1.`, fieldname, `) {`) p.In() if verbose { p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, ` this(%v) Not Equal that(%v)", this.`, fieldname, `, that1.`, fieldname, `)`) } else { p.P(`return false`) } p.Out() p.P(`}`) } if verbose { p.P(`return nil`) } else { p.P(`return true`) } p.Out() p.P(`}`) //Generate Equal methods for oneof fields m := proto.Clone(message.DescriptorProto).(*descriptor.DescriptorProto) for _, field := range m.Field { oneof := field.OneofIndex != nil if !oneof { continue } ccTypeName := p.OneOfTypeName(message, field) if verbose { p.P(`func (this *`, ccTypeName, `) VerboseEqual(that interface{}) error {`) } else { p.P(`func (this *`, ccTypeName, `) Equal(that interface{}) bool {`) } p.In() p.generateMsgNullAndTypeCheck(ccTypeName, verbose) vanity.TurnOffNullableForNativeTypesWithoutDefaultsOnly(field) p.generateField(file, message, field, verbose) if verbose { p.P(`return nil`) } else { p.P(`return true`) } p.Out() p.P(`}`) } }