2020-09-09 18:09:42 +00:00
|
|
|
// Copyright 2018 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
// Package tag marshals and unmarshals the legacy struct tags as generated
|
|
|
|
// by historical versions of protoc-gen-go.
|
|
|
|
package tag
|
|
|
|
|
|
|
|
import (
|
|
|
|
"reflect"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
|
2022-12-25 04:44:15 +00:00
|
|
|
"google.golang.org/protobuf/internal/encoding/defval"
|
|
|
|
"google.golang.org/protobuf/internal/filedesc"
|
2020-09-09 18:09:42 +00:00
|
|
|
"google.golang.org/protobuf/internal/strs"
|
2022-12-25 04:44:15 +00:00
|
|
|
"google.golang.org/protobuf/reflect/protoreflect"
|
2020-09-09 18:09:42 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var byteType = reflect.TypeOf(byte(0))
|
|
|
|
|
|
|
|
// Unmarshal decodes the tag into a prototype.Field.
|
|
|
|
//
|
|
|
|
// The goType is needed to determine the original protoreflect.Kind since the
|
|
|
|
// tag does not record sufficient information to determine that.
|
|
|
|
// The type is the underlying field type (e.g., a repeated field may be
|
|
|
|
// represented by []T, but the Go type passed in is just T).
|
|
|
|
// A list of enum value descriptors must be provided for enum fields.
|
|
|
|
// This does not populate the Enum or Message (except for weak message).
|
|
|
|
//
|
|
|
|
// This function is a best effort attempt; parsing errors are ignored.
|
2022-12-25 04:44:15 +00:00
|
|
|
func Unmarshal(tag string, goType reflect.Type, evs protoreflect.EnumValueDescriptors) protoreflect.FieldDescriptor {
|
|
|
|
f := new(filedesc.Field)
|
|
|
|
f.L0.ParentFile = filedesc.SurrogateProto2
|
2020-09-09 18:09:42 +00:00
|
|
|
for len(tag) > 0 {
|
|
|
|
i := strings.IndexByte(tag, ',')
|
|
|
|
if i < 0 {
|
|
|
|
i = len(tag)
|
|
|
|
}
|
|
|
|
switch s := tag[:i]; {
|
|
|
|
case strings.HasPrefix(s, "name="):
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L0.FullName = protoreflect.FullName(s[len("name="):])
|
2020-09-09 18:09:42 +00:00
|
|
|
case strings.Trim(s, "0123456789") == "":
|
|
|
|
n, _ := strconv.ParseUint(s, 10, 32)
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L1.Number = protoreflect.FieldNumber(n)
|
2020-09-09 18:09:42 +00:00
|
|
|
case s == "opt":
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L1.Cardinality = protoreflect.Optional
|
2020-09-09 18:09:42 +00:00
|
|
|
case s == "req":
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L1.Cardinality = protoreflect.Required
|
2020-09-09 18:09:42 +00:00
|
|
|
case s == "rep":
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L1.Cardinality = protoreflect.Repeated
|
2020-09-09 18:09:42 +00:00
|
|
|
case s == "varint":
|
|
|
|
switch goType.Kind() {
|
|
|
|
case reflect.Bool:
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L1.Kind = protoreflect.BoolKind
|
2020-09-09 18:09:42 +00:00
|
|
|
case reflect.Int32:
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L1.Kind = protoreflect.Int32Kind
|
2020-09-09 18:09:42 +00:00
|
|
|
case reflect.Int64:
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L1.Kind = protoreflect.Int64Kind
|
2020-09-09 18:09:42 +00:00
|
|
|
case reflect.Uint32:
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L1.Kind = protoreflect.Uint32Kind
|
2020-09-09 18:09:42 +00:00
|
|
|
case reflect.Uint64:
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L1.Kind = protoreflect.Uint64Kind
|
2020-09-09 18:09:42 +00:00
|
|
|
}
|
|
|
|
case s == "zigzag32":
|
|
|
|
if goType.Kind() == reflect.Int32 {
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L1.Kind = protoreflect.Sint32Kind
|
2020-09-09 18:09:42 +00:00
|
|
|
}
|
|
|
|
case s == "zigzag64":
|
|
|
|
if goType.Kind() == reflect.Int64 {
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L1.Kind = protoreflect.Sint64Kind
|
2020-09-09 18:09:42 +00:00
|
|
|
}
|
|
|
|
case s == "fixed32":
|
|
|
|
switch goType.Kind() {
|
|
|
|
case reflect.Int32:
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L1.Kind = protoreflect.Sfixed32Kind
|
2020-09-09 18:09:42 +00:00
|
|
|
case reflect.Uint32:
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L1.Kind = protoreflect.Fixed32Kind
|
2020-09-09 18:09:42 +00:00
|
|
|
case reflect.Float32:
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L1.Kind = protoreflect.FloatKind
|
2020-09-09 18:09:42 +00:00
|
|
|
}
|
|
|
|
case s == "fixed64":
|
|
|
|
switch goType.Kind() {
|
|
|
|
case reflect.Int64:
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L1.Kind = protoreflect.Sfixed64Kind
|
2020-09-09 18:09:42 +00:00
|
|
|
case reflect.Uint64:
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L1.Kind = protoreflect.Fixed64Kind
|
2020-09-09 18:09:42 +00:00
|
|
|
case reflect.Float64:
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L1.Kind = protoreflect.DoubleKind
|
2020-09-09 18:09:42 +00:00
|
|
|
}
|
|
|
|
case s == "bytes":
|
|
|
|
switch {
|
|
|
|
case goType.Kind() == reflect.String:
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L1.Kind = protoreflect.StringKind
|
2020-09-09 18:09:42 +00:00
|
|
|
case goType.Kind() == reflect.Slice && goType.Elem() == byteType:
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L1.Kind = protoreflect.BytesKind
|
2020-09-09 18:09:42 +00:00
|
|
|
default:
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L1.Kind = protoreflect.MessageKind
|
2020-09-09 18:09:42 +00:00
|
|
|
}
|
|
|
|
case s == "group":
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L1.Kind = protoreflect.GroupKind
|
2020-09-09 18:09:42 +00:00
|
|
|
case strings.HasPrefix(s, "enum="):
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L1.Kind = protoreflect.EnumKind
|
2020-09-09 18:09:42 +00:00
|
|
|
case strings.HasPrefix(s, "json="):
|
|
|
|
jsonName := s[len("json="):]
|
|
|
|
if jsonName != strs.JSONCamelCase(string(f.L0.FullName.Name())) {
|
2021-08-27 11:26:00 +00:00
|
|
|
f.L1.StringName.InitJSON(jsonName)
|
2020-09-09 18:09:42 +00:00
|
|
|
}
|
|
|
|
case s == "packed":
|
|
|
|
f.L1.HasPacked = true
|
|
|
|
f.L1.IsPacked = true
|
|
|
|
case strings.HasPrefix(s, "weak="):
|
|
|
|
f.L1.IsWeak = true
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L1.Message = filedesc.PlaceholderMessage(protoreflect.FullName(s[len("weak="):]))
|
2020-09-09 18:09:42 +00:00
|
|
|
case strings.HasPrefix(s, "def="):
|
|
|
|
// The default tag is special in that everything afterwards is the
|
|
|
|
// default regardless of the presence of commas.
|
|
|
|
s, i = tag[len("def="):], len(tag)
|
|
|
|
v, ev, _ := defval.Unmarshal(s, f.L1.Kind, evs, defval.GoTag)
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L1.Default = filedesc.DefaultValue(v, ev)
|
2020-09-09 18:09:42 +00:00
|
|
|
case s == "proto3":
|
2022-12-25 04:44:15 +00:00
|
|
|
f.L0.ParentFile = filedesc.SurrogateProto3
|
2020-09-09 18:09:42 +00:00
|
|
|
}
|
|
|
|
tag = strings.TrimPrefix(tag[i:], ",")
|
|
|
|
}
|
|
|
|
|
|
|
|
// The generator uses the group message name instead of the field name.
|
|
|
|
// We obtain the real field name by lowercasing the group name.
|
2022-12-25 04:44:15 +00:00
|
|
|
if f.L1.Kind == protoreflect.GroupKind {
|
|
|
|
f.L0.FullName = protoreflect.FullName(strings.ToLower(string(f.L0.FullName)))
|
2020-09-09 18:09:42 +00:00
|
|
|
}
|
|
|
|
return f
|
|
|
|
}
|
|
|
|
|
|
|
|
// Marshal encodes the protoreflect.FieldDescriptor as a tag.
|
|
|
|
//
|
|
|
|
// The enumName must be provided if the kind is an enum.
|
|
|
|
// Historically, the formulation of the enum "name" was the proto package
|
|
|
|
// dot-concatenated with the generated Go identifier for the enum type.
|
|
|
|
// Depending on the context on how Marshal is called, there are different ways
|
|
|
|
// through which that information is determined. As such it is the caller's
|
|
|
|
// responsibility to provide a function to obtain that information.
|
2022-12-25 04:44:15 +00:00
|
|
|
func Marshal(fd protoreflect.FieldDescriptor, enumName string) string {
|
2020-09-09 18:09:42 +00:00
|
|
|
var tag []string
|
|
|
|
switch fd.Kind() {
|
2022-12-25 04:44:15 +00:00
|
|
|
case protoreflect.BoolKind, protoreflect.EnumKind, protoreflect.Int32Kind, protoreflect.Uint32Kind, protoreflect.Int64Kind, protoreflect.Uint64Kind:
|
2020-09-09 18:09:42 +00:00
|
|
|
tag = append(tag, "varint")
|
2022-12-25 04:44:15 +00:00
|
|
|
case protoreflect.Sint32Kind:
|
2020-09-09 18:09:42 +00:00
|
|
|
tag = append(tag, "zigzag32")
|
2022-12-25 04:44:15 +00:00
|
|
|
case protoreflect.Sint64Kind:
|
2020-09-09 18:09:42 +00:00
|
|
|
tag = append(tag, "zigzag64")
|
2022-12-25 04:44:15 +00:00
|
|
|
case protoreflect.Sfixed32Kind, protoreflect.Fixed32Kind, protoreflect.FloatKind:
|
2020-09-09 18:09:42 +00:00
|
|
|
tag = append(tag, "fixed32")
|
2022-12-25 04:44:15 +00:00
|
|
|
case protoreflect.Sfixed64Kind, protoreflect.Fixed64Kind, protoreflect.DoubleKind:
|
2020-09-09 18:09:42 +00:00
|
|
|
tag = append(tag, "fixed64")
|
2022-12-25 04:44:15 +00:00
|
|
|
case protoreflect.StringKind, protoreflect.BytesKind, protoreflect.MessageKind:
|
2020-09-09 18:09:42 +00:00
|
|
|
tag = append(tag, "bytes")
|
2022-12-25 04:44:15 +00:00
|
|
|
case protoreflect.GroupKind:
|
2020-09-09 18:09:42 +00:00
|
|
|
tag = append(tag, "group")
|
|
|
|
}
|
|
|
|
tag = append(tag, strconv.Itoa(int(fd.Number())))
|
|
|
|
switch fd.Cardinality() {
|
2022-12-25 04:44:15 +00:00
|
|
|
case protoreflect.Optional:
|
2020-09-09 18:09:42 +00:00
|
|
|
tag = append(tag, "opt")
|
2022-12-25 04:44:15 +00:00
|
|
|
case protoreflect.Required:
|
2020-09-09 18:09:42 +00:00
|
|
|
tag = append(tag, "req")
|
2022-12-25 04:44:15 +00:00
|
|
|
case protoreflect.Repeated:
|
2020-09-09 18:09:42 +00:00
|
|
|
tag = append(tag, "rep")
|
|
|
|
}
|
|
|
|
if fd.IsPacked() {
|
|
|
|
tag = append(tag, "packed")
|
|
|
|
}
|
|
|
|
name := string(fd.Name())
|
2022-12-25 04:44:15 +00:00
|
|
|
if fd.Kind() == protoreflect.GroupKind {
|
2020-09-09 18:09:42 +00:00
|
|
|
// The name of the FieldDescriptor for a group field is
|
|
|
|
// lowercased. To find the original capitalization, we
|
|
|
|
// look in the field's MessageType.
|
|
|
|
name = string(fd.Message().Name())
|
|
|
|
}
|
|
|
|
tag = append(tag, "name="+name)
|
|
|
|
if jsonName := fd.JSONName(); jsonName != "" && jsonName != name && !fd.IsExtension() {
|
|
|
|
// NOTE: The jsonName != name condition is suspect, but it preserve
|
|
|
|
// the exact same semantics from the previous generator.
|
|
|
|
tag = append(tag, "json="+jsonName)
|
|
|
|
}
|
|
|
|
if fd.IsWeak() {
|
|
|
|
tag = append(tag, "weak="+string(fd.Message().FullName()))
|
|
|
|
}
|
|
|
|
// The previous implementation does not tag extension fields as proto3,
|
|
|
|
// even when the field is defined in a proto3 file. Match that behavior
|
|
|
|
// for consistency.
|
2022-12-25 04:44:15 +00:00
|
|
|
if fd.Syntax() == protoreflect.Proto3 && !fd.IsExtension() {
|
2020-09-09 18:09:42 +00:00
|
|
|
tag = append(tag, "proto3")
|
|
|
|
}
|
2022-12-25 04:44:15 +00:00
|
|
|
if fd.Kind() == protoreflect.EnumKind && enumName != "" {
|
2020-09-09 18:09:42 +00:00
|
|
|
tag = append(tag, "enum="+enumName)
|
|
|
|
}
|
|
|
|
if fd.ContainingOneof() != nil {
|
|
|
|
tag = append(tag, "oneof")
|
|
|
|
}
|
|
|
|
// This must appear last in the tag, since commas in strings aren't escaped.
|
|
|
|
if fd.HasDefault() {
|
|
|
|
def, _ := defval.Marshal(fd.Default(), fd.DefaultEnumValue(), fd.Kind(), defval.GoTag)
|
|
|
|
tag = append(tag, "def="+def)
|
|
|
|
}
|
|
|
|
return strings.Join(tag, ",")
|
|
|
|
}
|