blob: 4b280ef15aa478d5f092843e70ca13069df59268 [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 {
Damien Neild4f08002019-08-07 12:21:41 -070022 // PBValueOf converts a reflect.Value to a protoreflect.Value.
Damien Neil954bd922019-07-17 16:52:10 -070023 PBValueOf(reflect.Value) pref.Value
Damien Neild4f08002019-08-07 12:21:41 -070024
25 // GoValueOf converts a protoreflect.Value to a reflect.Value.
Damien Neil954bd922019-07-17 16:52:10 -070026 GoValueOf(pref.Value) reflect.Value
Damien Neild4f08002019-08-07 12:21:41 -070027
28 // New returns a new field value.
29 // For scalars, it returns the default value of the field.
30 // For composite types, it returns a new mutable value.
Damien Neil954bd922019-07-17 16:52:10 -070031 New() pref.Value
Damien Neild4f08002019-08-07 12:21:41 -070032
33 // Zero returns a new field value.
34 // For scalars, it returns the default value of the field.
35 // For composite types, it returns an immutable, empty value.
36 Zero() pref.Value
Damien Neil954bd922019-07-17 16:52:10 -070037}
38
39// NewConverter matches a Go type with a protobuf field and returns a Converter
40// that converts between the two. Enums must be a named int32 kind that
41// implements protoreflect.Enum, and messages must be pointer to a named
42// struct type that implements protoreflect.ProtoMessage.
43//
44// This matcher deliberately supports a wider range of Go types than what
45// protoc-gen-go historically generated to be able to automatically wrap some
46// v1 messages generated by other forks of protoc-gen-go.
47func NewConverter(t reflect.Type, fd pref.FieldDescriptor) Converter {
48 switch {
49 case fd.IsList():
50 return newListConverter(t, fd)
51 case fd.IsMap():
52 return newMapConverter(t, fd)
53 default:
54 return newSingularConverter(t, fd)
55 }
56 panic(fmt.Sprintf("invalid Go type %v for field %v", t, fd.FullName()))
57}
58
59var (
60 boolType = reflect.TypeOf(bool(false))
61 int32Type = reflect.TypeOf(int32(0))
62 int64Type = reflect.TypeOf(int64(0))
63 uint32Type = reflect.TypeOf(uint32(0))
64 uint64Type = reflect.TypeOf(uint64(0))
65 float32Type = reflect.TypeOf(float32(0))
66 float64Type = reflect.TypeOf(float64(0))
67 stringType = reflect.TypeOf(string(""))
68 bytesType = reflect.TypeOf([]byte(nil))
69 byteType = reflect.TypeOf(byte(0))
70)
71
Damien Neilf5274512019-08-05 10:48:38 -070072var (
73 boolZero = pref.ValueOf(bool(false))
74 int32Zero = pref.ValueOf(int32(0))
75 int64Zero = pref.ValueOf(int64(0))
76 uint32Zero = pref.ValueOf(uint32(0))
77 uint64Zero = pref.ValueOf(uint64(0))
78 float32Zero = pref.ValueOf(float32(0))
79 float64Zero = pref.ValueOf(float64(0))
80 stringZero = pref.ValueOf(string(""))
81 bytesZero = pref.ValueOf([]byte(nil))
82)
83
Damien Neil954bd922019-07-17 16:52:10 -070084type scalarConverter struct {
85 goType, pbType reflect.Type
86 def pref.Value
87}
88
89func newSingularConverter(t reflect.Type, fd pref.FieldDescriptor) Converter {
Damien Neilf5274512019-08-05 10:48:38 -070090 defVal := func(fd pref.FieldDescriptor, zero pref.Value) pref.Value {
91 if fd.Cardinality() == pref.Repeated {
92 // Default isn't defined for repeated fields.
93 return zero
94 }
95 return fd.Default()
96 }
Damien Neil954bd922019-07-17 16:52:10 -070097 switch fd.Kind() {
98 case pref.BoolKind:
99 if t.Kind() == reflect.Bool {
Damien Neilf5274512019-08-05 10:48:38 -0700100 return &scalarConverter{t, boolType, defVal(fd, boolZero)}
Damien Neil954bd922019-07-17 16:52:10 -0700101 }
102 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
103 if t.Kind() == reflect.Int32 {
Damien Neilf5274512019-08-05 10:48:38 -0700104 return &scalarConverter{t, int32Type, defVal(fd, int32Zero)}
Damien Neil954bd922019-07-17 16:52:10 -0700105 }
106 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
107 if t.Kind() == reflect.Int64 {
Damien Neilf5274512019-08-05 10:48:38 -0700108 return &scalarConverter{t, int64Type, defVal(fd, int64Zero)}
Damien Neil954bd922019-07-17 16:52:10 -0700109 }
110 case pref.Uint32Kind, pref.Fixed32Kind:
111 if t.Kind() == reflect.Uint32 {
Damien Neilf5274512019-08-05 10:48:38 -0700112 return &scalarConverter{t, uint32Type, defVal(fd, uint32Zero)}
Damien Neil954bd922019-07-17 16:52:10 -0700113 }
114 case pref.Uint64Kind, pref.Fixed64Kind:
115 if t.Kind() == reflect.Uint64 {
Damien Neilf5274512019-08-05 10:48:38 -0700116 return &scalarConverter{t, uint64Type, defVal(fd, uint64Zero)}
Damien Neil954bd922019-07-17 16:52:10 -0700117 }
118 case pref.FloatKind:
119 if t.Kind() == reflect.Float32 {
Damien Neilf5274512019-08-05 10:48:38 -0700120 return &scalarConverter{t, float32Type, defVal(fd, float32Zero)}
Damien Neil954bd922019-07-17 16:52:10 -0700121 }
122 case pref.DoubleKind:
123 if t.Kind() == reflect.Float64 {
Damien Neilf5274512019-08-05 10:48:38 -0700124 return &scalarConverter{t, float64Type, defVal(fd, float64Zero)}
Damien Neil954bd922019-07-17 16:52:10 -0700125 }
126 case pref.StringKind:
127 if t.Kind() == reflect.String || (t.Kind() == reflect.Slice && t.Elem() == byteType) {
Damien Neilf5274512019-08-05 10:48:38 -0700128 return &scalarConverter{t, stringType, defVal(fd, stringZero)}
Damien Neil954bd922019-07-17 16:52:10 -0700129 }
130 case pref.BytesKind:
131 if t.Kind() == reflect.String || (t.Kind() == reflect.Slice && t.Elem() == byteType) {
Damien Neilf5274512019-08-05 10:48:38 -0700132 return &scalarConverter{t, bytesType, defVal(fd, bytesZero)}
Damien Neil954bd922019-07-17 16:52:10 -0700133 }
134 case pref.EnumKind:
135 // Handle enums, which must be a named int32 type.
136 if t.Kind() == reflect.Int32 {
137 return newEnumConverter(t, fd)
138 }
139 case pref.MessageKind, pref.GroupKind:
140 return newMessageConverter(t)
141 }
142 panic(fmt.Sprintf("invalid Go type %v for field %v", t, fd.FullName()))
143}
144
145func (c *scalarConverter) PBValueOf(v reflect.Value) pref.Value {
146 if v.Type() != c.goType {
147 panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
148 }
149 if c.goType.Kind() == reflect.String && c.pbType.Kind() == reflect.Slice && v.Len() == 0 {
150 return pref.ValueOf([]byte(nil)) // ensure empty string is []byte(nil)
151 }
152 return pref.ValueOf(v.Convert(c.pbType).Interface())
153}
154
155func (c *scalarConverter) GoValueOf(v pref.Value) reflect.Value {
156 rv := reflect.ValueOf(v.Interface())
157 if rv.Type() != c.pbType {
158 panic(fmt.Sprintf("invalid type: got %v, want %v", rv.Type(), c.pbType))
159 }
160 if c.pbType.Kind() == reflect.String && c.goType.Kind() == reflect.Slice && rv.Len() == 0 {
161 return reflect.Zero(c.goType) // ensure empty string is []byte(nil)
162 }
163 return rv.Convert(c.goType)
164}
165
166func (c *scalarConverter) New() pref.Value {
Damien Neilf5274512019-08-05 10:48:38 -0700167 if c.pbType == bytesType {
168 return pref.ValueOf(append(([]byte)(nil), c.def.Bytes()...))
169 }
Damien Neil954bd922019-07-17 16:52:10 -0700170 return c.def
171}
172
Damien Neild4f08002019-08-07 12:21:41 -0700173func (c *scalarConverter) Zero() pref.Value {
174 return c.New()
175}
176
Damien Neil954bd922019-07-17 16:52:10 -0700177type enumConverter struct {
178 goType reflect.Type
179 def pref.Value
180}
181
182func newEnumConverter(goType reflect.Type, fd pref.FieldDescriptor) Converter {
Damien Neilf5274512019-08-05 10:48:38 -0700183 var def pref.Value
184 if fd.Cardinality() == pref.Repeated {
185 def = pref.ValueOf(fd.Enum().Values().Get(0).Number())
186 } else {
187 def = fd.Default()
188 }
189 return &enumConverter{goType, def}
Damien Neil954bd922019-07-17 16:52:10 -0700190}
191
192func (c *enumConverter) PBValueOf(v reflect.Value) pref.Value {
193 if v.Type() != c.goType {
194 panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
195 }
196 return pref.ValueOf(pref.EnumNumber(v.Int()))
197}
198
199func (c *enumConverter) GoValueOf(v pref.Value) reflect.Value {
200 return reflect.ValueOf(v.Enum()).Convert(c.goType)
201}
202
203func (c *enumConverter) New() pref.Value {
204 return c.def
205}
206
Damien Neild4f08002019-08-07 12:21:41 -0700207func (c *enumConverter) Zero() pref.Value {
208 return c.def
209}
210
Damien Neil954bd922019-07-17 16:52:10 -0700211type messageConverter struct {
212 goType reflect.Type
213}
214
215func newMessageConverter(goType reflect.Type) Converter {
216 return &messageConverter{goType}
217}
218
219func (c *messageConverter) PBValueOf(v reflect.Value) pref.Value {
220 if v.Type() != c.goType {
221 panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
222 }
223 if m, ok := v.Interface().(pref.ProtoMessage); ok {
224 return pref.ValueOf(m.ProtoReflect())
225 }
226 return pref.ValueOf(legacyWrapMessage(v).ProtoReflect())
227}
228
229func (c *messageConverter) GoValueOf(v pref.Value) reflect.Value {
230 m := v.Message()
231 var rv reflect.Value
232 if u, ok := m.(Unwrapper); ok {
233 rv = reflect.ValueOf(u.ProtoUnwrap())
234 } else {
235 rv = reflect.ValueOf(m.Interface())
236 }
237 if rv.Type() != c.goType {
238 panic(fmt.Sprintf("invalid type: got %v, want %v", rv.Type(), c.goType))
239 }
240 return rv
241}
242
243func (c *messageConverter) New() pref.Value {
244 return c.PBValueOf(reflect.New(c.goType.Elem()))
245}
Damien Neild4f08002019-08-07 12:21:41 -0700246
247func (c *messageConverter) Zero() pref.Value {
248 return c.PBValueOf(reflect.Zero(c.goType))
249}