blob: 9016fa44b0d955372b32a78397cfba8808fa508b [file] [log] [blame]
Damien Neil954bd922019-07-17 16:52:10 -07001// Copyright 2018 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package impl
6
7import (
8 "fmt"
9 "reflect"
10
11 pref "google.golang.org/protobuf/reflect/protoreflect"
12)
13
14// Unwrapper unwraps the value to the underlying value.
15// This is implemented by List and Map.
16type Unwrapper interface {
17 ProtoUnwrap() interface{}
18}
19
20// A Converter coverts to/from Go reflect.Value types and protobuf protoreflect.Value types.
21type Converter interface {
22 PBValueOf(reflect.Value) pref.Value
23 GoValueOf(pref.Value) reflect.Value
24 New() pref.Value
25}
26
27// NewConverter matches a Go type with a protobuf field and returns a Converter
28// that converts between the two. Enums must be a named int32 kind that
29// implements protoreflect.Enum, and messages must be pointer to a named
30// struct type that implements protoreflect.ProtoMessage.
31//
32// This matcher deliberately supports a wider range of Go types than what
33// protoc-gen-go historically generated to be able to automatically wrap some
34// v1 messages generated by other forks of protoc-gen-go.
35func NewConverter(t reflect.Type, fd pref.FieldDescriptor) Converter {
36 switch {
37 case fd.IsList():
38 return newListConverter(t, fd)
39 case fd.IsMap():
40 return newMapConverter(t, fd)
41 default:
42 return newSingularConverter(t, fd)
43 }
44 panic(fmt.Sprintf("invalid Go type %v for field %v", t, fd.FullName()))
45}
46
47var (
48 boolType = reflect.TypeOf(bool(false))
49 int32Type = reflect.TypeOf(int32(0))
50 int64Type = reflect.TypeOf(int64(0))
51 uint32Type = reflect.TypeOf(uint32(0))
52 uint64Type = reflect.TypeOf(uint64(0))
53 float32Type = reflect.TypeOf(float32(0))
54 float64Type = reflect.TypeOf(float64(0))
55 stringType = reflect.TypeOf(string(""))
56 bytesType = reflect.TypeOf([]byte(nil))
57 byteType = reflect.TypeOf(byte(0))
58)
59
60type scalarConverter struct {
61 goType, pbType reflect.Type
62 def pref.Value
63}
64
65func newSingularConverter(t reflect.Type, fd pref.FieldDescriptor) Converter {
66 switch fd.Kind() {
67 case pref.BoolKind:
68 if t.Kind() == reflect.Bool {
69 return &scalarConverter{t, boolType, fd.Default()}
70 }
71 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
72 if t.Kind() == reflect.Int32 {
73 return &scalarConverter{t, int32Type, fd.Default()}
74 }
75 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
76 if t.Kind() == reflect.Int64 {
77 return &scalarConverter{t, int64Type, fd.Default()}
78 }
79 case pref.Uint32Kind, pref.Fixed32Kind:
80 if t.Kind() == reflect.Uint32 {
81 return &scalarConverter{t, uint32Type, fd.Default()}
82 }
83 case pref.Uint64Kind, pref.Fixed64Kind:
84 if t.Kind() == reflect.Uint64 {
85 return &scalarConverter{t, uint64Type, fd.Default()}
86 }
87 case pref.FloatKind:
88 if t.Kind() == reflect.Float32 {
89 return &scalarConverter{t, float32Type, fd.Default()}
90 }
91 case pref.DoubleKind:
92 if t.Kind() == reflect.Float64 {
93 return &scalarConverter{t, float64Type, fd.Default()}
94 }
95 case pref.StringKind:
96 if t.Kind() == reflect.String || (t.Kind() == reflect.Slice && t.Elem() == byteType) {
97 return &scalarConverter{t, stringType, fd.Default()}
98 }
99 case pref.BytesKind:
100 if t.Kind() == reflect.String || (t.Kind() == reflect.Slice && t.Elem() == byteType) {
101 return &scalarConverter{t, bytesType, fd.Default()}
102 }
103 case pref.EnumKind:
104 // Handle enums, which must be a named int32 type.
105 if t.Kind() == reflect.Int32 {
106 return newEnumConverter(t, fd)
107 }
108 case pref.MessageKind, pref.GroupKind:
109 return newMessageConverter(t)
110 }
111 panic(fmt.Sprintf("invalid Go type %v for field %v", t, fd.FullName()))
112}
113
114func (c *scalarConverter) PBValueOf(v reflect.Value) pref.Value {
115 if v.Type() != c.goType {
116 panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
117 }
118 if c.goType.Kind() == reflect.String && c.pbType.Kind() == reflect.Slice && v.Len() == 0 {
119 return pref.ValueOf([]byte(nil)) // ensure empty string is []byte(nil)
120 }
121 return pref.ValueOf(v.Convert(c.pbType).Interface())
122}
123
124func (c *scalarConverter) GoValueOf(v pref.Value) reflect.Value {
125 rv := reflect.ValueOf(v.Interface())
126 if rv.Type() != c.pbType {
127 panic(fmt.Sprintf("invalid type: got %v, want %v", rv.Type(), c.pbType))
128 }
129 if c.pbType.Kind() == reflect.String && c.goType.Kind() == reflect.Slice && rv.Len() == 0 {
130 return reflect.Zero(c.goType) // ensure empty string is []byte(nil)
131 }
132 return rv.Convert(c.goType)
133}
134
135func (c *scalarConverter) New() pref.Value {
136 return c.def
137}
138
139type enumConverter struct {
140 goType reflect.Type
141 def pref.Value
142}
143
144func newEnumConverter(goType reflect.Type, fd pref.FieldDescriptor) Converter {
145 return &enumConverter{goType, fd.Default()}
146}
147
148func (c *enumConverter) PBValueOf(v reflect.Value) pref.Value {
149 if v.Type() != c.goType {
150 panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
151 }
152 return pref.ValueOf(pref.EnumNumber(v.Int()))
153}
154
155func (c *enumConverter) GoValueOf(v pref.Value) reflect.Value {
156 return reflect.ValueOf(v.Enum()).Convert(c.goType)
157}
158
159func (c *enumConverter) New() pref.Value {
160 return c.def
161}
162
163type messageConverter struct {
164 goType reflect.Type
165}
166
167func newMessageConverter(goType reflect.Type) Converter {
168 return &messageConverter{goType}
169}
170
171func (c *messageConverter) PBValueOf(v reflect.Value) pref.Value {
172 if v.Type() != c.goType {
173 panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
174 }
175 if m, ok := v.Interface().(pref.ProtoMessage); ok {
176 return pref.ValueOf(m.ProtoReflect())
177 }
178 return pref.ValueOf(legacyWrapMessage(v).ProtoReflect())
179}
180
181func (c *messageConverter) GoValueOf(v pref.Value) reflect.Value {
182 m := v.Message()
183 var rv reflect.Value
184 if u, ok := m.(Unwrapper); ok {
185 rv = reflect.ValueOf(u.ProtoUnwrap())
186 } else {
187 rv = reflect.ValueOf(m.Interface())
188 }
189 if rv.Type() != c.goType {
190 panic(fmt.Sprintf("invalid type: got %v, want %v", rv.Type(), c.goType))
191 }
192 return rv
193}
194
195func (c *messageConverter) New() pref.Value {
196 return c.PBValueOf(reflect.New(c.goType.Elem()))
197}