blob: 880eb22d8fdc214eee2b370cd944d413ffff28e8 [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)
David Symondsd20896f2016-02-10 10:39:21 +1100176 JSONName string // name to use for JSON; determined by protoc
David Symonds7e810982014-08-12 13:11:17 +1000177 Wire string
178 WireType int
179 Tag int
180 Required bool
181 Optional bool
182 Repeated bool
183 Packed bool // relevant for repeated primitives only
184 Enum string // set for enum types only
David Symondsabd3b412014-11-28 11:43:44 +1100185 proto3 bool // whether this is known to be a proto3 field; set for []byte only
David Symonds535a1042015-09-11 08:27:00 +1000186 oneof bool // whether this is a oneof field
David Symonds7e810982014-08-12 13:11:17 +1000187
Rob Pikeaaa3a622010-03-20 22:32:34 -0700188 Default string // default value
David Symonds7e810982014-08-12 13:11:17 +1000189 HasDefault bool // whether an explicit default was provided
Rob Pikeaaa3a622010-03-20 22:32:34 -0700190 def_uint64 uint64
191
David Symondsa80b2822012-03-14 14:31:25 +1100192 enc encoder
193 valEnc valueEncoder // set for bool and numeric types only
Russ Coxd4ce3f12012-09-12 10:36:26 +1000194 field field
David Symondsa80b2822012-03-14 14:31:25 +1100195 tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType)
196 tagbuf [8]byte
David Symondsc0287172012-08-15 11:10:30 +1000197 stype reflect.Type // set for struct types only
198 sprop *StructProperties // set for struct types only
David Symondsa80b2822012-03-14 14:31:25 +1100199 isMarshaler bool
200 isUnmarshaler bool
Rob Pikeaaa3a622010-03-20 22:32:34 -0700201
David Symonds3ea3e052014-12-22 16:15:28 +1100202 mtype reflect.Type // set for map types only
203 mkeyprop *Properties // set for map types only
204 mvalprop *Properties // set for map types only
205
David Symonds0bf1ad52013-10-11 09:07:50 +1100206 size sizer
207 valSize valueSizer // set for bool and numeric types only
208
David Symonds049646b2011-10-21 11:13:45 +1100209 dec decoder
210 valDec valueDecoder // set for bool and numeric types only
David Symonds5b7775e2010-12-01 10:09:04 +1100211
212 // If this is a packable field, this will be the decoder for the packed version of the field.
213 packedDec decoder
Rob Pikeaaa3a622010-03-20 22:32:34 -0700214}
215
David Symonds8935abf2011-07-04 15:53:16 +1000216// String formats the properties in the protobuf struct field tag style.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700217func (p *Properties) String() string {
218 s := p.Wire
219 s = ","
220 s += strconv.Itoa(p.Tag)
221 if p.Required {
222 s += ",req"
223 }
224 if p.Optional {
225 s += ",opt"
226 }
227 if p.Repeated {
228 s += ",rep"
229 }
David Symonds5b7775e2010-12-01 10:09:04 +1100230 if p.Packed {
231 s += ",packed"
232 }
David Symondsd20896f2016-02-10 10:39:21 +1100233 s += ",name=" + p.OrigName
234 if p.JSONName != p.OrigName {
235 s += ",json=" + p.JSONName
Rob Pikeaaa3a622010-03-20 22:32:34 -0700236 }
David Symondsabd3b412014-11-28 11:43:44 +1100237 if p.proto3 {
238 s += ",proto3"
239 }
David Symonds535a1042015-09-11 08:27:00 +1000240 if p.oneof {
241 s += ",oneof"
242 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700243 if len(p.Enum) > 0 {
244 s += ",enum=" + p.Enum
245 }
David Symonds7e810982014-08-12 13:11:17 +1000246 if p.HasDefault {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700247 s += ",def=" + p.Default
248 }
249 return s
250}
251
David Symonds8935abf2011-07-04 15:53:16 +1000252// Parse populates p by parsing a string in the protobuf struct field tag style.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700253func (p *Properties) Parse(s string) {
David Symondsa7e9ef92012-01-18 18:27:58 +1100254 // "bytes,49,opt,name=foo,def=hello!"
David Symonds8935abf2011-07-04 15:53:16 +1000255 fields := strings.Split(s, ",") // breaks def=, but handled below.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700256 if len(fields) < 2 {
257 fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s)
258 return
259 }
260
261 p.Wire = fields[0]
262 switch p.Wire {
263 case "varint":
264 p.WireType = WireVarint
265 p.valEnc = (*Buffer).EncodeVarint
266 p.valDec = (*Buffer).DecodeVarint
David Symonds0bf1ad52013-10-11 09:07:50 +1100267 p.valSize = sizeVarint
Rob Pikeaaa3a622010-03-20 22:32:34 -0700268 case "fixed32":
269 p.WireType = WireFixed32
270 p.valEnc = (*Buffer).EncodeFixed32
271 p.valDec = (*Buffer).DecodeFixed32
David Symonds0bf1ad52013-10-11 09:07:50 +1100272 p.valSize = sizeFixed32
Rob Pikeaaa3a622010-03-20 22:32:34 -0700273 case "fixed64":
274 p.WireType = WireFixed64
275 p.valEnc = (*Buffer).EncodeFixed64
276 p.valDec = (*Buffer).DecodeFixed64
David Symonds0bf1ad52013-10-11 09:07:50 +1100277 p.valSize = sizeFixed64
Rob Pikeaaa3a622010-03-20 22:32:34 -0700278 case "zigzag32":
279 p.WireType = WireVarint
280 p.valEnc = (*Buffer).EncodeZigzag32
281 p.valDec = (*Buffer).DecodeZigzag32
David Symonds0bf1ad52013-10-11 09:07:50 +1100282 p.valSize = sizeZigzag32
Rob Pikeaaa3a622010-03-20 22:32:34 -0700283 case "zigzag64":
284 p.WireType = WireVarint
285 p.valEnc = (*Buffer).EncodeZigzag64
286 p.valDec = (*Buffer).DecodeZigzag64
David Symonds0bf1ad52013-10-11 09:07:50 +1100287 p.valSize = sizeZigzag64
Rob Pikeaaa3a622010-03-20 22:32:34 -0700288 case "bytes", "group":
289 p.WireType = WireBytes
290 // no numeric converter for non-numeric types
291 default:
292 fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s)
293 return
294 }
295
Rob Pikea17fdd92011-11-02 12:43:05 -0700296 var err error
Rob Pikeaaa3a622010-03-20 22:32:34 -0700297 p.Tag, err = strconv.Atoi(fields[1])
298 if err != nil {
299 return
300 }
301
302 for i := 2; i < len(fields); i++ {
303 f := fields[i]
304 switch {
305 case f == "req":
306 p.Required = true
307 case f == "opt":
308 p.Optional = true
309 case f == "rep":
310 p.Repeated = true
David Symonds5b7775e2010-12-01 10:09:04 +1100311 case f == "packed":
312 p.Packed = true
David Symondsa7e9ef92012-01-18 18:27:58 +1100313 case strings.HasPrefix(f, "name="):
Albert Strasheim4676f6a2013-04-07 08:59:06 +1000314 p.OrigName = f[5:]
David Symondsd20896f2016-02-10 10:39:21 +1100315 case strings.HasPrefix(f, "json="):
316 p.JSONName = f[5:]
David Symondsa7e9ef92012-01-18 18:27:58 +1100317 case strings.HasPrefix(f, "enum="):
Albert Strasheim4676f6a2013-04-07 08:59:06 +1000318 p.Enum = f[5:]
David Symondsabd3b412014-11-28 11:43:44 +1100319 case f == "proto3":
320 p.proto3 = true
David Symonds535a1042015-09-11 08:27:00 +1000321 case f == "oneof":
322 p.oneof = true
David Symondsa7e9ef92012-01-18 18:27:58 +1100323 case strings.HasPrefix(f, "def="):
David Symonds7e810982014-08-12 13:11:17 +1000324 p.HasDefault = true
Albert Strasheim4676f6a2013-04-07 08:59:06 +1000325 p.Default = f[4:] // rest of string
Rob Pikeaaa3a622010-03-20 22:32:34 -0700326 if i+1 < len(fields) {
327 // Commas aren't escaped, and def is always last.
Albert Strasheim4676f6a2013-04-07 08:59:06 +1000328 p.Default += "," + strings.Join(fields[i+1:], ",")
Rob Pikeaaa3a622010-03-20 22:32:34 -0700329 break
330 }
331 }
332 }
333}
334
David Symonds5922d072011-06-22 15:48:09 +1000335func logNoSliceEnc(t1, t2 reflect.Type) {
336 fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2)
337}
338
David Symonds525838c2012-07-20 15:42:49 +1000339var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem()
340
Rob Pikeaaa3a622010-03-20 22:32:34 -0700341// Initialize the fields for encoding and decoding.
David Symonds3ea3e052014-12-22 16:15:28 +1100342func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lockGetProp bool) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700343 p.enc = nil
344 p.dec = nil
David Symonds0bf1ad52013-10-11 09:07:50 +1100345 p.size = nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700346
Rob Pike97e934d2011-04-11 12:52:49 -0700347 switch t1 := typ; t1.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700348 default:
David Symonds50386d22014-10-28 11:00:50 +1100349 fmt.Fprintf(os.Stderr, "proto: no coders for %v\n", t1)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700350
David Symondsabd3b412014-11-28 11:43:44 +1100351 // proto3 scalar types
352
353 case reflect.Bool:
354 p.enc = (*Buffer).enc_proto3_bool
355 p.dec = (*Buffer).dec_proto3_bool
356 p.size = size_proto3_bool
357 case reflect.Int32:
358 p.enc = (*Buffer).enc_proto3_int32
359 p.dec = (*Buffer).dec_proto3_int32
360 p.size = size_proto3_int32
361 case reflect.Uint32:
362 p.enc = (*Buffer).enc_proto3_uint32
363 p.dec = (*Buffer).dec_proto3_int32 // can reuse
364 p.size = size_proto3_uint32
365 case reflect.Int64, reflect.Uint64:
366 p.enc = (*Buffer).enc_proto3_int64
367 p.dec = (*Buffer).dec_proto3_int64
368 p.size = size_proto3_int64
369 case reflect.Float32:
370 p.enc = (*Buffer).enc_proto3_uint32 // can just treat them as bits
371 p.dec = (*Buffer).dec_proto3_int32
372 p.size = size_proto3_uint32
373 case reflect.Float64:
374 p.enc = (*Buffer).enc_proto3_int64 // can just treat them as bits
375 p.dec = (*Buffer).dec_proto3_int64
376 p.size = size_proto3_int64
377 case reflect.String:
378 p.enc = (*Buffer).enc_proto3_string
379 p.dec = (*Buffer).dec_proto3_string
380 p.size = size_proto3_string
381
Rob Pike97e934d2011-04-11 12:52:49 -0700382 case reflect.Ptr:
383 switch t2 := t1.Elem(); t2.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700384 default:
David Symonds3ea3e052014-12-22 16:15:28 +1100385 fmt.Fprintf(os.Stderr, "proto: no encoder function for %v -> %v\n", t1, t2)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700386 break
Rob Pike97e934d2011-04-11 12:52:49 -0700387 case reflect.Bool:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700388 p.enc = (*Buffer).enc_bool
389 p.dec = (*Buffer).dec_bool
David Symonds0bf1ad52013-10-11 09:07:50 +1100390 p.size = size_bool
David Symondsf054e842014-07-22 14:06:27 +1000391 case reflect.Int32:
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700392 p.enc = (*Buffer).enc_int32
393 p.dec = (*Buffer).dec_int32
David Symonds0bf1ad52013-10-11 09:07:50 +1100394 p.size = size_int32
David Symondsf054e842014-07-22 14:06:27 +1000395 case reflect.Uint32:
396 p.enc = (*Buffer).enc_uint32
397 p.dec = (*Buffer).dec_int32 // can reuse
398 p.size = size_uint32
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700399 case reflect.Int64, reflect.Uint64:
400 p.enc = (*Buffer).enc_int64
401 p.dec = (*Buffer).dec_int64
David Symonds0bf1ad52013-10-11 09:07:50 +1100402 p.size = size_int64
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700403 case reflect.Float32:
David Symondsf054e842014-07-22 14:06:27 +1000404 p.enc = (*Buffer).enc_uint32 // can just treat them as bits
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700405 p.dec = (*Buffer).dec_int32
David Symondsf054e842014-07-22 14:06:27 +1000406 p.size = size_uint32
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700407 case reflect.Float64:
408 p.enc = (*Buffer).enc_int64 // can just treat them as bits
409 p.dec = (*Buffer).dec_int64
David Symonds0bf1ad52013-10-11 09:07:50 +1100410 p.size = size_int64
Rob Pike97e934d2011-04-11 12:52:49 -0700411 case reflect.String:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700412 p.enc = (*Buffer).enc_string
413 p.dec = (*Buffer).dec_string
David Symonds0bf1ad52013-10-11 09:07:50 +1100414 p.size = size_string
Rob Pike97e934d2011-04-11 12:52:49 -0700415 case reflect.Struct:
David Symonds6a6f82c2012-08-22 09:18:54 +1000416 p.stype = t1.Elem()
David Symondsa80b2822012-03-14 14:31:25 +1100417 p.isMarshaler = isMarshaler(t1)
418 p.isUnmarshaler = isUnmarshaler(t1)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700419 if p.Wire == "bytes" {
420 p.enc = (*Buffer).enc_struct_message
421 p.dec = (*Buffer).dec_struct_message
David Symonds0bf1ad52013-10-11 09:07:50 +1100422 p.size = size_struct_message
Rob Pikeaaa3a622010-03-20 22:32:34 -0700423 } else {
424 p.enc = (*Buffer).enc_struct_group
425 p.dec = (*Buffer).dec_struct_group
David Symonds0bf1ad52013-10-11 09:07:50 +1100426 p.size = size_struct_group
Rob Pikeaaa3a622010-03-20 22:32:34 -0700427 }
428 }
429
Rob Pike97e934d2011-04-11 12:52:49 -0700430 case reflect.Slice:
431 switch t2 := t1.Elem(); t2.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700432 default:
David Symonds5922d072011-06-22 15:48:09 +1000433 logNoSliceEnc(t1, t2)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700434 break
Rob Pike97e934d2011-04-11 12:52:49 -0700435 case reflect.Bool:
David Symonds5b7775e2010-12-01 10:09:04 +1100436 if p.Packed {
437 p.enc = (*Buffer).enc_slice_packed_bool
David Symonds0bf1ad52013-10-11 09:07:50 +1100438 p.size = size_slice_packed_bool
David Symonds5b7775e2010-12-01 10:09:04 +1100439 } else {
440 p.enc = (*Buffer).enc_slice_bool
David Symonds0bf1ad52013-10-11 09:07:50 +1100441 p.size = size_slice_bool
David Symonds5b7775e2010-12-01 10:09:04 +1100442 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700443 p.dec = (*Buffer).dec_slice_bool
David Symonds5b7775e2010-12-01 10:09:04 +1100444 p.packedDec = (*Buffer).dec_slice_packed_bool
David Symonds0ec36a22014-08-12 13:21:46 +1000445 case reflect.Int32:
446 if p.Packed {
447 p.enc = (*Buffer).enc_slice_packed_int32
448 p.size = size_slice_packed_int32
449 } else {
450 p.enc = (*Buffer).enc_slice_int32
451 p.size = size_slice_int32
Rob Pikeab5b8022010-06-21 17:47:58 -0700452 }
David Symonds0ec36a22014-08-12 13:21:46 +1000453 p.dec = (*Buffer).dec_slice_int32
454 p.packedDec = (*Buffer).dec_slice_packed_int32
455 case reflect.Uint32:
456 if p.Packed {
457 p.enc = (*Buffer).enc_slice_packed_uint32
458 p.size = size_slice_packed_uint32
459 } else {
460 p.enc = (*Buffer).enc_slice_uint32
461 p.size = size_slice_uint32
462 }
463 p.dec = (*Buffer).dec_slice_int32
464 p.packedDec = (*Buffer).dec_slice_packed_int32
465 case reflect.Int64, reflect.Uint64:
466 if p.Packed {
467 p.enc = (*Buffer).enc_slice_packed_int64
468 p.size = size_slice_packed_int64
469 } else {
470 p.enc = (*Buffer).enc_slice_int64
471 p.size = size_slice_int64
472 }
473 p.dec = (*Buffer).dec_slice_int64
474 p.packedDec = (*Buffer).dec_slice_packed_int64
475 case reflect.Uint8:
476 p.enc = (*Buffer).enc_slice_byte
477 p.dec = (*Buffer).dec_slice_byte
478 p.size = size_slice_byte
David Symonds889ae492015-03-23 09:48:33 +1100479 // This is a []byte, which is either a bytes field,
480 // or the value of a map field. In the latter case,
481 // we always encode an empty []byte, so we should not
482 // use the proto3 enc/size funcs.
483 // f == nil iff this is the key/value of a map field.
484 if p.proto3 && f != nil {
David Symondsabd3b412014-11-28 11:43:44 +1100485 p.enc = (*Buffer).enc_proto3_slice_byte
486 p.size = size_proto3_slice_byte
487 }
Rob Pike97e934d2011-04-11 12:52:49 -0700488 case reflect.Float32, reflect.Float64:
Rob Pikeab5b8022010-06-21 17:47:58 -0700489 switch t2.Bits() {
490 case 32:
David Symonds5b7775e2010-12-01 10:09:04 +1100491 // can just treat them as bits
492 if p.Packed {
David Symonds0ec36a22014-08-12 13:21:46 +1000493 p.enc = (*Buffer).enc_slice_packed_uint32
494 p.size = size_slice_packed_uint32
David Symonds5b7775e2010-12-01 10:09:04 +1100495 } else {
David Symonds0ec36a22014-08-12 13:21:46 +1000496 p.enc = (*Buffer).enc_slice_uint32
497 p.size = size_slice_uint32
David Symonds5b7775e2010-12-01 10:09:04 +1100498 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700499 p.dec = (*Buffer).dec_slice_int32
David Symonds5b7775e2010-12-01 10:09:04 +1100500 p.packedDec = (*Buffer).dec_slice_packed_int32
Rob Pikeab5b8022010-06-21 17:47:58 -0700501 case 64:
David Symonds5b7775e2010-12-01 10:09:04 +1100502 // can just treat them as bits
503 if p.Packed {
504 p.enc = (*Buffer).enc_slice_packed_int64
David Symonds0bf1ad52013-10-11 09:07:50 +1100505 p.size = size_slice_packed_int64
David Symonds5b7775e2010-12-01 10:09:04 +1100506 } else {
507 p.enc = (*Buffer).enc_slice_int64
David Symonds0bf1ad52013-10-11 09:07:50 +1100508 p.size = size_slice_int64
David Symonds5b7775e2010-12-01 10:09:04 +1100509 }
Rob Pikeab5b8022010-06-21 17:47:58 -0700510 p.dec = (*Buffer).dec_slice_int64
David Symonds5b7775e2010-12-01 10:09:04 +1100511 p.packedDec = (*Buffer).dec_slice_packed_int64
Rob Pikeab5b8022010-06-21 17:47:58 -0700512 default:
David Symonds5922d072011-06-22 15:48:09 +1000513 logNoSliceEnc(t1, t2)
514 break
Rob Pikeab5b8022010-06-21 17:47:58 -0700515 }
Rob Pike97e934d2011-04-11 12:52:49 -0700516 case reflect.String:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700517 p.enc = (*Buffer).enc_slice_string
518 p.dec = (*Buffer).dec_slice_string
David Symonds0bf1ad52013-10-11 09:07:50 +1100519 p.size = size_slice_string
Rob Pike97e934d2011-04-11 12:52:49 -0700520 case reflect.Ptr:
521 switch t3 := t2.Elem(); t3.Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700522 default:
Rob Pikeab5b8022010-06-21 17:47:58 -0700523 fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700524 break
Rob Pike97e934d2011-04-11 12:52:49 -0700525 case reflect.Struct:
David Symonds6a6f82c2012-08-22 09:18:54 +1000526 p.stype = t2.Elem()
David Symondsa80b2822012-03-14 14:31:25 +1100527 p.isMarshaler = isMarshaler(t2)
528 p.isUnmarshaler = isUnmarshaler(t2)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700529 if p.Wire == "bytes" {
530 p.enc = (*Buffer).enc_slice_struct_message
531 p.dec = (*Buffer).dec_slice_struct_message
David Symonds0bf1ad52013-10-11 09:07:50 +1100532 p.size = size_slice_struct_message
533 } else {
534 p.enc = (*Buffer).enc_slice_struct_group
535 p.dec = (*Buffer).dec_slice_struct_group
536 p.size = size_slice_struct_group
Rob Pikeaaa3a622010-03-20 22:32:34 -0700537 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700538 }
Rob Pike97e934d2011-04-11 12:52:49 -0700539 case reflect.Slice:
Rob Pikeab5b8022010-06-21 17:47:58 -0700540 switch t2.Elem().Kind() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700541 default:
Rob Pikeab5b8022010-06-21 17:47:58 -0700542 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 -0700543 break
Rob Pikeab5b8022010-06-21 17:47:58 -0700544 case reflect.Uint8:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700545 p.enc = (*Buffer).enc_slice_slice_byte
546 p.dec = (*Buffer).dec_slice_slice_byte
David Symonds0bf1ad52013-10-11 09:07:50 +1100547 p.size = size_slice_slice_byte
Rob Pikeaaa3a622010-03-20 22:32:34 -0700548 }
549 }
David Symonds3ea3e052014-12-22 16:15:28 +1100550
551 case reflect.Map:
552 p.enc = (*Buffer).enc_new_map
553 p.dec = (*Buffer).dec_new_map
554 p.size = size_new_map
555
556 p.mtype = t1
557 p.mkeyprop = &Properties{}
558 p.mkeyprop.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp)
559 p.mvalprop = &Properties{}
560 vtype := p.mtype.Elem()
561 if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice {
562 // The value type is not a message (*T) or bytes ([]byte),
563 // so we need encoders for the pointer to this type.
564 vtype = reflect.PtrTo(vtype)
565 }
566 p.mvalprop.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700567 }
568
569 // precalculate tag code
David Symonds5b7775e2010-12-01 10:09:04 +1100570 wire := p.WireType
571 if p.Packed {
572 wire = WireBytes
573 }
David Symondsd73d7b12011-09-28 10:56:43 -0700574 x := uint32(p.Tag)<<3 | uint32(wire)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700575 i := 0
576 for i = 0; x > 127; i++ {
577 p.tagbuf[i] = 0x80 | uint8(x&0x7F)
578 x >>= 7
579 }
580 p.tagbuf[i] = uint8(x)
581 p.tagcode = p.tagbuf[0 : i+1]
David Symondsc0287172012-08-15 11:10:30 +1000582
583 if p.stype != nil {
584 if lockGetProp {
David Symonds6a6f82c2012-08-22 09:18:54 +1000585 p.sprop = GetProperties(p.stype)
David Symondsc0287172012-08-15 11:10:30 +1000586 } else {
David Symonds6a6f82c2012-08-22 09:18:54 +1000587 p.sprop = getPropertiesLocked(p.stype)
David Symondsc0287172012-08-15 11:10:30 +1000588 }
589 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700590}
591
David Symondsa80b2822012-03-14 14:31:25 +1100592var (
593 marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
594 unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
595)
596
597// isMarshaler reports whether type t implements Marshaler.
598func isMarshaler(t reflect.Type) bool {
599 // We're checking for (likely) pointer-receiver methods
600 // so if t is not a pointer, something is very wrong.
601 // The calls above only invoke isMarshaler on pointer types.
602 if t.Kind() != reflect.Ptr {
603 panic("proto: misuse of isMarshaler")
604 }
605 return t.Implements(marshalerType)
606}
607
608// isUnmarshaler reports whether type t implements Unmarshaler.
609func isUnmarshaler(t reflect.Type) bool {
610 // We're checking for (likely) pointer-receiver methods
611 // so if t is not a pointer, something is very wrong.
612 // The calls above only invoke isUnmarshaler on pointer types.
613 if t.Kind() != reflect.Ptr {
614 panic("proto: misuse of isUnmarshaler")
615 }
616 return t.Implements(unmarshalerType)
617}
618
David Symonds8935abf2011-07-04 15:53:16 +1000619// Init populates the properties from a protocol buffer struct tag.
Russ Coxd4ce3f12012-09-12 10:36:26 +1000620func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) {
621 p.init(typ, name, tag, f, true)
David Symondsc0287172012-08-15 11:10:30 +1000622}
623
Russ Coxd4ce3f12012-09-12 10:36:26 +1000624func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) {
David Symonds8935abf2011-07-04 15:53:16 +1000625 // "bytes,49,opt,def=hello!"
Rob Pikeaaa3a622010-03-20 22:32:34 -0700626 p.Name = name
627 p.OrigName = name
Russ Coxd4ce3f12012-09-12 10:36:26 +1000628 if f != nil {
629 p.field = toField(f)
630 }
David Symonds8935abf2011-07-04 15:53:16 +1000631 if tag == "" {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700632 return
633 }
David Symonds8935abf2011-07-04 15:53:16 +1000634 p.Parse(tag)
David Symonds3ea3e052014-12-22 16:15:28 +1100635 p.setEncAndDec(typ, f, lockGetProp)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700636}
637
638var (
David Symondsf7137ae2015-03-17 08:40:00 +1100639 propertiesMu sync.RWMutex
Rob Pike97e934d2011-04-11 12:52:49 -0700640 propertiesMap = make(map[reflect.Type]*StructProperties)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700641)
642
643// GetProperties returns the list of properties for the type represented by t.
David Symonds905b3fd2014-10-12 16:27:29 +1100644// t must represent a generated struct type of a protocol message.
Rob Pike97e934d2011-04-11 12:52:49 -0700645func GetProperties(t reflect.Type) *StructProperties {
David Symonds905b3fd2014-10-12 16:27:29 +1100646 if t.Kind() != reflect.Struct {
647 panic("proto: type must have kind struct")
648 }
David Symondsf7137ae2015-03-17 08:40:00 +1100649
650 // Most calls to GetProperties in a long-running program will be
651 // retrieving details for types we have seen before.
652 propertiesMu.RLock()
653 sprop, ok := propertiesMap[t]
654 propertiesMu.RUnlock()
655 if ok {
656 if collectStats {
657 stats.Chit++
658 }
659 return sprop
660 }
661
662 propertiesMu.Lock()
663 sprop = getPropertiesLocked(t)
664 propertiesMu.Unlock()
David Symondsc0287172012-08-15 11:10:30 +1000665 return sprop
666}
667
David Symondsf7137ae2015-03-17 08:40:00 +1100668// getPropertiesLocked requires that propertiesMu is held.
David Symondsc0287172012-08-15 11:10:30 +1000669func getPropertiesLocked(t reflect.Type) *StructProperties {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700670 if prop, ok := propertiesMap[t]; ok {
David Symonds9f60f432012-06-14 09:45:25 +1000671 if collectStats {
672 stats.Chit++
673 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700674 return prop
675 }
David Symonds9f60f432012-06-14 09:45:25 +1000676 if collectStats {
677 stats.Cmiss++
678 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700679
680 prop := new(StructProperties)
David Symondsc0287172012-08-15 11:10:30 +1000681 // in case of recursive protos, fill this in now.
682 propertiesMap[t] = prop
Rob Pikeaaa3a622010-03-20 22:32:34 -0700683
684 // build properties
Russ Coxd4ce3f12012-09-12 10:36:26 +1000685 prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType)
686 prop.unrecField = invalidField
Rob Pikeaaa3a622010-03-20 22:32:34 -0700687 prop.Prop = make([]*Properties, t.NumField())
David Symondsd15e81b2011-10-03 14:31:12 -0700688 prop.order = make([]int, t.NumField())
David Symonds20370902013-03-23 17:20:01 +1100689
Rob Pikeaaa3a622010-03-20 22:32:34 -0700690 for i := 0; i < t.NumField(); i++ {
691 f := t.Field(i)
692 p := new(Properties)
David Symonds20370902013-03-23 17:20:01 +1100693 name := f.Name
694 p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false)
695
Rob Pikeaaa3a622010-03-20 22:32:34 -0700696 if f.Name == "XXX_extensions" { // special case
Rob Pikeaaa3a622010-03-20 22:32:34 -0700697 p.enc = (*Buffer).enc_map
698 p.dec = nil // not needed
David Symonds0bf1ad52013-10-11 09:07:50 +1100699 p.size = size_map
Rob Pikeaaa3a622010-03-20 22:32:34 -0700700 }
David Symonds10c93ba2012-08-04 16:38:08 +1000701 if f.Name == "XXX_unrecognized" { // special case
Russ Coxd4ce3f12012-09-12 10:36:26 +1000702 prop.unrecField = toField(&f)
David Symonds10c93ba2012-08-04 16:38:08 +1000703 }
Dave Day2ebff282016-04-18 12:44:00 +1000704 oneof := f.Tag.Get("protobuf_oneof") // special case
705 if oneof != "" {
706 // Oneof fields don't use the traditional protobuf tag.
707 p.OrigName = oneof
708 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700709 prop.Prop[i] = p
David Symondsd15e81b2011-10-03 14:31:12 -0700710 prop.order[i] = i
Rob Pikeaaa3a622010-03-20 22:32:34 -0700711 if debug {
712 print(i, " ", f.Name, " ", t.String(), " ")
713 if p.Tag > 0 {
714 print(p.String())
715 }
716 print("\n")
717 }
Dave Day2ebff282016-04-18 12:44:00 +1000718 if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") && oneof == "" {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700719 fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]")
720 }
721 }
722
David Symondsd15e81b2011-10-03 14:31:12 -0700723 // Re-order prop.order.
724 sort.Sort(prop)
725
David Symonds59b73b32015-08-24 13:22:02 +1000726 type oneofMessage interface {
Damien Neil08794902015-12-04 07:39:00 +1100727 XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{})
David Symonds59b73b32015-08-24 13:22:02 +1000728 }
729 if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok {
David Symonds1baed092015-08-25 15:42:00 +1000730 var oots []interface{}
Damien Neil08794902015-12-04 07:39:00 +1100731 prop.oneofMarshaler, prop.oneofUnmarshaler, prop.oneofSizer, oots = om.XXX_OneofFuncs()
David Symonds59b73b32015-08-24 13:22:02 +1000732 prop.stype = t
David Symonds1baed092015-08-25 15:42:00 +1000733
734 // Interpret oneof metadata.
735 prop.OneofTypes = make(map[string]*OneofProperties)
736 for _, oot := range oots {
737 oop := &OneofProperties{
738 Type: reflect.ValueOf(oot).Type(), // *T
739 Prop: new(Properties),
740 }
741 sft := oop.Type.Elem().Field(0)
742 oop.Prop.Name = sft.Name
743 oop.Prop.Parse(sft.Tag.Get("protobuf"))
744 // There will be exactly one interface field that
745 // this new value is assignable to.
746 for i := 0; i < t.NumField(); i++ {
747 f := t.Field(i)
748 if f.Type.Kind() != reflect.Interface {
749 continue
750 }
751 if !oop.Type.AssignableTo(f.Type) {
752 continue
753 }
754 oop.Field = i
755 break
756 }
757 prop.OneofTypes[oop.Prop.OrigName] = oop
758 }
David Symonds59b73b32015-08-24 13:22:02 +1000759 }
760
Rob Pikeaaa3a622010-03-20 22:32:34 -0700761 // build required counts
Rob Pikeaaa3a622010-03-20 22:32:34 -0700762 // build tags
763 reqCount := 0
David Symonds2bba1b22012-09-26 14:53:08 +1000764 prop.decoderOrigNames = make(map[string]int)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700765 for i, p := range prop.Prop {
David Symonds6e50db52012-02-11 15:56:22 +1100766 if strings.HasPrefix(p.Name, "XXX_") {
767 // Internal fields should not appear in tags/origNames maps.
768 // They are handled specially when encoding and decoding.
769 continue
770 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700771 if p.Required {
772 reqCount++
773 }
David Symonds2bba1b22012-09-26 14:53:08 +1000774 prop.decoderTags.put(p.Tag, i)
775 prop.decoderOrigNames[p.OrigName] = i
Rob Pikeaaa3a622010-03-20 22:32:34 -0700776 }
777 prop.reqCount = reqCount
Rob Pikeaaa3a622010-03-20 22:32:34 -0700778
Rob Pikeaaa3a622010-03-20 22:32:34 -0700779 return prop
780}
781
Rob Pikeaaa3a622010-03-20 22:32:34 -0700782// Return the Properties object for the x[0]'th field of the structure.
Rob Pike97e934d2011-04-11 12:52:49 -0700783func propByIndex(t reflect.Type, x []int) *Properties {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700784 if len(x) != 1 {
785 fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t)
786 return nil
787 }
788 prop := GetProperties(t)
789 return prop.Prop[x[0]]
790}
791
David Symonds7656e742011-07-22 14:54:17 +1000792// Get the address and type of a pointer to a struct from an interface.
Russ Coxd4ce3f12012-09-12 10:36:26 +1000793func getbase(pb Message) (t reflect.Type, b structPointer, err error) {
Rob Pikef1b341e2011-10-20 14:51:10 -0700794 if pb == nil {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700795 err = ErrNil
796 return
797 }
Rob Pikef1b341e2011-10-20 14:51:10 -0700798 // get the reflect type of the pointer to the struct.
Nigel Tao4ede8452011-04-28 11:27:25 +1000799 t = reflect.TypeOf(pb)
Rob Pikef1b341e2011-10-20 14:51:10 -0700800 // get the address of the struct.
801 value := reflect.ValueOf(pb)
Russ Coxd4ce3f12012-09-12 10:36:26 +1000802 b = toStructPointer(value)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700803 return
804}
805
Rob Pikeaaa3a622010-03-20 22:32:34 -0700806// A global registry of enum types.
807// The generated code will register the generated maps by calling RegisterEnum.
808
Rob Pikeaaa3a622010-03-20 22:32:34 -0700809var enumValueMaps = make(map[string]map[string]int32)
810
811// RegisterEnum is called from the generated code to install the enum descriptor
David Symondsf8a1fcc2013-05-03 08:51:23 +1000812// maps into the global table to aid parsing text format protocol buffers.
813func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[string]int32) {
814 if _, ok := enumValueMaps[typeName]; ok {
Rob Pike79c63792010-03-24 17:48:35 -0700815 panic("proto: duplicate enum registered: " + typeName)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700816 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700817 enumValueMaps[typeName] = valueMap
818}
David Symonds5d7f79b2015-10-19 11:37:00 +1100819
820// EnumValueMap returns the mapping from names to integers of the
821// enum type enumType, or a nil if not found.
822func EnumValueMap(enumType string) map[string]int32 {
823 return enumValueMaps[enumType]
824}
David Symondsa7f1e752015-11-02 15:31:00 +1100825
826// A registry of all linked message types.
David Symondsd3d78382015-11-05 09:41:00 +1100827// The string is a fully-qualified proto name ("pkg.Message").
828var (
829 protoTypes = make(map[string]reflect.Type)
830 revProtoTypes = make(map[reflect.Type]string)
831)
David Symondsa7f1e752015-11-02 15:31:00 +1100832
833// RegisterType is called from generated code and maps from the fully qualified
834// proto name to the type (pointer to struct) of the protocol buffer.
David Symondsd3d78382015-11-05 09:41:00 +1100835func RegisterType(x Message, name string) {
David Symondsa7f1e752015-11-02 15:31:00 +1100836 if _, ok := protoTypes[name]; ok {
837 // TODO: Some day, make this a panic.
838 log.Printf("proto: duplicate proto type registered: %s", name)
839 return
840 }
David Symondsd3d78382015-11-05 09:41:00 +1100841 t := reflect.TypeOf(x)
842 protoTypes[name] = t
843 revProtoTypes[t] = name
David Symondsa7f1e752015-11-02 15:31:00 +1100844}
David Symondsd3d78382015-11-05 09:41:00 +1100845
846// MessageName returns the fully-qualified proto name for the given message type.
847func MessageName(x Message) string { return revProtoTypes[reflect.TypeOf(x)] }
848
849// MessageType returns the message type (pointer to struct) for a named message.
850func MessageType(name string) reflect.Type { return protoTypes[name] }