blob: 86da5133d470e29e8ff6892831f0b07d5372a091 [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
Damien Neilf5274512019-08-05 10:48:38 -070060var (
61 boolZero = pref.ValueOf(bool(false))
62 int32Zero = pref.ValueOf(int32(0))
63 int64Zero = pref.ValueOf(int64(0))
64 uint32Zero = pref.ValueOf(uint32(0))
65 uint64Zero = pref.ValueOf(uint64(0))
66 float32Zero = pref.ValueOf(float32(0))
67 float64Zero = pref.ValueOf(float64(0))
68 stringZero = pref.ValueOf(string(""))
69 bytesZero = pref.ValueOf([]byte(nil))
70)
71
Damien Neil954bd922019-07-17 16:52:10 -070072type scalarConverter struct {
73 goType, pbType reflect.Type
74 def pref.Value
75}
76
77func newSingularConverter(t reflect.Type, fd pref.FieldDescriptor) Converter {
Damien Neilf5274512019-08-05 10:48:38 -070078 defVal := func(fd pref.FieldDescriptor, zero pref.Value) pref.Value {
79 if fd.Cardinality() == pref.Repeated {
80 // Default isn't defined for repeated fields.
81 return zero
82 }
83 return fd.Default()
84 }
Damien Neil954bd922019-07-17 16:52:10 -070085 switch fd.Kind() {
86 case pref.BoolKind:
87 if t.Kind() == reflect.Bool {
Damien Neilf5274512019-08-05 10:48:38 -070088 return &scalarConverter{t, boolType, defVal(fd, boolZero)}
Damien Neil954bd922019-07-17 16:52:10 -070089 }
90 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
91 if t.Kind() == reflect.Int32 {
Damien Neilf5274512019-08-05 10:48:38 -070092 return &scalarConverter{t, int32Type, defVal(fd, int32Zero)}
Damien Neil954bd922019-07-17 16:52:10 -070093 }
94 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
95 if t.Kind() == reflect.Int64 {
Damien Neilf5274512019-08-05 10:48:38 -070096 return &scalarConverter{t, int64Type, defVal(fd, int64Zero)}
Damien Neil954bd922019-07-17 16:52:10 -070097 }
98 case pref.Uint32Kind, pref.Fixed32Kind:
99 if t.Kind() == reflect.Uint32 {
Damien Neilf5274512019-08-05 10:48:38 -0700100 return &scalarConverter{t, uint32Type, defVal(fd, uint32Zero)}
Damien Neil954bd922019-07-17 16:52:10 -0700101 }
102 case pref.Uint64Kind, pref.Fixed64Kind:
103 if t.Kind() == reflect.Uint64 {
Damien Neilf5274512019-08-05 10:48:38 -0700104 return &scalarConverter{t, uint64Type, defVal(fd, uint64Zero)}
Damien Neil954bd922019-07-17 16:52:10 -0700105 }
106 case pref.FloatKind:
107 if t.Kind() == reflect.Float32 {
Damien Neilf5274512019-08-05 10:48:38 -0700108 return &scalarConverter{t, float32Type, defVal(fd, float32Zero)}
Damien Neil954bd922019-07-17 16:52:10 -0700109 }
110 case pref.DoubleKind:
111 if t.Kind() == reflect.Float64 {
Damien Neilf5274512019-08-05 10:48:38 -0700112 return &scalarConverter{t, float64Type, defVal(fd, float64Zero)}
Damien Neil954bd922019-07-17 16:52:10 -0700113 }
114 case pref.StringKind:
115 if t.Kind() == reflect.String || (t.Kind() == reflect.Slice && t.Elem() == byteType) {
Damien Neilf5274512019-08-05 10:48:38 -0700116 return &scalarConverter{t, stringType, defVal(fd, stringZero)}
Damien Neil954bd922019-07-17 16:52:10 -0700117 }
118 case pref.BytesKind:
119 if t.Kind() == reflect.String || (t.Kind() == reflect.Slice && t.Elem() == byteType) {
Damien Neilf5274512019-08-05 10:48:38 -0700120 return &scalarConverter{t, bytesType, defVal(fd, bytesZero)}
Damien Neil954bd922019-07-17 16:52:10 -0700121 }
122 case pref.EnumKind:
123 // Handle enums, which must be a named int32 type.
124 if t.Kind() == reflect.Int32 {
125 return newEnumConverter(t, fd)
126 }
127 case pref.MessageKind, pref.GroupKind:
128 return newMessageConverter(t)
129 }
130 panic(fmt.Sprintf("invalid Go type %v for field %v", t, fd.FullName()))
131}
132
133func (c *scalarConverter) PBValueOf(v reflect.Value) pref.Value {
134 if v.Type() != c.goType {
135 panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
136 }
137 if c.goType.Kind() == reflect.String && c.pbType.Kind() == reflect.Slice && v.Len() == 0 {
138 return pref.ValueOf([]byte(nil)) // ensure empty string is []byte(nil)
139 }
140 return pref.ValueOf(v.Convert(c.pbType).Interface())
141}
142
143func (c *scalarConverter) GoValueOf(v pref.Value) reflect.Value {
144 rv := reflect.ValueOf(v.Interface())
145 if rv.Type() != c.pbType {
146 panic(fmt.Sprintf("invalid type: got %v, want %v", rv.Type(), c.pbType))
147 }
148 if c.pbType.Kind() == reflect.String && c.goType.Kind() == reflect.Slice && rv.Len() == 0 {
149 return reflect.Zero(c.goType) // ensure empty string is []byte(nil)
150 }
151 return rv.Convert(c.goType)
152}
153
154func (c *scalarConverter) New() pref.Value {
Damien Neilf5274512019-08-05 10:48:38 -0700155 if c.pbType == bytesType {
156 return pref.ValueOf(append(([]byte)(nil), c.def.Bytes()...))
157 }
Damien Neil954bd922019-07-17 16:52:10 -0700158 return c.def
159}
160
161type enumConverter struct {
162 goType reflect.Type
163 def pref.Value
164}
165
166func newEnumConverter(goType reflect.Type, fd pref.FieldDescriptor) Converter {
Damien Neilf5274512019-08-05 10:48:38 -0700167 var def pref.Value
168 if fd.Cardinality() == pref.Repeated {
169 def = pref.ValueOf(fd.Enum().Values().Get(0).Number())
170 } else {
171 def = fd.Default()
172 }
173 return &enumConverter{goType, def}
Damien Neil954bd922019-07-17 16:52:10 -0700174}
175
176func (c *enumConverter) PBValueOf(v reflect.Value) pref.Value {
177 if v.Type() != c.goType {
178 panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
179 }
180 return pref.ValueOf(pref.EnumNumber(v.Int()))
181}
182
183func (c *enumConverter) GoValueOf(v pref.Value) reflect.Value {
184 return reflect.ValueOf(v.Enum()).Convert(c.goType)
185}
186
187func (c *enumConverter) New() pref.Value {
188 return c.def
189}
190
191type messageConverter struct {
192 goType reflect.Type
193}
194
195func newMessageConverter(goType reflect.Type) Converter {
196 return &messageConverter{goType}
197}
198
199func (c *messageConverter) PBValueOf(v reflect.Value) pref.Value {
200 if v.Type() != c.goType {
201 panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
202 }
203 if m, ok := v.Interface().(pref.ProtoMessage); ok {
204 return pref.ValueOf(m.ProtoReflect())
205 }
206 return pref.ValueOf(legacyWrapMessage(v).ProtoReflect())
207}
208
209func (c *messageConverter) GoValueOf(v pref.Value) reflect.Value {
210 m := v.Message()
211 var rv reflect.Value
212 if u, ok := m.(Unwrapper); ok {
213 rv = reflect.ValueOf(u.ProtoUnwrap())
214 } else {
215 rv = reflect.ValueOf(m.Interface())
216 }
217 if rv.Type() != c.goType {
218 panic(fmt.Sprintf("invalid type: got %v, want %v", rv.Type(), c.goType))
219 }
220 return rv
221}
222
223func (c *messageConverter) New() pref.Value {
224 return c.PBValueOf(reflect.New(c.goType.Elem()))
225}