Пример #1
0
func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.FileDescriptor, message *generator.Descriptor, field *descriptor.FieldDescriptorProto) {
	fieldname := p.GetOneOfFieldName(message, field)
	nullable := gogoproto.IsNullable(field)
	repeated := field.IsRepeated()
	required := field.IsRequired()

	protoSizer := gogoproto.IsProtoSizer(file.FileDescriptorProto, message.DescriptorProto)
	doNilCheck := gogoproto.NeedsNilCheck(proto3, field)
	if required && nullable {
		p.P(`if m.`, fieldname, `== nil {`)
		p.In()
		if !gogoproto.ImportsGoGoProto(file.FileDescriptorProto) {
			p.P(`return 0, new(`, p.protoPkg.Use(), `.RequiredNotSetError)`)
		} else {
			p.P(`return 0, `, p.protoPkg.Use(), `.NewRequiredNotSetError("`, field.GetName(), `")`)
		}
		p.Out()
		p.P(`} else {`)
	} else if repeated {
		p.P(`if len(m.`, fieldname, `) > 0 {`)
		p.In()
	} else if doNilCheck {
		p.P(`if m.`, fieldname, ` != nil {`)
		p.In()
	}
	packed := field.IsPacked() || (proto3 && field.IsRepeated() && generator.IsScalar(field))
	wireType := field.WireType()
	fieldNumber := field.GetNumber()
	if packed {
		wireType = proto.WireBytes
	}
	switch *field.Type {
	case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
		if !p.unsafe || gogoproto.IsCastType(field) {
			if packed {
				p.encodeKey(fieldNumber, wireType)
				p.callVarint(`len(m.`, fieldname, `) * 8`)
				p.P(`for _, num := range m.`, fieldname, ` {`)
				p.In()
				p.P(`f`, numGen.Next(), ` := `, p.mathPkg.Use(), `.Float64bits(float64(num))`)
				p.encodeFixed64("f" + numGen.Current())
				p.Out()
				p.P(`}`)
			} else if repeated {
				p.P(`for _, num := range m.`, fieldname, ` {`)
				p.In()
				p.encodeKey(fieldNumber, wireType)
				p.P(`f`, numGen.Next(), ` := `, p.mathPkg.Use(), `.Float64bits(float64(num))`)
				p.encodeFixed64("f" + numGen.Current())
				p.Out()
				p.P(`}`)
			} else if proto3 {
				p.P(`if m.`, fieldname, ` != 0 {`)
				p.In()
				p.encodeKey(fieldNumber, wireType)
				p.callFixed64(p.mathPkg.Use(), `.Float64bits(float64(m.`+fieldname, `))`)
				p.Out()
				p.P(`}`)
			} else if !nullable {
				p.encodeKey(fieldNumber, wireType)
				p.callFixed64(p.mathPkg.Use(), `.Float64bits(float64(m.`+fieldname, `))`)
			} else {
				p.encodeKey(fieldNumber, wireType)
				p.callFixed64(p.mathPkg.Use(), `.Float64bits(float64(*m.`+fieldname, `))`)
			}
		} else {
			if packed {
				p.encodeKey(fieldNumber, wireType)
				p.callVarint(`len(m.`, fieldname, `) * 8`)
				p.P(`for _, num := range m.`, fieldname, ` {`)
				p.In()
				p.unsafeFixed64("num", "float64")
				p.Out()
				p.P(`}`)
			} else if repeated {
				p.P(`for _, num := range m.`, fieldname, ` {`)
				p.In()
				p.encodeKey(fieldNumber, wireType)
				p.unsafeFixed64("num", "float64")
				p.Out()
				p.P(`}`)
			} else if proto3 {
				p.P(`if m.`, fieldname, ` != 0 {`)
				p.In()
				p.encodeKey(fieldNumber, wireType)
				p.unsafeFixed64(`m.`+fieldname, "float64")
				p.Out()
				p.P(`}`)
			} else if !nullable {
				p.encodeKey(fieldNumber, wireType)
				p.unsafeFixed64(`m.`+fieldname, "float64")
			} else {
				p.encodeKey(fieldNumber, wireType)
				p.unsafeFixed64(`*m.`+fieldname, `float64`)
			}
		}
	case descriptor.FieldDescriptorProto_TYPE_FLOAT:
		if !p.unsafe || gogoproto.IsCastType(field) {
			if packed {
				p.encodeKey(fieldNumber, wireType)
				p.callVarint(`len(m.`, fieldname, `) * 4`)
				p.P(`for _, num := range m.`, fieldname, ` {`)
				p.In()
				p.P(`f`, numGen.Next(), ` := `, p.mathPkg.Use(), `.Float32bits(float32(num))`)
				p.encodeFixed32("f" + numGen.Current())
				p.Out()
				p.P(`}`)
			} else if repeated {
				p.P(`for _, num := range m.`, fieldname, ` {`)
				p.In()
				p.encodeKey(fieldNumber, wireType)
				p.P(`f`, numGen.Next(), ` := `, p.mathPkg.Use(), `.Float32bits(float32(num))`)
				p.encodeFixed32("f" + numGen.Current())
				p.Out()
				p.P(`}`)
			} else if proto3 {
				p.P(`if m.`, fieldname, ` != 0 {`)
				p.In()
				p.encodeKey(fieldNumber, wireType)
				p.callFixed32(p.mathPkg.Use(), `.Float32bits(float32(m.`+fieldname, `))`)
				p.Out()
				p.P(`}`)
			} else if !nullable {
				p.encodeKey(fieldNumber, wireType)
				p.callFixed32(p.mathPkg.Use(), `.Float32bits(float32(m.`+fieldname, `))`)
			} else {
				p.encodeKey(fieldNumber, wireType)
				p.callFixed32(p.mathPkg.Use(), `.Float32bits(float32(*m.`+fieldname, `))`)
			}
		} else {
			if packed {
				p.encodeKey(fieldNumber, wireType)
				p.callVarint(`len(m.`, fieldname, `) * 4`)
				p.P(`for _, num := range m.`, fieldname, ` {`)
				p.In()
				p.unsafeFixed32("num", "float32")
				p.Out()
				p.P(`}`)
			} else if repeated {
				p.P(`for _, num := range m.`, fieldname, ` {`)
				p.In()
				p.encodeKey(fieldNumber, wireType)
				p.unsafeFixed32("num", "float32")
				p.Out()
				p.P(`}`)
			} else if proto3 {
				p.P(`if m.`, fieldname, ` != 0 {`)
				p.In()
				p.encodeKey(fieldNumber, wireType)
				p.unsafeFixed32(`m.`+fieldname, `float32`)
				p.Out()
				p.P(`}`)
			} else if !nullable {
				p.encodeKey(fieldNumber, wireType)
				p.unsafeFixed32(`m.`+fieldname, `float32`)
			} else {
				p.encodeKey(fieldNumber, wireType)
				p.unsafeFixed32(`*m.`+fieldname, "float32")
			}
		}
	case descriptor.FieldDescriptorProto_TYPE_INT64,
		descriptor.FieldDescriptorProto_TYPE_UINT64,
		descriptor.FieldDescriptorProto_TYPE_INT32,
		descriptor.FieldDescriptorProto_TYPE_UINT32,
		descriptor.FieldDescriptorProto_TYPE_ENUM:
		if packed {
			jvar := "j" + numGen.Next()
			p.P(`data`, numGen.Next(), ` := make([]byte, len(m.`, fieldname, `)*10)`)
			p.P(`var `, jvar, ` int`)
			if *field.Type == descriptor.FieldDescriptorProto_TYPE_INT64 ||
				*field.Type == descriptor.FieldDescriptorProto_TYPE_INT32 {
				p.P(`for _, num1 := range m.`, fieldname, ` {`)
				p.In()
				p.P(`num := uint64(num1)`)
			} else {
				p.P(`for _, num := range m.`, fieldname, ` {`)
				p.In()
			}
			p.P(`for num >= 1<<7 {`)
			p.In()
			p.P(`data`, numGen.Current(), `[`, jvar, `] = uint8(uint64(num)&0x7f|0x80)`)
			p.P(`num >>= 7`)
			p.P(jvar, `++`)
			p.Out()
			p.P(`}`)
			p.P(`data`, numGen.Current(), `[`, jvar, `] = uint8(num)`)
			p.P(jvar, `++`)
			p.Out()
			p.P(`}`)
			p.encodeKey(fieldNumber, wireType)
			p.callVarint(jvar)
			p.P(`i += copy(data[i:], data`, numGen.Current(), `[:`, jvar, `])`)
		} else if repeated {
			p.P(`for _, num := range m.`, fieldname, ` {`)
			p.In()
			p.encodeKey(fieldNumber, wireType)
			p.callVarint("num")
			p.Out()
			p.P(`}`)
		} else if proto3 {
			p.P(`if m.`, fieldname, ` != 0 {`)
			p.In()
			p.encodeKey(fieldNumber, wireType)
			p.callVarint(`m.`, fieldname)
			p.Out()
			p.P(`}`)
		} else if !nullable {
			p.encodeKey(fieldNumber, wireType)
			p.callVarint(`m.`, fieldname)
		} else {
			p.encodeKey(fieldNumber, wireType)
			p.callVarint(`*m.`, fieldname)
		}
	case descriptor.FieldDescriptorProto_TYPE_FIXED64,
		descriptor.FieldDescriptorProto_TYPE_SFIXED64:
		if !p.unsafe {
			if packed {
				p.encodeKey(fieldNumber, wireType)
				p.callVarint(`len(m.`, fieldname, `) * 8`)
				p.P(`for _, num := range m.`, fieldname, ` {`)
				p.In()
				p.encodeFixed64("num")
				p.Out()
				p.P(`}`)
			} else if repeated {
				p.P(`for _, num := range m.`, fieldname, ` {`)
				p.In()
				p.encodeKey(fieldNumber, wireType)
				p.encodeFixed64("num")
				p.Out()
				p.P(`}`)
			} else if proto3 {
				p.P(`if m.`, fieldname, ` != 0 {`)
				p.In()
				p.encodeKey(fieldNumber, wireType)
				p.callFixed64("m." + fieldname)
				p.Out()
				p.P(`}`)
			} else if !nullable {
				p.encodeKey(fieldNumber, wireType)
				p.callFixed64("m." + fieldname)
			} else {
				p.encodeKey(fieldNumber, wireType)
				p.callFixed64("*m." + fieldname)
			}
		} else {
			typeName := "int64"
			if *field.Type == descriptor.FieldDescriptorProto_TYPE_FIXED64 {
				typeName = "uint64"
			}
			if packed {
				p.encodeKey(fieldNumber, wireType)
				p.callVarint(`len(m.`, fieldname, `) * 8`)
				p.P(`for _, num := range m.`, fieldname, ` {`)
				p.In()
				p.unsafeFixed64("num", typeName)
				p.Out()
				p.P(`}`)
			} else if repeated {
				p.P(`for _, num := range m.`, fieldname, ` {`)
				p.In()
				p.encodeKey(fieldNumber, wireType)
				p.unsafeFixed64("num", typeName)
				p.Out()
				p.P(`}`)
			} else if proto3 {
				p.P(`if m.`, fieldname, ` != 0 {`)
				p.In()
				p.encodeKey(fieldNumber, wireType)
				p.unsafeFixed64("m."+fieldname, typeName)
				p.Out()
				p.P(`}`)
			} else if !nullable {
				p.encodeKey(fieldNumber, wireType)
				p.unsafeFixed64("m."+fieldname, typeName)
			} else {
				p.encodeKey(fieldNumber, wireType)
				p.unsafeFixed64("*m."+fieldname, typeName)
			}
		}
	case descriptor.FieldDescriptorProto_TYPE_FIXED32,
		descriptor.FieldDescriptorProto_TYPE_SFIXED32:
		if !p.unsafe {
			if packed {
				p.encodeKey(fieldNumber, wireType)
				p.callVarint(`len(m.`, fieldname, `) * 4`)
				p.P(`for _, num := range m.`, fieldname, ` {`)
				p.In()
				p.encodeFixed32("num")
				p.Out()
				p.P(`}`)
			} else if repeated {
				p.P(`for _, num := range m.`, fieldname, ` {`)
				p.In()
				p.encodeKey(fieldNumber, wireType)
				p.encodeFixed32("num")
				p.Out()
				p.P(`}`)
			} else if proto3 {
				p.P(`if m.`, fieldname, ` != 0 {`)
				p.In()
				p.encodeKey(fieldNumber, wireType)
				p.callFixed32("m." + fieldname)
				p.Out()
				p.P(`}`)
			} else if !nullable {
				p.encodeKey(fieldNumber, wireType)
				p.callFixed32("m." + fieldname)
			} else {
				p.encodeKey(fieldNumber, wireType)
				p.callFixed32("*m." + fieldname)
			}
		} else {
			typeName := "int32"
			if *field.Type == descriptor.FieldDescriptorProto_TYPE_FIXED32 {
				typeName = "uint32"
			}
			if packed {
				p.encodeKey(fieldNumber, wireType)
				p.callVarint(`len(m.`, fieldname, `) * 4`)
				p.P(`for _, num := range m.`, fieldname, ` {`)
				p.In()
				p.unsafeFixed32("num", typeName)
				p.Out()
				p.P(`}`)
			} else if repeated {
				p.P(`for _, num := range m.`, fieldname, ` {`)
				p.In()
				p.encodeKey(fieldNumber, wireType)
				p.unsafeFixed32("num", typeName)
				p.Out()
				p.P(`}`)
			} else if proto3 {
				p.P(`if m.`, fieldname, ` != 0 {`)
				p.In()
				p.encodeKey(fieldNumber, wireType)
				p.unsafeFixed32("m."+fieldname, typeName)
				p.Out()
				p.P(`}`)
			} else if !nullable {
				p.encodeKey(fieldNumber, wireType)
				p.unsafeFixed32("m."+fieldname, typeName)
			} else {
				p.encodeKey(fieldNumber, wireType)
				p.unsafeFixed32("*m."+fieldname, typeName)
			}
		}
	case descriptor.FieldDescriptorProto_TYPE_BOOL:
		if packed {
			p.encodeKey(fieldNumber, wireType)
			p.callVarint(`len(m.`, fieldname, `)`)
			p.P(`for _, b := range m.`, fieldname, ` {`)
			p.In()
			p.P(`if b {`)
			p.In()
			p.P(`data[i] = 1`)
			p.Out()
			p.P(`} else {`)
			p.In()
			p.P(`data[i] = 0`)
			p.Out()
			p.P(`}`)
			p.P(`i++`)
			p.Out()
			p.P(`}`)
		} else if repeated {
			p.P(`for _, b := range m.`, fieldname, ` {`)
			p.In()
			p.encodeKey(fieldNumber, wireType)
			p.P(`if b {`)
			p.In()
			p.P(`data[i] = 1`)
			p.Out()
			p.P(`} else {`)
			p.In()
			p.P(`data[i] = 0`)
			p.Out()
			p.P(`}`)
			p.P(`i++`)
			p.Out()
			p.P(`}`)
		} else if proto3 {
			p.P(`if m.`, fieldname, ` {`)
			p.In()
			p.encodeKey(fieldNumber, wireType)
			p.P(`if m.`, fieldname, ` {`)
			p.In()
			p.P(`data[i] = 1`)
			p.Out()
			p.P(`} else {`)
			p.In()
			p.P(`data[i] = 0`)
			p.Out()
			p.P(`}`)
			p.P(`i++`)
			p.Out()
			p.P(`}`)
		} else if !nullable {
			p.encodeKey(fieldNumber, wireType)
			p.P(`if m.`, fieldname, ` {`)
			p.In()
			p.P(`data[i] = 1`)
			p.Out()
			p.P(`} else {`)
			p.In()
			p.P(`data[i] = 0`)
			p.Out()
			p.P(`}`)
			p.P(`i++`)
		} else {
			p.encodeKey(fieldNumber, wireType)
			p.P(`if *m.`, fieldname, ` {`)
			p.In()
			p.P(`data[i] = 1`)
			p.Out()
			p.P(`} else {`)
			p.In()
			p.P(`data[i] = 0`)
			p.Out()
			p.P(`}`)
			p.P(`i++`)
		}
	case descriptor.FieldDescriptorProto_TYPE_STRING:
		if repeated {
			p.P(`for _, s := range m.`, fieldname, ` {`)
			p.In()
			p.encodeKey(fieldNumber, wireType)
			p.P(`l = len(s)`)
			p.encodeVarint("l")
			p.P(`i+=copy(data[i:], s)`)
			p.Out()
			p.P(`}`)
		} else if proto3 {
			p.P(`if len(m.`, fieldname, `) > 0 {`)
			p.In()
			p.encodeKey(fieldNumber, wireType)
			p.callVarint(`len(m.`, fieldname, `)`)
			p.P(`i+=copy(data[i:], m.`, fieldname, `)`)
			p.Out()
			p.P(`}`)
		} else if !nullable {
			p.encodeKey(fieldNumber, wireType)
			p.callVarint(`len(m.`, fieldname, `)`)
			p.P(`i+=copy(data[i:], m.`, fieldname, `)`)
		} else {
			p.encodeKey(fieldNumber, wireType)
			p.callVarint(`len(*m.`, fieldname, `)`)
			p.P(`i+=copy(data[i:], *m.`, fieldname, `)`)
		}
	case descriptor.FieldDescriptorProto_TYPE_GROUP:
		panic(fmt.Errorf("marshaler does not support group %v", fieldname))
	case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
		if p.IsMap(field) {
			m := p.GoMapType(nil, field)
			keygoTyp, keywire := p.GoType(nil, m.KeyField)
			keygoAliasTyp, _ := p.GoType(nil, m.KeyAliasField)
			// keys may not be pointers
			keygoTyp = strings.Replace(keygoTyp, "*", "", 1)
			keygoAliasTyp = strings.Replace(keygoAliasTyp, "*", "", 1)
			keyCapTyp := generator.CamelCase(keygoTyp)
			valuegoTyp, valuewire := p.GoType(nil, m.ValueField)
			valuegoAliasTyp, _ := p.GoType(nil, m.ValueAliasField)
			nullable, valuegoTyp, valuegoAliasTyp = generator.GoMapValueTypes(field, m.ValueField, valuegoTyp, valuegoAliasTyp)
			keyKeySize := keySize(1, wireToType(keywire))
			valueKeySize := keySize(2, wireToType(valuewire))
			if gogoproto.IsStableMarshaler(file.FileDescriptorProto, message.DescriptorProto) {
				keysName := `keysFor` + fieldname
				p.P(keysName, ` := make([]`, keygoTyp, `, 0, len(m.`, fieldname, `))`)
				p.P(`for k, _ := range m.`, fieldname, ` {`)
				p.In()
				p.P(keysName, ` = append(`, keysName, `, `, keygoTyp, `(k))`)
				p.Out()
				p.P(`}`)
				p.P(p.sortKeysPkg.Use(), `.`, keyCapTyp, `s(`, keysName, `)`)
				p.P(`for _, k := range `, keysName, ` {`)
			} else {
				p.P(`for k, _ := range m.`, fieldname, ` {`)
			}
			p.In()
			p.encodeKey(fieldNumber, wireType)
			sum := []string{strconv.Itoa(keyKeySize)}
			switch m.KeyField.GetType() {
			case descriptor.FieldDescriptorProto_TYPE_DOUBLE,
				descriptor.FieldDescriptorProto_TYPE_FIXED64,
				descriptor.FieldDescriptorProto_TYPE_SFIXED64:
				sum = append(sum, `8`)
			case descriptor.FieldDescriptorProto_TYPE_FLOAT,
				descriptor.FieldDescriptorProto_TYPE_FIXED32,
				descriptor.FieldDescriptorProto_TYPE_SFIXED32:
				sum = append(sum, `4`)
			case descriptor.FieldDescriptorProto_TYPE_INT64,
				descriptor.FieldDescriptorProto_TYPE_UINT64,
				descriptor.FieldDescriptorProto_TYPE_UINT32,
				descriptor.FieldDescriptorProto_TYPE_ENUM,
				descriptor.FieldDescriptorProto_TYPE_INT32:
				sum = append(sum, `sov`+p.localName+`(uint64(k))`)
			case descriptor.FieldDescriptorProto_TYPE_BOOL:
				sum = append(sum, `1`)
			case descriptor.FieldDescriptorProto_TYPE_STRING,
				descriptor.FieldDescriptorProto_TYPE_BYTES:
				sum = append(sum, `len(k)+sov`+p.localName+`(uint64(len(k)))`)
			case descriptor.FieldDescriptorProto_TYPE_SINT32,
				descriptor.FieldDescriptorProto_TYPE_SINT64:
				sum = append(sum, `soz`+p.localName+`(uint64(k))`)
			}
			if gogoproto.IsStableMarshaler(file.FileDescriptorProto, message.DescriptorProto) {
				p.P(`v := m.`, fieldname, `[`, keygoAliasTyp, `(k)]`)
			} else {
				p.P(`v := m.`, fieldname, `[k]`)
			}
			accessor := `v`
			switch m.ValueField.GetType() {
			case descriptor.FieldDescriptorProto_TYPE_DOUBLE,
				descriptor.FieldDescriptorProto_TYPE_FIXED64,
				descriptor.FieldDescriptorProto_TYPE_SFIXED64:
				sum = append(sum, strconv.Itoa(valueKeySize))
				sum = append(sum, strconv.Itoa(8))
			case descriptor.FieldDescriptorProto_TYPE_FLOAT,
				descriptor.FieldDescriptorProto_TYPE_FIXED32,
				descriptor.FieldDescriptorProto_TYPE_SFIXED32:
				sum = append(sum, strconv.Itoa(valueKeySize))
				sum = append(sum, strconv.Itoa(4))
			case descriptor.FieldDescriptorProto_TYPE_INT64,
				descriptor.FieldDescriptorProto_TYPE_UINT64,
				descriptor.FieldDescriptorProto_TYPE_UINT32,
				descriptor.FieldDescriptorProto_TYPE_ENUM,
				descriptor.FieldDescriptorProto_TYPE_INT32:
				sum = append(sum, strconv.Itoa(valueKeySize))
				sum = append(sum, `sov`+p.localName+`(uint64(v))`)
			case descriptor.FieldDescriptorProto_TYPE_BOOL:
				sum = append(sum, strconv.Itoa(valueKeySize))
				sum = append(sum, `1`)
			case descriptor.FieldDescriptorProto_TYPE_STRING:
				sum = append(sum, strconv.Itoa(valueKeySize))
				sum = append(sum, `len(v)+sov`+p.localName+`(uint64(len(v)))`)
			case descriptor.FieldDescriptorProto_TYPE_BYTES:
				if gogoproto.IsCustomType(field) {
					p.P(`cSize := 0`)
					if gogoproto.IsNullable(field) {
						p.P(`if `, accessor, ` != nil {`)
						p.In()
					}
					p.P(`cSize = `, accessor, `.Size()`)
					p.P(`cSize += `, strconv.Itoa(valueKeySize), ` + sov`+p.localName+`(uint64(cSize))`)
					if gogoproto.IsNullable(field) {
						p.Out()
						p.P(`}`)
					}
					sum = append(sum, `cSize`)
				} else {
					p.P(`byteSize := 0`)
					if proto3 {
						p.P(`if len(v) > 0 {`)
					} else {
						p.P(`if v != nil {`)
					}
					p.In()
					p.P(`byteSize = `, strconv.Itoa(valueKeySize), ` + len(v)+sov`+p.localName+`(uint64(len(v)))`)
					p.Out()
					p.P(`}`)
					sum = append(sum, `byteSize`)
				}
			case descriptor.FieldDescriptorProto_TYPE_SINT32,
				descriptor.FieldDescriptorProto_TYPE_SINT64:
				sum = append(sum, strconv.Itoa(valueKeySize))
				sum = append(sum, `soz`+p.localName+`(uint64(v))`)
			case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
				if valuegoTyp != valuegoAliasTyp &&
					!gogoproto.IsStdTime(field) &&
					!gogoproto.IsStdDuration(field) {
					if nullable {
						// cast back to the type that has the generated methods on it
						accessor = `((` + valuegoTyp + `)(` + accessor + `))`
					} else {
						accessor = `((*` + valuegoTyp + `)(&` + accessor + `))`
					}
				} else if !nullable {
					accessor = `(&v)`
				}
				p.P(`msgSize := 0`)
				p.P(`if `, accessor, ` != nil {`)
				p.In()
				if gogoproto.IsStdTime(field) {
					p.P(`msgSize = `, p.typesPkg.Use(), `.SizeOfStdTime(*`, accessor, `)`)
				} else if gogoproto.IsStdDuration(field) {
					p.P(`msgSize = `, p.typesPkg.Use(), `.SizeOfStdDuration(*`, accessor, `)`)
				} else if protoSizer {
					p.P(`msgSize = `, accessor, `.ProtoSize()`)
				} else {
					p.P(`msgSize = `, accessor, `.Size()`)
				}
				p.P(`msgSize += `, strconv.Itoa(valueKeySize), ` + sov`+p.localName+`(uint64(msgSize))`)
				p.Out()
				p.P(`}`)
				sum = append(sum, `msgSize`)
			}
			p.P(`mapSize := `, strings.Join(sum, " + "))
			p.callVarint("mapSize")
			p.encodeKey(1, wireToType(keywire))
			p.mapField(numGen, field, m.KeyField, "k", protoSizer)
			nullableMsg := nullable && (m.ValueField.GetType() == descriptor.FieldDescriptorProto_TYPE_MESSAGE ||
				gogoproto.IsCustomType(field) && m.ValueField.IsBytes())
			plainBytes := m.ValueField.IsBytes() && !gogoproto.IsCustomType(field)
			if nullableMsg {
				p.P(`if `, accessor, ` != nil { `)
				p.In()
			} else if plainBytes {
				if proto3 {
					p.P(`if len(`, accessor, `) > 0 {`)
				} else {
					p.P(`if `, accessor, ` != nil {`)
				}
				p.In()
			}
			p.encodeKey(2, wireToType(valuewire))
			p.mapField(numGen, field, m.ValueField, accessor, protoSizer)
			if nullableMsg || plainBytes {
				p.Out()
				p.P(`}`)
			}
			p.Out()
			p.P(`}`)
		} else if repeated {
			p.P(`for _, msg := range m.`, fieldname, ` {`)
			p.In()
			p.encodeKey(fieldNumber, wireType)
			varName := "msg"
			if gogoproto.IsStdTime(field) {
				if gogoproto.IsNullable(field) {
					varName = "*" + varName
				}
				p.callVarint(p.typesPkg.Use(), `.SizeOfStdTime(`, varName, `)`)
				p.P(`n, err := `, p.typesPkg.Use(), `.StdTimeMarshalTo(`, varName, `, data[i:])`)
			} else if gogoproto.IsStdDuration(field) {
				if gogoproto.IsNullable(field) {
					varName = "*" + varName
				}
				p.callVarint(p.typesPkg.Use(), `.SizeOfStdDuration(`, varName, `)`)
				p.P(`n, err := `, p.typesPkg.Use(), `.StdDurationMarshalTo(`, varName, `, data[i:])`)
			} else if protoSizer {
				p.callVarint(varName, ".ProtoSize()")
				p.P(`n, err := `, varName, `.MarshalTo(data[i:])`)
			} else {
				p.callVarint(varName, ".Size()")
				p.P(`n, err := `, varName, `.MarshalTo(data[i:])`)
			}
			p.P(`if err != nil {`)
			p.In()
			p.P(`return 0, err`)
			p.Out()
			p.P(`}`)
			p.P(`i+=n`)
			p.Out()
			p.P(`}`)
		} else {
			p.encodeKey(fieldNumber, wireType)
			varName := `m.` + fieldname
			if gogoproto.IsStdTime(field) {
				if gogoproto.IsNullable(field) {
					varName = "*" + varName
				}
				p.callVarint(p.typesPkg.Use(), `.SizeOfStdTime(`, varName, `)`)
				p.P(`n`, numGen.Next(), `, err := `, p.typesPkg.Use(), `.StdTimeMarshalTo(`, varName, `, data[i:])`)
			} else if gogoproto.IsStdDuration(field) {
				if gogoproto.IsNullable(field) {
					varName = "*" + varName
				}
				p.callVarint(p.typesPkg.Use(), `.SizeOfStdDuration(`, varName, `)`)
				p.P(`n`, numGen.Next(), `, err := `, p.typesPkg.Use(), `.StdDurationMarshalTo(`, varName, `, data[i:])`)
			} else if protoSizer {
				p.callVarint(varName, `.ProtoSize()`)
				p.P(`n`, numGen.Next(), `, err := `, varName, `.MarshalTo(data[i:])`)
			} else {
				p.callVarint(varName, `.Size()`)
				p.P(`n`, numGen.Next(), `, err := `, varName, `.MarshalTo(data[i:])`)
			}
			p.P(`if err != nil {`)
			p.In()
			p.P(`return 0, err`)
			p.Out()
			p.P(`}`)
			p.P(`i+=n`, numGen.Current())
		}
	case descriptor.FieldDescriptorProto_TYPE_BYTES:
		if !gogoproto.IsCustomType(field) {
			if repeated {
				p.P(`for _, b := range m.`, fieldname, ` {`)
				p.In()
				p.encodeKey(fieldNumber, wireType)
				p.callVarint("len(b)")
				p.P(`i+=copy(data[i:], b)`)
				p.Out()
				p.P(`}`)
			} else if proto3 {
				p.P(`if len(m.`, fieldname, `) > 0 {`)
				p.In()
				p.encodeKey(fieldNumber, wireType)
				p.callVarint(`len(m.`, fieldname, `)`)
				p.P(`i+=copy(data[i:], m.`, fieldname, `)`)
				p.Out()
				p.P(`}`)
			} else {
				p.encodeKey(fieldNumber, wireType)
				p.callVarint(`len(m.`, fieldname, `)`)
				p.P(`i+=copy(data[i:], m.`, fieldname, `)`)
			}
		} else {
			if repeated {
				p.P(`for _, msg := range m.`, fieldname, ` {`)
				p.In()
				p.encodeKey(fieldNumber, wireType)
				if protoSizer {
					p.callVarint(`msg.ProtoSize()`)
				} else {
					p.callVarint(`msg.Size()`)
				}
				p.P(`n, err := msg.MarshalTo(data[i:])`)
				p.P(`if err != nil {`)
				p.In()
				p.P(`return 0, err`)
				p.Out()
				p.P(`}`)
				p.P(`i+=n`)
				p.Out()
				p.P(`}`)
			} else {
				p.encodeKey(fieldNumber, wireType)
				if protoSizer {
					p.callVarint(`m.`, fieldname, `.ProtoSize()`)
				} else {
					p.callVarint(`m.`, fieldname, `.Size()`)
				}
				p.P(`n`, 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+=n`, numGen.Current())
			}
		}
	case descriptor.FieldDescriptorProto_TYPE_SINT32:
		if packed {
			datavar := "data" + numGen.Next()
			jvar := "j" + numGen.Next()
			p.P(datavar, ` := make([]byte, len(m.`, fieldname, ")*5)")
			p.P(`var `, jvar, ` int`)
			p.P(`for _, num := range m.`, fieldname, ` {`)
			p.In()
			xvar := "x" + numGen.Next()
			p.P(xvar, ` := (uint32(num) << 1) ^ uint32((num >> 31))`)
			p.P(`for `, xvar, ` >= 1<<7 {`)
			p.In()
			p.P(datavar, `[`, jvar, `] = uint8(uint64(`, xvar, `)&0x7f|0x80)`)
			p.P(jvar, `++`)
			p.P(xvar, ` >>= 7`)
			p.Out()
			p.P(`}`)
			p.P(datavar, `[`, jvar, `] = uint8(`, xvar, `)`)
			p.P(jvar, `++`)
			p.Out()
			p.P(`}`)
			p.encodeKey(fieldNumber, wireType)
			p.callVarint(jvar)
			p.P(`i+=copy(data[i:], `, datavar, `[:`, jvar, `])`)
		} else if repeated {
			p.P(`for _, num := range m.`, fieldname, ` {`)
			p.In()
			p.encodeKey(fieldNumber, wireType)
			p.P(`x`, numGen.Next(), ` := (uint32(num) << 1) ^ uint32((num >> 31))`)
			p.encodeVarint("x" + numGen.Current())
			p.Out()
			p.P(`}`)
		} else if proto3 {
			p.P(`if m.`, fieldname, ` != 0 {`)
			p.In()
			p.encodeKey(fieldNumber, wireType)
			p.callVarint(`(uint32(m.`, fieldname, `) << 1) ^ uint32((m.`, fieldname, ` >> 31))`)
			p.Out()
			p.P(`}`)
		} else if !nullable {
			p.encodeKey(fieldNumber, wireType)
			p.callVarint(`(uint32(m.`, fieldname, `) << 1) ^ uint32((m.`, fieldname, ` >> 31))`)
		} else {
			p.encodeKey(fieldNumber, wireType)
			p.callVarint(`(uint32(*m.`, fieldname, `) << 1) ^ uint32((*m.`, fieldname, ` >> 31))`)
		}
	case descriptor.FieldDescriptorProto_TYPE_SINT64:
		if packed {
			jvar := "j" + numGen.Next()
			xvar := "x" + numGen.Next()
			datavar := "data" + numGen.Next()
			p.P(`var `, jvar, ` int`)
			p.P(datavar, ` := make([]byte, len(m.`, fieldname, `)*10)`)
			p.P(`for _, num := range m.`, fieldname, ` {`)
			p.In()
			p.P(xvar, ` := (uint64(num) << 1) ^ uint64((num >> 63))`)
			p.P(`for `, xvar, ` >= 1<<7 {`)
			p.In()
			p.P(datavar, `[`, jvar, `] = uint8(uint64(`, xvar, `)&0x7f|0x80)`)
			p.P(jvar, `++`)
			p.P(xvar, ` >>= 7`)
			p.Out()
			p.P(`}`)
			p.P(datavar, `[`, jvar, `] = uint8(`, xvar, `)`)
			p.P(jvar, `++`)
			p.Out()
			p.P(`}`)
			p.encodeKey(fieldNumber, wireType)
			p.callVarint(jvar)
			p.P(`i+=copy(data[i:], `, datavar, `[:`, jvar, `])`)
		} else if repeated {
			p.P(`for _, num := range m.`, fieldname, ` {`)
			p.In()
			p.encodeKey(fieldNumber, wireType)
			p.P(`x`, numGen.Next(), ` := (uint64(num) << 1) ^ uint64((num >> 63))`)
			p.encodeVarint("x" + numGen.Current())
			p.Out()
			p.P(`}`)
		} else if proto3 {
			p.P(`if m.`, fieldname, ` != 0 {`)
			p.In()
			p.encodeKey(fieldNumber, wireType)
			p.callVarint(`(uint64(m.`, fieldname, `) << 1) ^ uint64((m.`, fieldname, ` >> 63))`)
			p.Out()
			p.P(`}`)
		} else if !nullable {
			p.encodeKey(fieldNumber, wireType)
			p.callVarint(`(uint64(m.`, fieldname, `) << 1) ^ uint64((m.`, fieldname, ` >> 63))`)
		} else {
			p.encodeKey(fieldNumber, wireType)
			p.callVarint(`(uint64(*m.`, fieldname, `) << 1) ^ uint64((*m.`, fieldname, ` >> 63))`)
		}
	default:
		panic("not implemented")
	}
	if (required && nullable) || repeated || doNilCheck {
		p.Out()
		p.P(`}`)
	}
}
Пример #2
0
func (p *size) generateField(proto3 bool, file *generator.FileDescriptor, message *generator.Descriptor, field *descriptor.FieldDescriptorProto, sizeName string) {
	fieldname := p.GetOneOfFieldName(message, field)
	nullable := gogoproto.IsNullable(field)
	repeated := field.IsRepeated()
	doNilCheck := gogoproto.NeedsNilCheck(proto3, field)
	if repeated {
		p.P(`if len(m.`, fieldname, `) > 0 {`)
		p.In()
	} else if doNilCheck {
		p.P(`if m.`, fieldname, ` != nil {`)
		p.In()
	}
	packed := field.IsPacked() || (proto3 && field.IsRepeated() && generator.IsScalar(field))
	_, wire := p.GoType(message, field)
	wireType := wireToType(wire)
	fieldNumber := field.GetNumber()
	if packed {
		wireType = proto.WireBytes
	}
	key := keySize(fieldNumber, wireType)
	switch *field.Type {
	case descriptor.FieldDescriptorProto_TYPE_DOUBLE,
		descriptor.FieldDescriptorProto_TYPE_FIXED64,
		descriptor.FieldDescriptorProto_TYPE_SFIXED64:
		if packed {
			p.P(`n+=`, strconv.Itoa(key), `+sov`, p.localName, `(uint64(len(m.`, fieldname, `)*8))`, `+len(m.`, fieldname, `)*8`)
		} else if repeated {
			p.P(`n+=`, strconv.Itoa(key+8), `*len(m.`, fieldname, `)`)
		} else if proto3 {
			p.P(`if m.`, fieldname, ` != 0 {`)
			p.In()
			p.P(`n+=`, strconv.Itoa(key+8))
			p.Out()
			p.P(`}`)
		} else if nullable {
			p.P(`n+=`, strconv.Itoa(key+8))
		} else {
			p.P(`n+=`, strconv.Itoa(key+8))
		}
	case descriptor.FieldDescriptorProto_TYPE_FLOAT,
		descriptor.FieldDescriptorProto_TYPE_FIXED32,
		descriptor.FieldDescriptorProto_TYPE_SFIXED32:
		if packed {
			p.P(`n+=`, strconv.Itoa(key), `+sov`, p.localName, `(uint64(len(m.`, fieldname, `)*4))`, `+len(m.`, fieldname, `)*4`)
		} else if repeated {
			p.P(`n+=`, strconv.Itoa(key+4), `*len(m.`, fieldname, `)`)
		} else if proto3 {
			p.P(`if m.`, fieldname, ` != 0 {`)
			p.In()
			p.P(`n+=`, strconv.Itoa(key+4))
			p.Out()
			p.P(`}`)
		} else if nullable {
			p.P(`n+=`, strconv.Itoa(key+4))
		} else {
			p.P(`n+=`, strconv.Itoa(key+4))
		}
	case descriptor.FieldDescriptorProto_TYPE_INT64,
		descriptor.FieldDescriptorProto_TYPE_UINT64,
		descriptor.FieldDescriptorProto_TYPE_UINT32,
		descriptor.FieldDescriptorProto_TYPE_ENUM,
		descriptor.FieldDescriptorProto_TYPE_INT32:
		if packed {
			p.P(`l = 0`)
			p.P(`for _, e := range m.`, fieldname, ` {`)
			p.In()
			p.P(`l+=sov`, p.localName, `(uint64(e))`)
			p.Out()
			p.P(`}`)
			p.P(`n+=`, strconv.Itoa(key), `+sov`, p.localName, `(uint64(l))+l`)
		} else if repeated {
			p.P(`for _, e := range m.`, fieldname, ` {`)
			p.In()
			p.P(`n+=`, strconv.Itoa(key), `+sov`, p.localName, `(uint64(e))`)
			p.Out()
			p.P(`}`)
		} else if proto3 {
			p.P(`if m.`, fieldname, ` != 0 {`)
			p.In()
			p.P(`n+=`, strconv.Itoa(key), `+sov`, p.localName, `(uint64(m.`, fieldname, `))`)
			p.Out()
			p.P(`}`)
		} else if nullable {
			p.P(`n+=`, strconv.Itoa(key), `+sov`, p.localName, `(uint64(*m.`, fieldname, `))`)
		} else {
			p.P(`n+=`, strconv.Itoa(key), `+sov`, p.localName, `(uint64(m.`, fieldname, `))`)
		}
	case descriptor.FieldDescriptorProto_TYPE_BOOL:
		if packed {
			p.P(`n+=`, strconv.Itoa(key), `+sov`, p.localName, `(uint64(len(m.`, fieldname, `)))`, `+len(m.`, fieldname, `)*1`)
		} else if repeated {
			p.P(`n+=`, strconv.Itoa(key+1), `*len(m.`, fieldname, `)`)
		} else if proto3 {
			p.P(`if m.`, fieldname, ` {`)
			p.In()
			p.P(`n+=`, strconv.Itoa(key+1))
			p.Out()
			p.P(`}`)
		} else if nullable {
			p.P(`n+=`, strconv.Itoa(key+1))
		} else {
			p.P(`n+=`, strconv.Itoa(key+1))
		}
	case descriptor.FieldDescriptorProto_TYPE_STRING:
		if repeated {
			p.P(`for _, s := range m.`, fieldname, ` { `)
			p.In()
			p.P(`l = len(s)`)
			p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
			p.Out()
			p.P(`}`)
		} else if proto3 {
			p.P(`l=len(m.`, fieldname, `)`)
			p.P(`if l > 0 {`)
			p.In()
			p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
			p.Out()
			p.P(`}`)
		} else if nullable {
			p.P(`l=len(*m.`, fieldname, `)`)
			p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
		} else {
			p.P(`l=len(m.`, fieldname, `)`)
			p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
		}
	case descriptor.FieldDescriptorProto_TYPE_GROUP:
		panic(fmt.Errorf("size does not support group %v", fieldname))
	case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
		if p.IsMap(field) {
			m := p.GoMapType(nil, field)
			_, keywire := p.GoType(nil, m.KeyAliasField)
			valuegoTyp, _ := p.GoType(nil, m.ValueField)
			valuegoAliasTyp, valuewire := p.GoType(nil, m.ValueAliasField)
			_, fieldwire := p.GoType(nil, field)

			nullable, valuegoTyp, valuegoAliasTyp = generator.GoMapValueTypes(field, m.ValueField, valuegoTyp, valuegoAliasTyp)

			fieldKeySize := keySize(field.GetNumber(), wireToType(fieldwire))
			keyKeySize := keySize(1, wireToType(keywire))
			valueKeySize := keySize(2, wireToType(valuewire))
			p.P(`for k, v := range m.`, fieldname, ` { `)
			p.In()
			p.P(`_ = k`)
			p.P(`_ = v`)
			sum := []string{strconv.Itoa(keyKeySize)}
			switch m.KeyField.GetType() {
			case descriptor.FieldDescriptorProto_TYPE_DOUBLE,
				descriptor.FieldDescriptorProto_TYPE_FIXED64,
				descriptor.FieldDescriptorProto_TYPE_SFIXED64:
				sum = append(sum, `8`)
			case descriptor.FieldDescriptorProto_TYPE_FLOAT,
				descriptor.FieldDescriptorProto_TYPE_FIXED32,
				descriptor.FieldDescriptorProto_TYPE_SFIXED32:
				sum = append(sum, `4`)
			case descriptor.FieldDescriptorProto_TYPE_INT64,
				descriptor.FieldDescriptorProto_TYPE_UINT64,
				descriptor.FieldDescriptorProto_TYPE_UINT32,
				descriptor.FieldDescriptorProto_TYPE_ENUM,
				descriptor.FieldDescriptorProto_TYPE_INT32:
				sum = append(sum, `sov`+p.localName+`(uint64(k))`)
			case descriptor.FieldDescriptorProto_TYPE_BOOL:
				sum = append(sum, `1`)
			case descriptor.FieldDescriptorProto_TYPE_STRING,
				descriptor.FieldDescriptorProto_TYPE_BYTES:
				sum = append(sum, `len(k)+sov`+p.localName+`(uint64(len(k)))`)
			case descriptor.FieldDescriptorProto_TYPE_SINT32,
				descriptor.FieldDescriptorProto_TYPE_SINT64:
				sum = append(sum, `soz`+p.localName+`(uint64(k))`)
			}
			switch m.ValueField.GetType() {
			case descriptor.FieldDescriptorProto_TYPE_DOUBLE,
				descriptor.FieldDescriptorProto_TYPE_FIXED64,
				descriptor.FieldDescriptorProto_TYPE_SFIXED64:
				sum = append(sum, strconv.Itoa(valueKeySize))
				sum = append(sum, strconv.Itoa(8))
			case descriptor.FieldDescriptorProto_TYPE_FLOAT,
				descriptor.FieldDescriptorProto_TYPE_FIXED32,
				descriptor.FieldDescriptorProto_TYPE_SFIXED32:
				sum = append(sum, strconv.Itoa(valueKeySize))
				sum = append(sum, strconv.Itoa(4))
			case descriptor.FieldDescriptorProto_TYPE_INT64,
				descriptor.FieldDescriptorProto_TYPE_UINT64,
				descriptor.FieldDescriptorProto_TYPE_UINT32,
				descriptor.FieldDescriptorProto_TYPE_ENUM,
				descriptor.FieldDescriptorProto_TYPE_INT32:
				sum = append(sum, strconv.Itoa(valueKeySize))
				sum = append(sum, `sov`+p.localName+`(uint64(v))`)
			case descriptor.FieldDescriptorProto_TYPE_BOOL:
				sum = append(sum, strconv.Itoa(valueKeySize))
				sum = append(sum, `1`)
			case descriptor.FieldDescriptorProto_TYPE_STRING:
				sum = append(sum, strconv.Itoa(valueKeySize))
				sum = append(sum, `len(v)+sov`+p.localName+`(uint64(len(v)))`)
			case descriptor.FieldDescriptorProto_TYPE_BYTES:
				if gogoproto.IsCustomType(field) {
					p.P(`l = 0`)
					if nullable {
						p.P(`if v != nil {`)
						p.In()
					}
					p.P(`l = v.`, sizeName, `()`)
					p.P(`l += `, strconv.Itoa(valueKeySize), ` + sov`+p.localName+`(uint64(l))`)
					if nullable {
						p.Out()
						p.P(`}`)
					}
					sum = append(sum, `l`)
				} else {
					p.P(`l = 0`)
					if proto3 {
						p.P(`if len(v) > 0 {`)
					} else {
						p.P(`if v != nil {`)
					}
					p.In()
					p.P(`l = `, strconv.Itoa(valueKeySize), ` + len(v)+sov`+p.localName+`(uint64(len(v)))`)
					p.Out()
					p.P(`}`)
					sum = append(sum, `l`)
				}
			case descriptor.FieldDescriptorProto_TYPE_SINT32,
				descriptor.FieldDescriptorProto_TYPE_SINT64:
				sum = append(sum, strconv.Itoa(valueKeySize))
				sum = append(sum, `soz`+p.localName+`(uint64(v))`)
			case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
				stdSizeCall, stdOk := p.std(field, "v")
				if nullable {
					p.P(`l = 0`)
					p.P(`if v != nil {`)
					p.In()
					if stdOk {
						p.P(`l = `, stdSizeCall)
					} else if valuegoTyp != valuegoAliasTyp {
						p.P(`l = ((`, valuegoTyp, `)(v)).`, sizeName, `()`)
					} else {
						p.P(`l = v.`, sizeName, `()`)
					}
					p.P(`l += `, strconv.Itoa(valueKeySize), ` + sov`+p.localName+`(uint64(l))`)
					p.Out()
					p.P(`}`)
					sum = append(sum, `l`)
				} else {
					if stdOk {
						p.P(`l = `, stdSizeCall)
					} else if valuegoTyp != valuegoAliasTyp {
						p.P(`l = ((*`, valuegoTyp, `)(&v)).`, sizeName, `()`)
					} else {
						p.P(`l = v.`, sizeName, `()`)
					}
					sum = append(sum, strconv.Itoa(valueKeySize))
					sum = append(sum, `l+sov`+p.localName+`(uint64(l))`)
				}
			}
			p.P(`mapEntrySize := `, strings.Join(sum, "+"))
			p.P(`n+=mapEntrySize+`, fieldKeySize, `+sov`, p.localName, `(uint64(mapEntrySize))`)
			p.Out()
			p.P(`}`)
		} else if repeated {
			p.P(`for _, e := range m.`, fieldname, ` { `)
			p.In()
			stdSizeCall, stdOk := p.std(field, "e")
			if stdOk {
				p.P(`l=`, stdSizeCall)
			} else {
				p.P(`l=e.`, sizeName, `()`)
			}
			p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
			p.Out()
			p.P(`}`)
		} else {
			stdSizeCall, stdOk := p.std(field, "m."+fieldname)
			if stdOk {
				p.P(`l=`, stdSizeCall)
			} else {
				p.P(`l=m.`, fieldname, `.`, sizeName, `()`)
			}
			p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
		}
	case descriptor.FieldDescriptorProto_TYPE_BYTES:
		if !gogoproto.IsCustomType(field) {
			if repeated {
				p.P(`for _, b := range m.`, fieldname, ` { `)
				p.In()
				p.P(`l = len(b)`)
				p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
				p.Out()
				p.P(`}`)
			} else if proto3 {
				p.P(`l=len(m.`, fieldname, `)`)
				p.P(`if l > 0 {`)
				p.In()
				p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
				p.Out()
				p.P(`}`)
			} else {
				p.P(`l=len(m.`, fieldname, `)`)
				p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
			}
		} else {
			if repeated {
				p.P(`for _, e := range m.`, fieldname, ` { `)
				p.In()
				p.P(`l=e.`, sizeName, `()`)
				p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
				p.Out()
				p.P(`}`)
			} else {
				p.P(`l=m.`, fieldname, `.`, sizeName, `()`)
				p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
			}
		}
	case descriptor.FieldDescriptorProto_TYPE_SINT32,
		descriptor.FieldDescriptorProto_TYPE_SINT64:
		if packed {
			p.P(`l = 0`)
			p.P(`for _, e := range m.`, fieldname, ` {`)
			p.In()
			p.P(`l+=soz`, p.localName, `(uint64(e))`)
			p.Out()
			p.P(`}`)
			p.P(`n+=`, strconv.Itoa(key), `+sov`, p.localName, `(uint64(l))+l`)
		} else if repeated {
			p.P(`for _, e := range m.`, fieldname, ` {`)
			p.In()
			p.P(`n+=`, strconv.Itoa(key), `+soz`, p.localName, `(uint64(e))`)
			p.Out()
			p.P(`}`)
		} else if proto3 {
			p.P(`if m.`, fieldname, ` != 0 {`)
			p.In()
			p.P(`n+=`, strconv.Itoa(key), `+soz`, p.localName, `(uint64(m.`, fieldname, `))`)
			p.Out()
			p.P(`}`)
		} else if nullable {
			p.P(`n+=`, strconv.Itoa(key), `+soz`, p.localName, `(uint64(*m.`, fieldname, `))`)
		} else {
			p.P(`n+=`, strconv.Itoa(key), `+soz`, p.localName, `(uint64(m.`, fieldname, `))`)
		}
	default:
		panic("not implemented")
	}
	if repeated || doNilCheck {
		p.Out()
		p.P(`}`)
	}
}
Пример #3
0
func (p *unmarshal) Generate(file *generator.FileDescriptor) {
	proto3 := gogoproto.IsProto3(file.FileDescriptorProto)
	p.PluginImports = generator.NewPluginImports(p.Generator)
	p.atleastOne = false
	p.localName = generator.FileName(file)
	if p.unsafe {
		p.localName += "Unsafe"
	}

	p.ioPkg = p.NewImport("io")
	p.mathPkg = p.NewImport("math")
	p.unsafePkg = p.NewImport("unsafe")
	p.typesPkg = p.NewImport("github.com/maditya/protobuf/types")
	fmtPkg := p.NewImport("fmt")
	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() {
		ccTypeName := generator.CamelCaseSlice(message.TypeName())
		if p.unsafe {
			if !gogoproto.IsUnsafeUnmarshaler(file.FileDescriptorProto, message.DescriptorProto) {
				continue
			}
			if gogoproto.IsUnmarshaler(file.FileDescriptorProto, message.DescriptorProto) {
				panic(fmt.Sprintf("unsafe_unmarshaler and unmarshaler enabled for %v", ccTypeName))
			}
		}
		if !p.unsafe {
			if !gogoproto.IsUnmarshaler(file.FileDescriptorProto, message.DescriptorProto) {
				continue
			}
			if gogoproto.IsUnsafeUnmarshaler(file.FileDescriptorProto, message.DescriptorProto) {
				panic(fmt.Sprintf("unsafe_unmarshaler and unmarshaler enabled for %v", ccTypeName))
			}
		}
		if message.DescriptorProto.GetOptions().GetMapEntry() {
			continue
		}
		p.atleastOne = true

		// build a map required field_id -> bitmask offset
		rfMap := make(map[int32]uint)
		rfNextId := uint(0)
		for _, field := range message.Field {
			if field.IsRequired() {
				rfMap[field.GetNumber()] = rfNextId
				rfNextId++
			}
		}
		rfCount := len(rfMap)

		p.P(`func (m *`, ccTypeName, `) Unmarshal(data []byte) error {`)
		p.In()
		if rfCount > 0 {
			p.P(`var hasFields [`, strconv.Itoa(1+(rfCount-1)/64), `]uint64`)
		}
		p.P(`l := len(data)`)
		p.P(`iNdEx := 0`)
		p.P(`for iNdEx < l {`)
		p.In()
		p.P(`preIndex := iNdEx`)
		p.P(`var wire uint64`)
		p.decodeVarint("wire", "uint64")
		p.P(`fieldNum := int32(wire >> 3)`)
		if len(message.Field) > 0 || !message.IsGroup() {
			p.P(`wireType := int(wire & 0x7)`)
		}
		if !message.IsGroup() {
			p.P(`if wireType == `, strconv.Itoa(proto.WireEndGroup), ` {`)
			p.In()
			p.P(`return `, fmtPkg.Use(), `.Errorf("proto: `+message.GetName()+`: wiretype end group for non-group")`)
			p.Out()
			p.P(`}`)
		}
		p.P(`if fieldNum <= 0 {`)
		p.In()
		p.P(`return `, fmtPkg.Use(), `.Errorf("proto: `+message.GetName()+`: illegal tag %d (wire type %d)", fieldNum, wire)`)
		p.Out()
		p.P(`}`)
		p.P(`switch fieldNum {`)
		p.In()
		for _, field := range message.Field {
			fieldname := p.GetFieldName(message, field)
			errFieldname := fieldname
			if field.OneofIndex != nil {
				errFieldname = p.GetOneOfFieldName(message, field)
			}
			packed := field.IsPacked() || (proto3 && field.IsRepeated() && generator.IsScalar(field))
			p.P(`case `, strconv.Itoa(int(field.GetNumber())), `:`)
			p.In()
			wireType := field.WireType()
			if packed {
				p.P(`if wireType == `, strconv.Itoa(proto.WireBytes), `{`)
				p.In()
				p.P(`var packedLen int`)
				p.decodeVarint("packedLen", "int")
				p.P(`if packedLen < 0 {`)
				p.In()
				p.P(`return ErrInvalidLength` + p.localName)
				p.Out()
				p.P(`}`)
				p.P(`postIndex := iNdEx + packedLen`)
				p.P(`if postIndex > l {`)
				p.In()
				p.P(`return `, p.ioPkg.Use(), `.ErrUnexpectedEOF`)
				p.Out()
				p.P(`}`)
				p.P(`for iNdEx < postIndex {`)
				p.In()
				p.field(file, message, field, fieldname, false)
				p.Out()
				p.P(`}`)
				p.Out()
				p.P(`} else if wireType == `, strconv.Itoa(wireType), `{`)
				p.In()
				p.field(file, message, field, fieldname, false)
				p.Out()
				p.P(`} else {`)
				p.In()
				p.P(`return ` + fmtPkg.Use() + `.Errorf("proto: wrong wireType = %d for field ` + errFieldname + `", wireType)`)
				p.Out()
				p.P(`}`)
			} else {
				p.P(`if wireType != `, strconv.Itoa(wireType), `{`)
				p.In()
				p.P(`return ` + fmtPkg.Use() + `.Errorf("proto: wrong wireType = %d for field ` + errFieldname + `", wireType)`)
				p.Out()
				p.P(`}`)
				p.field(file, message, field, fieldname, proto3)
			}

			if field.IsRequired() {
				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()
		p.P(`default:`)
		p.In()
		if message.DescriptorProto.HasExtension() {
			c := []string{}
			for _, erange := range message.GetExtensionRange() {
				c = append(c, `((fieldNum >= `+strconv.Itoa(int(erange.GetStart()))+") && (fieldNum<"+strconv.Itoa(int(erange.GetEnd()))+`))`)
			}
			p.P(`if `, strings.Join(c, "||"), `{`)
			p.In()
			p.P(`var sizeOfWire int`)
			p.P(`for {`)
			p.In()
			p.P(`sizeOfWire++`)
			p.P(`wire >>= 7`)
			p.P(`if wire == 0 {`)
			p.In()
			p.P(`break`)
			p.Out()
			p.P(`}`)
			p.Out()
			p.P(`}`)
			p.P(`iNdEx-=sizeOfWire`)
			p.P(`skippy, err := skip`, p.localName+`(data[iNdEx:])`)
			p.P(`if err != nil {`)
			p.In()
			p.P(`return err`)
			p.Out()
			p.P(`}`)
			p.P(`if skippy < 0 {`)
			p.In()
			p.P(`return ErrInvalidLength`, p.localName)
			p.Out()
			p.P(`}`)
			p.P(`if (iNdEx + skippy) > l {`)
			p.In()
			p.P(`return `, p.ioPkg.Use(), `.ErrUnexpectedEOF`)
			p.Out()
			p.P(`}`)
			p.P(protoPkg.Use(), `.AppendExtension(m, int32(fieldNum), data[iNdEx:iNdEx+skippy])`)
			p.P(`iNdEx += skippy`)
			p.Out()
			p.P(`} else {`)
			p.In()
		}
		p.P(`iNdEx=preIndex`)
		p.P(`skippy, err := skip`, p.localName, `(data[iNdEx:])`)
		p.P(`if err != nil {`)
		p.In()
		p.P(`return err`)
		p.Out()
		p.P(`}`)
		p.P(`if skippy < 0 {`)
		p.In()
		p.P(`return ErrInvalidLength`, p.localName)
		p.Out()
		p.P(`}`)
		p.P(`if (iNdEx + skippy) > l {`)
		p.In()
		p.P(`return `, p.ioPkg.Use(), `.ErrUnexpectedEOF`)
		p.Out()
		p.P(`}`)
		if gogoproto.HasUnrecognized(file.FileDescriptorProto, message.DescriptorProto) {
			p.P(`m.XXX_unrecognized = append(m.XXX_unrecognized, data[iNdEx:iNdEx+skippy]...)`)
		}
		p.P(`iNdEx += skippy`)
		p.Out()
		if message.DescriptorProto.HasExtension() {
			p.Out()
			p.P(`}`)
		}
		p.Out()
		p.P(`}`)
		p.Out()
		p.P(`}`)

		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()
			if !gogoproto.ImportsGoGoProto(file.FileDescriptorProto) {
				p.P(`return new(`, protoPkg.Use(), `.RequiredNotSetError)`)
			} else {
				p.P(`return `, protoPkg.Use(), `.NewRequiredNotSetError("`, field.GetName(), `")`)
			}
			p.Out()
			p.P(`}`)
		}
		p.P()
		p.P(`if iNdEx > l {`)
		p.In()
		p.P(`return ` + p.ioPkg.Use() + `.ErrUnexpectedEOF`)
		p.Out()
		p.P(`}`)
		p.P(`return nil`)
		p.Out()
		p.P(`}`)
	}
	if !p.atleastOne {
		return
	}

	p.P(`func skip` + p.localName + `(data []byte) (n int, err error) {
		l := len(data)
		iNdEx := 0
		for iNdEx < l {
			var wire uint64
			for shift := uint(0); ; shift += 7 {
				if shift >= 64 {
					return 0, ErrIntOverflow` + p.localName + `
				}
				if iNdEx >= l {
					return 0, ` + p.ioPkg.Use() + `.ErrUnexpectedEOF
				}
				b := data[iNdEx]
				iNdEx++
				wire |= (uint64(b) & 0x7F) << shift
				if b < 0x80 {
					break
				}
			}
			wireType := int(wire & 0x7)
			switch wireType {
			case 0:
				for shift := uint(0); ; shift += 7 {
					if shift >= 64 {
						return 0, ErrIntOverflow` + p.localName + `
					}
					if iNdEx >= l {
						return 0, ` + p.ioPkg.Use() + `.ErrUnexpectedEOF
					}
					iNdEx++
					if data[iNdEx-1] < 0x80 {
						break
					}
				}
				return iNdEx, nil
			case 1:
				iNdEx += 8
				return iNdEx, nil
			case 2:
				var length int
				for shift := uint(0); ; shift += 7 {
					if shift >= 64 {
						return 0, ErrIntOverflow` + p.localName + `
					}
					if iNdEx >= l {
						return 0, ` + p.ioPkg.Use() + `.ErrUnexpectedEOF
					}
					b := data[iNdEx]
					iNdEx++
					length |= (int(b) & 0x7F) << shift
					if b < 0x80 {
						break
					}
				}
				iNdEx += length
				if length < 0 {
					return 0, ErrInvalidLength` + p.localName + `
				}
				return iNdEx, nil
			case 3:
				for {
					var innerWire uint64
					var start int = iNdEx
					for shift := uint(0); ; shift += 7 {
						if shift >= 64 {
							return 0, ErrIntOverflow` + p.localName + `
						}
						if iNdEx >= l {
							return 0, ` + p.ioPkg.Use() + `.ErrUnexpectedEOF
						}
						b := data[iNdEx]
						iNdEx++
						innerWire |= (uint64(b) & 0x7F) << shift
						if b < 0x80 {
							break
						}
					}
					innerWireType := int(innerWire & 0x7)
					if innerWireType == 4 {
						break
					}
					next, err := skip` + p.localName + `(data[start:])
					if err != nil {
						return 0, err
					}
					iNdEx = start + next
				}
				return iNdEx, nil
			case 4:
				return iNdEx, nil
			case 5:
				iNdEx += 4
				return iNdEx, nil
			default:
				return 0, ` + fmtPkg.Use() + `.Errorf("proto: illegal wireType %d", wireType)
			}
		}
		panic("unreachable")
	}

	var (
		ErrInvalidLength` + p.localName + ` = ` + fmtPkg.Use() + `.Errorf("proto: negative length found during unmarshaling")
		ErrIntOverflow` + p.localName + ` = ` + fmtPkg.Use() + `.Errorf("proto: integer overflow")
	)
	`)
}