blob: d4531c05638476154df3c388fbae13406913c488 [file] [log] [blame]
Rob Pikeaaa3a622010-03-20 22:32:34 -07001// Go support for Protocol Buffers - Google's data interchange format
2//
David Symondsee6e9c52012-11-29 08:51:07 +11003// Copyright 2010 The Go Authors. All rights reserved.
David Symonds558f13f2014-11-24 10:28:53 +11004// https://github.com/golang/protobuf
Rob Pikeaaa3a622010-03-20 22:32:34 -07005//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are
8// met:
9//
10// * Redistributions of source code must retain the above copyright
11// notice, this list of conditions and the following disclaimer.
12// * Redistributions in binary form must reproduce the above
13// copyright notice, this list of conditions and the following disclaimer
14// in the documentation and/or other materials provided with the
15// distribution.
16// * Neither the name of Google Inc. nor the names of its
17// contributors may be used to endorse or promote products derived from
18// this software without specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32package proto
33
34/*
35 * Routines for encoding data into the wire format for protocol buffers.
36 */
37
38import (
39 "fmt"
David Symondsa7f1e752015-11-02 15:31:00 +110040 "log"
Rob Pikeaaa3a622010-03-20 22:32:34 -070041 "os"
42 "reflect"
David Symondsd15e81b2011-10-03 14:31:12 -070043 "sort"
Rob Pikeaaa3a622010-03-20 22:32:34 -070044 "strconv"
45 "strings"
46 "sync"
Rob Pikeaaa3a622010-03-20 22:32:34 -070047)
48
49const debug bool = false
50
51// Constants that identify the encoding of a value on the wire.
52const (
53 WireVarint = 0
54 WireFixed64 = 1
55 WireBytes = 2
56 WireStartGroup = 3
57 WireEndGroup = 4
58 WireFixed32 = 5
59)
60
61const startSize = 10 // initial slice/string sizes
62
David Symonds0bf1ad52013-10-11 09:07:50 +110063// Encoders are defined in encode.go
Rob Pikeaaa3a622010-03-20 22:32:34 -070064// An encoder outputs the full representation of a field, including its
65// tag and encoder type.
Russ Coxd4ce3f12012-09-12 10:36:26 +100066type encoder func(p *Buffer, prop *Properties, base structPointer) error
Rob Pikeaaa3a622010-03-20 22:32:34 -070067
68// A valueEncoder encodes a single integer in a particular encoding.
Rob Pikea17fdd92011-11-02 12:43:05 -070069type valueEncoder func(o *Buffer, x uint64) error
Rob Pikeaaa3a622010-03-20 22:32:34 -070070
David Symonds0bf1ad52013-10-11 09:07:50 +110071// Sizers are defined in encode.go
72// A sizer returns the encoded size of a field, including its tag and encoder
73// type.
74type sizer func(prop *Properties, base structPointer) int
75
76// A valueSizer returns the encoded size of a single integer in a particular
77// encoding.
78type valueSizer func(x uint64) int
79
Rob Pikeaaa3a622010-03-20 22:32:34 -070080// Decoders are defined in decode.go
81// A decoder creates a value from its wire representation.
82// Unrecognized subelements are saved in unrec.
Russ Coxd4ce3f12012-09-12 10:36:26 +100083type decoder func(p *Buffer, prop *Properties, base structPointer) error
Rob Pikeaaa3a622010-03-20 22:32:34 -070084
85// A valueDecoder decodes a single integer in a particular encoding.
Rob Pikea17fdd92011-11-02 12:43:05 -070086type valueDecoder func(o *Buffer) (x uint64, err error)
Rob Pikeaaa3a622010-03-20 22:32:34 -070087
David Symonds59b73b32015-08-24 13:22:02 +100088// A oneofMarshaler does the marshaling for all oneof fields in a message.
89type oneofMarshaler func(Message, *Buffer) error
90
91// A oneofUnmarshaler does the unmarshaling for a oneof field in a message.
92type oneofUnmarshaler func(Message, int, int, *Buffer) (bool, error)
93
Damien Neil08794902015-12-04 07:39:00 +110094// A oneofSizer does the sizing for all oneof fields in a message.
95type oneofSizer func(Message) int
96
David Symonds6a6f82c2012-08-22 09:18:54 +100097// tagMap is an optimization over map[int]int for typical protocol buffer
98// use-cases. Encoded protocol buffers are often in tag order with small tag
99// numbers.
100type tagMap struct {
101 fastTags []int
102 slowTags map[int]int
103}
104
105// tagMapFastLimit is the upper bound on the tag number that will be stored in
106// the tagMap slice rather than its map.
107const tagMapFastLimit = 1024
108
109func (p *tagMap) get(t int) (int, bool) {
110 if t > 0 && t < tagMapFastLimit {
111 if t >= len(p.fastTags) {
112 return 0, false
113 }
114 fi := p.fastTags[t]
115 return fi, fi >= 0
116 }
117 fi, ok := p.slowTags[t]
118 return fi, ok
119}
120
121func (p *tagMap) put(t int, fi int) {
122 if t > 0 && t < tagMapFastLimit {
123 for len(p.fastTags) < t+1 {
124 p.fastTags = append(p.fastTags, -1)
125 }
126 p.fastTags[t] = fi
127 return
128 }
129 if p.slowTags == nil {
130 p.slowTags = make(map[int]int)
131 }
132 p.slowTags[t] = fi
133}
134
Rob Pikeaaa3a622010-03-20 22:32:34 -0700135// StructProperties represents properties for all the fields of a struct.
David Symonds2bba1b22012-09-26 14:53:08 +1000136// decoderTags and decoderOrigNames should only be used by the decoder.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700137type StructProperties struct {
David Symonds2bba1b22012-09-26 14:53:08 +1000138 Prop []*Properties // properties for each field
139 reqCount int // required count
140 decoderTags tagMap // map from proto tag to struct field number
141 decoderOrigNames map[string]int // map from original name to struct field number
142 order []int // list of struct field numbers in tag order
143 unrecField field // field id of the XXX_unrecognized []byte field
144 extendable bool // is this an extendable proto
David Symonds59b73b32015-08-24 13:22:02 +1000145
146 oneofMarshaler oneofMarshaler
147 oneofUnmarshaler oneofUnmarshaler
Damien Neil08794902015-12-04 07:39:00 +1100148 oneofSizer oneofSizer
David Symonds59b73b32015-08-24 13:22:02 +1000149 stype reflect.Type
David Symonds1baed092015-08-25 15:42:00 +1000150
151 // OneofTypes contains information about the oneof fields in this message.
152 // It is keyed by the original name of a field.
153 OneofTypes map[string]*OneofProperties
154}
155
156// OneofProperties represents information about a specific field in a oneof.
157type OneofProperties struct {
158 Type reflect.Type // pointer to generated struct type for this oneof field
159 Field int // struct field number of the containing oneof in the message
160 Prop *Properties
Rob Pikeaaa3a622010-03-20 22:32:34 -0700161}
162
David Symondsd15e81b2011-10-03 14:31:12 -0700163// Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec.
David Symonds0bf1ad52013-10-11 09:07:50 +1100164// See encode.go, (*Buffer).enc_struct.
David Symondsd15e81b2011-10-03 14:31:12 -0700165
166func (sp *StructProperties) Len() int { return len(sp.order) }
167func (sp *StructProperties) Less(i, j int) bool {
168 return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag
169}
170func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] }
171
Rob Pikeaaa3a622010-03-20 22:32:34 -0700172// Properties represents the protocol-specific behavior of a single struct field.
173type Properties struct {
David Symonds7e810982014-08-12 13:11:17 +1000174 Name string // name of the field, for error messages
175 OrigName string // original name before protocol compiler (always set)
176 Wire string
177 WireType int
178 Tag int
179 Required bool
180 Optional bool
181 Repeated bool
182 Packed bool // relevant for repeated primitives only
183 Enum string // set for enum types only
David Symondsabd3b412014-11-28 11:43:44 +1100184 proto3 bool // whether this is known to be a proto3 field; set for []byte only
David Symonds535a1042015-09-11 08:27:00 +1000185 oneof bool // whether this is a oneof field
David Symonds7e810982014-08-12 13:11:17 +1000186
Rob Pikeaaa3a622010-03-20 22:32:34 -0700187 Default string // default value
David Symonds7e810982014-08-12 13:11:17 +1000188 HasDefault bool // whether an explicit default was provided
Rob Pikeaaa3a622010-03-20 22:32:34 -0700189 def_uint64 uint64
190
David Symondsa80b2822012-03-14 14:31:25 +1100191 enc encoder
192 valEnc valueEncoder // set for bool and numeric types only
Russ Coxd4ce3f12012-09-12 10:36:26 +1000193 field field
David Symondsa80b2822012-03-14 14:31:25 +1100194 tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType)
195 tagbuf [8]byte
David Symondsc0287172012-08-15 11:10:30 +1000196 stype reflect.Type // set for struct types only
197 sprop *StructProperties // set for struct types only
David Symondsa80b2822012-03-14 14:31:25 +1100198 isMarshaler bool
199 isUnmarshaler bool
Rob Pikeaaa3a622010-03-20 22:32:34 -0700200
David Symonds3ea3e052014-12-22 16:15:28 +1100201 mtype reflect.Type // set for map types only
202 mkeyprop *Properties // set for map types only
203 mvalprop *Properties // set for map types only
204
David Symonds0bf1ad52013-10-11 09:07:50 +1100205 size sizer
206 valSize valueSizer // set for bool and numeric types only
207
David Symonds049646b2011-10-21 11:13:45 +1100208 dec decoder
209 valDec valueDecoder // set for bool and numeric types only
David Symonds5b7775e2010-12-01 10:09:04 +1100210
211 // If this is a packable field, this will be the decoder for the packed version of the field.
212 packedDec decoder
Rob Pikeaaa3a622010-03-20 22:32:34 -0700213}
214
David Symonds8935abf2011-07-04 15:53:16 +1000215// String formats the properties in the protobuf struct field tag style.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700216func (p *Properties) String() string {
217 s := p.Wire
218 s = ","
219 s += strconv.Itoa(p.Tag)
220 if p.Required {
221 s += ",req"
222 }
223 if p.Optional {
224 s += ",opt"
225 }
226 if p.Repeated {
227 s += ",rep"
228 }
David Symonds5b7775e2010-12-01 10:09:04 +1100229 if p.Packed {
230 s += ",packed"
231 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700232 if p.OrigName != p.Name {
233 s += ",name=" + p.OrigName
234 }
David Symondsabd3b412014-11-28 11:43:44 +1100235 if p.proto3 {
236 s += ",proto3"
237 }
David Symonds535a1042015-09-11 08:27:00 +1000238 if p.oneof {
239 s += ",oneof"
240 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700241 if len(p.Enum) > 0 {
242 s += ",enum=" + p.Enum
243 }
David Symonds7e810982014-08-12 13:11:17 +1000244 if p.HasDefault {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700245 s += ",def=" + p.Default
246 }
247 return s
248}
249
David Symonds8935abf2011-07-04 15:53:16 +1000250// Parse populates p by parsing a string in the protobuf struct field tag style.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700251func (p *Properties) Parse(s string) {
David Symondsa7e9ef92012-01-18 18:27:58 +1100252 // "bytes,49,opt,name=foo,def=hello!"
David Symonds8935abf2011-07-04 15:53:16 +1000253 fields := strings.Split(s, ",") // breaks def=, but handled below.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700254 if len(fields) < 2 {
255 fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s)
256 return
257 }
258
259 p.Wire = fields[0]
260 switch p.Wire {
261 case "varint":
262 p.WireType = WireVarint
263 p.valEnc = (*Buffer).EncodeVarint
264 p.valDec = (*Buffer).DecodeVarint
David Symonds0bf1ad52013-10-11 09:07:50 +1100265 p.valSize = sizeVarint
Rob Pikeaaa3a622010-03-20 22:32:34 -0700266 case "fixed32":
267 p.WireType = WireFixed32
268 p.valEnc = (*Buffer).EncodeFixed32
269 p.valDec = (*Buffer).DecodeFixed32
David Symonds0bf1ad52013-10-11 09:07:50 +1100270 p.valSize = sizeFixed32
Rob Pikeaaa3a622010-03-20 22:32:34 -0700271 case "fixed64":
272 p.WireType = WireFixed64
273 p.valEnc = (*Buffer).EncodeFixed64
274 p.valDec = (*Buffer).DecodeFixed64
David Symonds0bf1ad52013-10-11 09:07:50 +1100275 p.valSize = sizeFixed64
Rob Pikeaaa3a622010-03-20 22:32:34 -0700276 case "zigzag32":
277 p.WireType = WireVarint
278 p.valEnc = (*Buffer).EncodeZigzag32
279 p.valDec = (*Buffer).DecodeZigzag32
David Symonds0bf1ad52013-10-11 09:07:50 +1100280 p.valSize = sizeZigzag32
Rob Pikeaaa3a622010-03-20 22:32:34 -0700281 case "zigzag64":
282 p.WireType = WireVarint
283 p.valEnc = (*Buffer).EncodeZigzag64
284 p.valDec = (*Buffer).DecodeZigzag64
David Symonds0bf1ad52013-10-11 09:07:50 +1100285 p.valSize = sizeZigzag64
Rob Pikeaaa3a622010-03-20 22:32:34 -0700286 case "bytes", "group":
287 p.WireType = WireBytes
288 // no numeric converter for non-numeric types
289 default:
290 fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s)
291 return
292 }
293
Rob Pikea17fdd92011-11-02 12:43:05 -0700294 var err error
Rob Pikeaaa3a622010-03-20 22:32:34 -0700295 p.Tag, err = strconv.Atoi(fields[1])
296 if err != nil {
297 return
298 }
299
300 for i := 2; i < len(fields); i++ {
301 f := fields[i]
302 switch {
303 case f == "req":
304 p.Required = true
305 case f == "opt":
306 p.Optional = true
307 case f == "rep":
308 p.Repeated = true
David Symonds5b7775e2010-12-01 10:09:04 +1100309 case f == "packed":
310 p.Packed = true
David Symondsa7e9ef92012-01-18 18:27:58 +1100311 case strings.HasPrefix(f, "name="):
Albert Strasheim4676f6a2013-04-07 08:59:06 +1000312 p.OrigName = f[5:]
David Symondsa7e9ef92012-01-18 18:27:58 +1100313 case strings.HasPrefix(f, "enum="):
Albert Strasheim4676f6a2013-04-07 08:59:06 +1000314 p.Enum = f[5:]
David Symondsabd3b412014-11-28 11:43:44 +1100315 case f == "proto3":
316 p.proto3 = true
David Symonds535a1042015-09-11 08:27:00 +1000317 case f == "oneof":
318 p.oneof = true
David Symondsa7e9ef92012-01-18 18:27:58 +1100319 case strings.HasPrefix(f, "def="):
David Symonds7e810982014-08-12 13:11:17 +1000320 p.HasDefault = true
Albert Strasheim4676f6a2013-04-07 08:59:06 +1000321 p.Default = f[4:] // rest of string
Rob Pikeaaa3a622010-03-20 22:32:34 -0700322 if i+1 < len(fields) {
323 // Commas aren't escaped, and def is always last.
Albert Strasheim4676f6a2013-04-07 08:59:06 +1000324 p.Default += "," + strings.Join(fields[i+1:], ",")
Rob Pikeaaa3a622010-03-20 22:32:34 -0700325 break
326 }
327 }
328 }
329}
330
David Symonds5922d072011-06-22 15:48:09 +1000331func logNoSliceEnc(t1, t2 reflect.Type) {
332 fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2)
333}
334
David Symonds525838c2012-07-20 15:42:49 +1000335var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem()
336
Rob Pikeaaa3a622010-03-20 22:32:34 -0700337// Initialize the fields for encoding and decoding.
David Symonds3ea3e052014-12-22 16:15:28 +1100338func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lockGetProp bool) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700339 p.enc = nil
340 p.dec = nil
David Symonds0bf1ad52013-10-11 09:07:50 +1100341 p.size = nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700342
Rob Pike97e934d2011-04-11 12:52:49 -0700343 switch t1 := typ; t1.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700344 default:
David Symonds50386d22014-10-28 11:00:50 +1100345 fmt.Fprintf(os.Stderr, "proto: no coders for %v\n", t1)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700346
David Symondsabd3b412014-11-28 11:43:44 +1100347 // proto3 scalar types
348
349 case reflect.Bool:
350 p.enc = (*Buffer).enc_proto3_bool
351 p.dec = (*Buffer).dec_proto3_bool
352 p.size = size_proto3_bool
353 case reflect.Int32:
354 p.enc = (*Buffer).enc_proto3_int32
355 p.dec = (*Buffer).dec_proto3_int32
356 p.size = size_proto3_int32
357 case reflect.Uint32:
358 p.enc = (*Buffer).enc_proto3_uint32
359 p.dec = (*Buffer).dec_proto3_int32 // can reuse
360 p.size = size_proto3_uint32
361 case reflect.Int64, reflect.Uint64:
362 p.enc = (*Buffer).enc_proto3_int64
363 p.dec = (*Buffer).dec_proto3_int64
364 p.size = size_proto3_int64
365 case reflect.Float32:
366 p.enc = (*Buffer).enc_proto3_uint32 // can just treat them as bits
367 p.dec = (*Buffer).dec_proto3_int32
368 p.size = size_proto3_uint32
369 case reflect.Float64:
370 p.enc = (*Buffer).enc_proto3_int64 // can just treat them as bits
371 p.dec = (*Buffer).dec_proto3_int64
372 p.size = size_proto3_int64
373 case reflect.String:
374 p.enc = (*Buffer).enc_proto3_string
375 p.dec = (*Buffer).dec_proto3_string
376 p.size = size_proto3_string
377
Rob Pike97e934d2011-04-11 12:52:49 -0700378 case reflect.Ptr:
379 switch t2 := t1.Elem(); t2.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700380 default:
David Symonds3ea3e052014-12-22 16:15:28 +1100381 fmt.Fprintf(os.Stderr, "proto: no encoder function for %v -> %v\n", t1, t2)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700382 break
Rob Pike97e934d2011-04-11 12:52:49 -0700383 case reflect.Bool:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700384 p.enc = (*Buffer).enc_bool
385 p.dec = (*Buffer).dec_bool
David Symonds0bf1ad52013-10-11 09:07:50 +1100386 p.size = size_bool
David Symondsf054e842014-07-22 14:06:27 +1000387 case reflect.Int32:
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700388 p.enc = (*Buffer).enc_int32
389 p.dec = (*Buffer).dec_int32
David Symonds0bf1ad52013-10-11 09:07:50 +1100390 p.size = size_int32
David Symondsf054e842014-07-22 14:06:27 +1000391 case reflect.Uint32:
392 p.enc = (*Buffer).enc_uint32
393 p.dec = (*Buffer).dec_int32 // can reuse
394 p.size = size_uint32
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700395 case reflect.Int64, reflect.Uint64:
396 p.enc = (*Buffer).enc_int64
397 p.dec = (*Buffer).dec_int64
David Symonds0bf1ad52013-10-11 09:07:50 +1100398 p.size = size_int64
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700399 case reflect.Float32:
David Symondsf054e842014-07-22 14:06:27 +1000400 p.enc = (*Buffer).enc_uint32 // can just treat them as bits
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700401 p.dec = (*Buffer).dec_int32
David Symondsf054e842014-07-22 14:06:27 +1000402 p.size = size_uint32
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700403 case reflect.Float64:
404 p.enc = (*Buffer).enc_int64 // can just treat them as bits
405 p.dec = (*Buffer).dec_int64
David Symonds0bf1ad52013-10-11 09:07:50 +1100406 p.size = size_int64
Rob Pike97e934d2011-04-11 12:52:49 -0700407 case reflect.String:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700408 p.enc = (*Buffer).enc_string
409 p.dec = (*Buffer).dec_string
David Symonds0bf1ad52013-10-11 09:07:50 +1100410 p.size = size_string
Rob Pike97e934d2011-04-11 12:52:49 -0700411 case reflect.Struct:
David Symonds6a6f82c2012-08-22 09:18:54 +1000412 p.stype = t1.Elem()
David Symondsa80b2822012-03-14 14:31:25 +1100413 p.isMarshaler = isMarshaler(t1)
414 p.isUnmarshaler = isUnmarshaler(t1)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700415 if p.Wire == "bytes" {
416 p.enc = (*Buffer).enc_struct_message
417 p.dec = (*Buffer).dec_struct_message
David Symonds0bf1ad52013-10-11 09:07:50 +1100418 p.size = size_struct_message
Rob Pikeaaa3a622010-03-20 22:32:34 -0700419 } else {
420 p.enc = (*Buffer).enc_struct_group
421 p.dec = (*Buffer).dec_struct_group
David Symonds0bf1ad52013-10-11 09:07:50 +1100422 p.size = size_struct_group
Rob Pikeaaa3a622010-03-20 22:32:34 -0700423 }
424 }
425
Rob Pike97e934d2011-04-11 12:52:49 -0700426 case reflect.Slice:
427 switch t2 := t1.Elem(); t2.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700428 default:
David Symonds5922d072011-06-22 15:48:09 +1000429 logNoSliceEnc(t1, t2)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700430 break
Rob Pike97e934d2011-04-11 12:52:49 -0700431 case reflect.Bool:
David Symonds5b7775e2010-12-01 10:09:04 +1100432 if p.Packed {
433 p.enc = (*Buffer).enc_slice_packed_bool
David Symonds0bf1ad52013-10-11 09:07:50 +1100434 p.size = size_slice_packed_bool
David Symonds5b7775e2010-12-01 10:09:04 +1100435 } else {
436 p.enc = (*Buffer).enc_slice_bool
David Symonds0bf1ad52013-10-11 09:07:50 +1100437 p.size = size_slice_bool
David Symonds5b7775e2010-12-01 10:09:04 +1100438 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700439 p.dec = (*Buffer).dec_slice_bool
David Symonds5b7775e2010-12-01 10:09:04 +1100440 p.packedDec = (*Buffer).dec_slice_packed_bool
David Symonds0ec36a22014-08-12 13:21:46 +1000441 case reflect.Int32:
442 if p.Packed {
443 p.enc = (*Buffer).enc_slice_packed_int32
444 p.size = size_slice_packed_int32
445 } else {
446 p.enc = (*Buffer).enc_slice_int32
447 p.size = size_slice_int32
Rob Pikeab5b8022010-06-21 17:47:58 -0700448 }
David Symonds0ec36a22014-08-12 13:21:46 +1000449 p.dec = (*Buffer).dec_slice_int32
450 p.packedDec = (*Buffer).dec_slice_packed_int32
451 case reflect.Uint32:
452 if p.Packed {
453 p.enc = (*Buffer).enc_slice_packed_uint32
454 p.size = size_slice_packed_uint32
455 } else {
456 p.enc = (*Buffer).enc_slice_uint32
457 p.size = size_slice_uint32
458 }
459 p.dec = (*Buffer).dec_slice_int32
460 p.packedDec = (*Buffer).dec_slice_packed_int32
461 case reflect.Int64, reflect.Uint64:
462 if p.Packed {
463 p.enc = (*Buffer).enc_slice_packed_int64
464 p.size = size_slice_packed_int64
465 } else {
466 p.enc = (*Buffer).enc_slice_int64
467 p.size = size_slice_int64
468 }
469 p.dec = (*Buffer).dec_slice_int64
470 p.packedDec = (*Buffer).dec_slice_packed_int64
471 case reflect.Uint8:
472 p.enc = (*Buffer).enc_slice_byte
473 p.dec = (*Buffer).dec_slice_byte
474 p.size = size_slice_byte
David Symonds889ae492015-03-23 09:48:33 +1100475 // This is a []byte, which is either a bytes field,
476 // or the value of a map field. In the latter case,
477 // we always encode an empty []byte, so we should not
478 // use the proto3 enc/size funcs.
479 // f == nil iff this is the key/value of a map field.
480 if p.proto3 && f != nil {
David Symondsabd3b412014-11-28 11:43:44 +1100481 p.enc = (*Buffer).enc_proto3_slice_byte
482 p.size = size_proto3_slice_byte
483 }
Rob Pike97e934d2011-04-11 12:52:49 -0700484 case reflect.Float32, reflect.Float64:
Rob Pikeab5b8022010-06-21 17:47:58 -0700485 switch t2.Bits() {
486 case 32:
David Symonds5b7775e2010-12-01 10:09:04 +1100487 // can just treat them as bits
488 if p.Packed {
David Symonds0ec36a22014-08-12 13:21:46 +1000489 p.enc = (*Buffer).enc_slice_packed_uint32
490 p.size = size_slice_packed_uint32
David Symonds5b7775e2010-12-01 10:09:04 +1100491 } else {
David Symonds0ec36a22014-08-12 13:21:46 +1000492 p.enc = (*Buffer).enc_slice_uint32
493 p.size = size_slice_uint32
David Symonds5b7775e2010-12-01 10:09:04 +1100494 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700495 p.dec = (*Buffer).dec_slice_int32
David Symonds5b7775e2010-12-01 10:09:04 +1100496 p.packedDec = (*Buffer).dec_slice_packed_int32
Rob Pikeab5b8022010-06-21 17:47:58 -0700497 case 64:
David Symonds5b7775e2010-12-01 10:09:04 +1100498 // can just treat them as bits
499 if p.Packed {
500 p.enc = (*Buffer).enc_slice_packed_int64
David Symonds0bf1ad52013-10-11 09:07:50 +1100501 p.size = size_slice_packed_int64
David Symonds5b7775e2010-12-01 10:09:04 +1100502 } else {
503 p.enc = (*Buffer).enc_slice_int64
David Symonds0bf1ad52013-10-11 09:07:50 +1100504 p.size = size_slice_int64
David Symonds5b7775e2010-12-01 10:09:04 +1100505 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700506 p.dec = (*Buffer).dec_slice_int64
David Symonds5b7775e2010-12-01 10:09:04 +1100507 p.packedDec = (*Buffer).dec_slice_packed_int64
Rob Pikeab5b8022010-06-21 17:47:58 -0700508 default:
David Symonds5922d072011-06-22 15:48:09 +1000509 logNoSliceEnc(t1, t2)
510 break
Rob Pikeab5b8022010-06-21 17:47:58 -0700511 }
Rob Pike97e934d2011-04-11 12:52:49 -0700512 case reflect.String:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700513 p.enc = (*Buffer).enc_slice_string
514 p.dec = (*Buffer).dec_slice_string
David Symonds0bf1ad52013-10-11 09:07:50 +1100515 p.size = size_slice_string
Rob Pike97e934d2011-04-11 12:52:49 -0700516 case reflect.Ptr:
517 switch t3 := t2.Elem(); t3.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700518 default:
Rob Pikeab5b8022010-06-21 17:47:58 -0700519 fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700520 break
Rob Pike97e934d2011-04-11 12:52:49 -0700521 case reflect.Struct:
David Symonds6a6f82c2012-08-22 09:18:54 +1000522 p.stype = t2.Elem()
David Symondsa80b2822012-03-14 14:31:25 +1100523 p.isMarshaler = isMarshaler(t2)
524 p.isUnmarshaler = isUnmarshaler(t2)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700525 if p.Wire == "bytes" {
526 p.enc = (*Buffer).enc_slice_struct_message
527 p.dec = (*Buffer).dec_slice_struct_message
David Symonds0bf1ad52013-10-11 09:07:50 +1100528 p.size = size_slice_struct_message
529 } else {
530 p.enc = (*Buffer).enc_slice_struct_group
531 p.dec = (*Buffer).dec_slice_struct_group
532 p.size = size_slice_struct_group
Rob Pikeaaa3a622010-03-20 22:32:34 -0700533 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700534 }
Rob Pike97e934d2011-04-11 12:52:49 -0700535 case reflect.Slice:
Rob Pikeab5b8022010-06-21 17:47:58 -0700536 switch t2.Elem().Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700537 default:
Rob Pikeab5b8022010-06-21 17:47:58 -0700538 fmt.Fprintf(os.Stderr, "proto: no slice elem oenc for %T -> %T -> %T\n", t1, t2, t2.Elem())
Rob Pikeaaa3a622010-03-20 22:32:34 -0700539 break
Rob Pikeab5b8022010-06-21 17:47:58 -0700540 case reflect.Uint8:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700541 p.enc = (*Buffer).enc_slice_slice_byte
542 p.dec = (*Buffer).dec_slice_slice_byte
David Symonds0bf1ad52013-10-11 09:07:50 +1100543 p.size = size_slice_slice_byte
Rob Pikeaaa3a622010-03-20 22:32:34 -0700544 }
545 }
David Symonds3ea3e052014-12-22 16:15:28 +1100546
547 case reflect.Map:
548 p.enc = (*Buffer).enc_new_map
549 p.dec = (*Buffer).dec_new_map
550 p.size = size_new_map
551
552 p.mtype = t1
553 p.mkeyprop = &Properties{}
554 p.mkeyprop.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp)
555 p.mvalprop = &Properties{}
556 vtype := p.mtype.Elem()
557 if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice {
558 // The value type is not a message (*T) or bytes ([]byte),
559 // so we need encoders for the pointer to this type.
560 vtype = reflect.PtrTo(vtype)
561 }
562 p.mvalprop.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700563 }
564
565 // precalculate tag code
David Symonds5b7775e2010-12-01 10:09:04 +1100566 wire := p.WireType
567 if p.Packed {
568 wire = WireBytes
569 }
David Symondsd73d7b12011-09-28 10:56:43 -0700570 x := uint32(p.Tag)<<3 | uint32(wire)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700571 i := 0
572 for i = 0; x > 127; i++ {
573 p.tagbuf[i] = 0x80 | uint8(x&0x7F)
574 x >>= 7
575 }
576 p.tagbuf[i] = uint8(x)
577 p.tagcode = p.tagbuf[0 : i+1]
David Symondsc0287172012-08-15 11:10:30 +1000578
579 if p.stype != nil {
580 if lockGetProp {
David Symonds6a6f82c2012-08-22 09:18:54 +1000581 p.sprop = GetProperties(p.stype)
David Symondsc0287172012-08-15 11:10:30 +1000582 } else {
David Symonds6a6f82c2012-08-22 09:18:54 +1000583 p.sprop = getPropertiesLocked(p.stype)
David Symondsc0287172012-08-15 11:10:30 +1000584 }
585 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700586}
587
David Symondsa80b2822012-03-14 14:31:25 +1100588var (
589 marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
590 unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
591)
592
593// isMarshaler reports whether type t implements Marshaler.
594func isMarshaler(t reflect.Type) bool {
595 // We're checking for (likely) pointer-receiver methods
596 // so if t is not a pointer, something is very wrong.
597 // The calls above only invoke isMarshaler on pointer types.
598 if t.Kind() != reflect.Ptr {
599 panic("proto: misuse of isMarshaler")
600 }
601 return t.Implements(marshalerType)
602}
603
604// isUnmarshaler reports whether type t implements Unmarshaler.
605func isUnmarshaler(t reflect.Type) bool {
606 // We're checking for (likely) pointer-receiver methods
607 // so if t is not a pointer, something is very wrong.
608 // The calls above only invoke isUnmarshaler on pointer types.
609 if t.Kind() != reflect.Ptr {
610 panic("proto: misuse of isUnmarshaler")
611 }
612 return t.Implements(unmarshalerType)
613}
614
David Symonds8935abf2011-07-04 15:53:16 +1000615// Init populates the properties from a protocol buffer struct tag.
Russ Coxd4ce3f12012-09-12 10:36:26 +1000616func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) {
617 p.init(typ, name, tag, f, true)
David Symondsc0287172012-08-15 11:10:30 +1000618}
619
Russ Coxd4ce3f12012-09-12 10:36:26 +1000620func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) {
David Symonds8935abf2011-07-04 15:53:16 +1000621 // "bytes,49,opt,def=hello!"
Rob Pikeaaa3a622010-03-20 22:32:34 -0700622 p.Name = name
623 p.OrigName = name
Russ Coxd4ce3f12012-09-12 10:36:26 +1000624 if f != nil {
625 p.field = toField(f)
626 }
David Symonds8935abf2011-07-04 15:53:16 +1000627 if tag == "" {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700628 return
629 }
David Symonds8935abf2011-07-04 15:53:16 +1000630 p.Parse(tag)
David Symonds3ea3e052014-12-22 16:15:28 +1100631 p.setEncAndDec(typ, f, lockGetProp)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700632}
633
634var (
David Symondsf7137ae2015-03-17 08:40:00 +1100635 propertiesMu sync.RWMutex
Rob Pike97e934d2011-04-11 12:52:49 -0700636 propertiesMap = make(map[reflect.Type]*StructProperties)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700637)
638
639// GetProperties returns the list of properties for the type represented by t.
David Symonds905b3fd2014-10-12 16:27:29 +1100640// t must represent a generated struct type of a protocol message.
Rob Pike97e934d2011-04-11 12:52:49 -0700641func GetProperties(t reflect.Type) *StructProperties {
David Symonds905b3fd2014-10-12 16:27:29 +1100642 if t.Kind() != reflect.Struct {
643 panic("proto: type must have kind struct")
644 }
David Symondsf7137ae2015-03-17 08:40:00 +1100645
646 // Most calls to GetProperties in a long-running program will be
647 // retrieving details for types we have seen before.
648 propertiesMu.RLock()
649 sprop, ok := propertiesMap[t]
650 propertiesMu.RUnlock()
651 if ok {
652 if collectStats {
653 stats.Chit++
654 }
655 return sprop
656 }
657
658 propertiesMu.Lock()
659 sprop = getPropertiesLocked(t)
660 propertiesMu.Unlock()
David Symondsc0287172012-08-15 11:10:30 +1000661 return sprop
662}
663
David Symondsf7137ae2015-03-17 08:40:00 +1100664// getPropertiesLocked requires that propertiesMu is held.
David Symondsc0287172012-08-15 11:10:30 +1000665func getPropertiesLocked(t reflect.Type) *StructProperties {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700666 if prop, ok := propertiesMap[t]; ok {
David Symonds9f60f432012-06-14 09:45:25 +1000667 if collectStats {
668 stats.Chit++
669 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700670 return prop
671 }
David Symonds9f60f432012-06-14 09:45:25 +1000672 if collectStats {
673 stats.Cmiss++
674 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700675
676 prop := new(StructProperties)
David Symondsc0287172012-08-15 11:10:30 +1000677 // in case of recursive protos, fill this in now.
678 propertiesMap[t] = prop
Rob Pikeaaa3a622010-03-20 22:32:34 -0700679
680 // build properties
Russ Coxd4ce3f12012-09-12 10:36:26 +1000681 prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType)
682 prop.unrecField = invalidField
Rob Pikeaaa3a622010-03-20 22:32:34 -0700683 prop.Prop = make([]*Properties, t.NumField())
David Symondsd15e81b2011-10-03 14:31:12 -0700684 prop.order = make([]int, t.NumField())
David Symonds20370902013-03-23 17:20:01 +1100685
Rob Pikeaaa3a622010-03-20 22:32:34 -0700686 for i := 0; i < t.NumField(); i++ {
687 f := t.Field(i)
688 p := new(Properties)
David Symonds20370902013-03-23 17:20:01 +1100689 name := f.Name
690 p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false)
691
Rob Pikeaaa3a622010-03-20 22:32:34 -0700692 if f.Name == "XXX_extensions" { // special case
Rob Pikeaaa3a622010-03-20 22:32:34 -0700693 p.enc = (*Buffer).enc_map
694 p.dec = nil // not needed
David Symonds0bf1ad52013-10-11 09:07:50 +1100695 p.size = size_map
Rob Pikeaaa3a622010-03-20 22:32:34 -0700696 }
David Symonds10c93ba2012-08-04 16:38:08 +1000697 if f.Name == "XXX_unrecognized" { // special case
Russ Coxd4ce3f12012-09-12 10:36:26 +1000698 prop.unrecField = toField(&f)
David Symonds10c93ba2012-08-04 16:38:08 +1000699 }
David Symonds59b73b32015-08-24 13:22:02 +1000700 oneof := f.Tag.Get("protobuf_oneof") != "" // special case
Rob Pikeaaa3a622010-03-20 22:32:34 -0700701 prop.Prop[i] = p
David Symondsd15e81b2011-10-03 14:31:12 -0700702 prop.order[i] = i
Rob Pikeaaa3a622010-03-20 22:32:34 -0700703 if debug {
704 print(i, " ", f.Name, " ", t.String(), " ")
705 if p.Tag > 0 {
706 print(p.String())
707 }
708 print("\n")
709 }
David Symonds59b73b32015-08-24 13:22:02 +1000710 if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") && !oneof {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700711 fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]")
712 }
713 }
714
David Symondsd15e81b2011-10-03 14:31:12 -0700715 // Re-order prop.order.
716 sort.Sort(prop)
717
David Symonds59b73b32015-08-24 13:22:02 +1000718 type oneofMessage interface {
Damien Neil08794902015-12-04 07:39:00 +1100719 XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{})
David Symonds59b73b32015-08-24 13:22:02 +1000720 }
721 if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok {
David Symonds1baed092015-08-25 15:42:00 +1000722 var oots []interface{}
Damien Neil08794902015-12-04 07:39:00 +1100723 prop.oneofMarshaler, prop.oneofUnmarshaler, prop.oneofSizer, oots = om.XXX_OneofFuncs()
David Symonds59b73b32015-08-24 13:22:02 +1000724 prop.stype = t
David Symonds1baed092015-08-25 15:42:00 +1000725
726 // Interpret oneof metadata.
727 prop.OneofTypes = make(map[string]*OneofProperties)
728 for _, oot := range oots {
729 oop := &OneofProperties{
730 Type: reflect.ValueOf(oot).Type(), // *T
731 Prop: new(Properties),
732 }
733 sft := oop.Type.Elem().Field(0)
734 oop.Prop.Name = sft.Name
735 oop.Prop.Parse(sft.Tag.Get("protobuf"))
736 // There will be exactly one interface field that
737 // this new value is assignable to.
738 for i := 0; i < t.NumField(); i++ {
739 f := t.Field(i)
740 if f.Type.Kind() != reflect.Interface {
741 continue
742 }
743 if !oop.Type.AssignableTo(f.Type) {
744 continue
745 }
746 oop.Field = i
747 break
748 }
749 prop.OneofTypes[oop.Prop.OrigName] = oop
750 }
David Symonds59b73b32015-08-24 13:22:02 +1000751 }
752
Rob Pikeaaa3a622010-03-20 22:32:34 -0700753 // build required counts
Rob Pikeaaa3a622010-03-20 22:32:34 -0700754 // build tags
755 reqCount := 0
David Symonds2bba1b22012-09-26 14:53:08 +1000756 prop.decoderOrigNames = make(map[string]int)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700757 for i, p := range prop.Prop {
David Symonds6e50db52012-02-11 15:56:22 +1100758 if strings.HasPrefix(p.Name, "XXX_") {
759 // Internal fields should not appear in tags/origNames maps.
760 // They are handled specially when encoding and decoding.
761 continue
762 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700763 if p.Required {
764 reqCount++
765 }
David Symonds2bba1b22012-09-26 14:53:08 +1000766 prop.decoderTags.put(p.Tag, i)
767 prop.decoderOrigNames[p.OrigName] = i
Rob Pikeaaa3a622010-03-20 22:32:34 -0700768 }
769 prop.reqCount = reqCount
Rob Pikeaaa3a622010-03-20 22:32:34 -0700770
Rob Pikeaaa3a622010-03-20 22:32:34 -0700771 return prop
772}
773
Rob Pikeaaa3a622010-03-20 22:32:34 -0700774// Return the Properties object for the x[0]'th field of the structure.
Rob Pike97e934d2011-04-11 12:52:49 -0700775func propByIndex(t reflect.Type, x []int) *Properties {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700776 if len(x) != 1 {
777 fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t)
778 return nil
779 }
780 prop := GetProperties(t)
781 return prop.Prop[x[0]]
782}
783
David Symonds7656e742011-07-22 14:54:17 +1000784// Get the address and type of a pointer to a struct from an interface.
Russ Coxd4ce3f12012-09-12 10:36:26 +1000785func getbase(pb Message) (t reflect.Type, b structPointer, err error) {
Rob Pikef1b341e2011-10-20 14:51:10 -0700786 if pb == nil {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700787 err = ErrNil
788 return
789 }
Rob Pikef1b341e2011-10-20 14:51:10 -0700790 // get the reflect type of the pointer to the struct.
Nigel Tao4ede8452011-04-28 11:27:25 +1000791 t = reflect.TypeOf(pb)
Rob Pikef1b341e2011-10-20 14:51:10 -0700792 // get the address of the struct.
793 value := reflect.ValueOf(pb)
Russ Coxd4ce3f12012-09-12 10:36:26 +1000794 b = toStructPointer(value)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700795 return
796}
797
Rob Pikeaaa3a622010-03-20 22:32:34 -0700798// A global registry of enum types.
799// The generated code will register the generated maps by calling RegisterEnum.
800
Rob Pikeaaa3a622010-03-20 22:32:34 -0700801var enumValueMaps = make(map[string]map[string]int32)
802
803// RegisterEnum is called from the generated code to install the enum descriptor
David Symondsf8a1fcc2013-05-03 08:51:23 +1000804// maps into the global table to aid parsing text format protocol buffers.
805func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[string]int32) {
806 if _, ok := enumValueMaps[typeName]; ok {
Rob Pike79c63792010-03-24 17:48:35 -0700807 panic("proto: duplicate enum registered: " + typeName)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700808 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700809 enumValueMaps[typeName] = valueMap
810}
David Symonds5d7f79b2015-10-19 11:37:00 +1100811
812// EnumValueMap returns the mapping from names to integers of the
813// enum type enumType, or a nil if not found.
814func EnumValueMap(enumType string) map[string]int32 {
815 return enumValueMaps[enumType]
816}
David Symondsa7f1e752015-11-02 15:31:00 +1100817
818// A registry of all linked message types.
David Symondsd3d78382015-11-05 09:41:00 +1100819// The string is a fully-qualified proto name ("pkg.Message").
820var (
821 protoTypes = make(map[string]reflect.Type)
822 revProtoTypes = make(map[reflect.Type]string)
823)
David Symondsa7f1e752015-11-02 15:31:00 +1100824
825// RegisterType is called from generated code and maps from the fully qualified
826// proto name to the type (pointer to struct) of the protocol buffer.
David Symondsd3d78382015-11-05 09:41:00 +1100827func RegisterType(x Message, name string) {
David Symondsa7f1e752015-11-02 15:31:00 +1100828 if _, ok := protoTypes[name]; ok {
829 // TODO: Some day, make this a panic.
830 log.Printf("proto: duplicate proto type registered: %s", name)
831 return
832 }
David Symondsd3d78382015-11-05 09:41:00 +1100833 t := reflect.TypeOf(x)
834 protoTypes[name] = t
835 revProtoTypes[t] = name
David Symondsa7f1e752015-11-02 15:31:00 +1100836}
David Symondsd3d78382015-11-05 09:41:00 +1100837
838// MessageName returns the fully-qualified proto name for the given message type.
839func MessageName(x Message) string { return revProtoTypes[reflect.TypeOf(x)] }
840
841// MessageType returns the message type (pointer to struct) for a named message.
842func MessageType(name string) reflect.Type { return protoTypes[name] }