blob: 39edea32fddfb0e64e956585679aef54b40e743d [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
matloob@google.come51d0022016-05-23 09:09:04 -0400685 prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType) ||
686 reflect.PtrTo(t).Implements(extendableProtoV1Type)
Russ Coxd4ce3f12012-09-12 10:36:26 +1000687 prop.unrecField = invalidField
Rob Pikeaaa3a622010-03-20 22:32:34 -0700688 prop.Prop = make([]*Properties, t.NumField())
David Symondsd15e81b2011-10-03 14:31:12 -0700689 prop.order = make([]int, t.NumField())
David Symonds20370902013-03-23 17:20:01 +1100690
Rob Pikeaaa3a622010-03-20 22:32:34 -0700691 for i := 0; i < t.NumField(); i++ {
692 f := t.Field(i)
693 p := new(Properties)
David Symonds20370902013-03-23 17:20:01 +1100694 name := f.Name
695 p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false)
696
matloob@google.come51d0022016-05-23 09:09:04 -0400697 if f.Name == "XXX_InternalExtensions" { // special case
698 p.enc = (*Buffer).enc_exts
699 p.dec = nil // not needed
700 p.size = size_exts
701 } else if f.Name == "XXX_extensions" { // special case
Rob Pikeaaa3a622010-03-20 22:32:34 -0700702 p.enc = (*Buffer).enc_map
703 p.dec = nil // not needed
David Symonds0bf1ad52013-10-11 09:07:50 +1100704 p.size = size_map
matloob@google.come51d0022016-05-23 09:09:04 -0400705 } else if f.Name == "XXX_unrecognized" { // special case
Russ Coxd4ce3f12012-09-12 10:36:26 +1000706 prop.unrecField = toField(&f)
David Symonds10c93ba2012-08-04 16:38:08 +1000707 }
Dave Day2ebff282016-04-18 12:44:00 +1000708 oneof := f.Tag.Get("protobuf_oneof") // special case
709 if oneof != "" {
710 // Oneof fields don't use the traditional protobuf tag.
711 p.OrigName = oneof
712 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700713 prop.Prop[i] = p
David Symondsd15e81b2011-10-03 14:31:12 -0700714 prop.order[i] = i
Rob Pikeaaa3a622010-03-20 22:32:34 -0700715 if debug {
716 print(i, " ", f.Name, " ", t.String(), " ")
717 if p.Tag > 0 {
718 print(p.String())
719 }
720 print("\n")
721 }
Dave Day2ebff282016-04-18 12:44:00 +1000722 if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") && oneof == "" {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700723 fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]")
724 }
725 }
726
David Symondsd15e81b2011-10-03 14:31:12 -0700727 // Re-order prop.order.
728 sort.Sort(prop)
729
David Symonds59b73b32015-08-24 13:22:02 +1000730 type oneofMessage interface {
Damien Neil08794902015-12-04 07:39:00 +1100731 XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{})
David Symonds59b73b32015-08-24 13:22:02 +1000732 }
733 if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok {
David Symonds1baed092015-08-25 15:42:00 +1000734 var oots []interface{}
Damien Neil08794902015-12-04 07:39:00 +1100735 prop.oneofMarshaler, prop.oneofUnmarshaler, prop.oneofSizer, oots = om.XXX_OneofFuncs()
David Symonds59b73b32015-08-24 13:22:02 +1000736 prop.stype = t
David Symonds1baed092015-08-25 15:42:00 +1000737
738 // Interpret oneof metadata.
739 prop.OneofTypes = make(map[string]*OneofProperties)
740 for _, oot := range oots {
741 oop := &OneofProperties{
742 Type: reflect.ValueOf(oot).Type(), // *T
743 Prop: new(Properties),
744 }
745 sft := oop.Type.Elem().Field(0)
746 oop.Prop.Name = sft.Name
747 oop.Prop.Parse(sft.Tag.Get("protobuf"))
748 // There will be exactly one interface field that
749 // this new value is assignable to.
750 for i := 0; i < t.NumField(); i++ {
751 f := t.Field(i)
752 if f.Type.Kind() != reflect.Interface {
753 continue
754 }
755 if !oop.Type.AssignableTo(f.Type) {
756 continue
757 }
758 oop.Field = i
759 break
760 }
761 prop.OneofTypes[oop.Prop.OrigName] = oop
762 }
David Symonds59b73b32015-08-24 13:22:02 +1000763 }
764
Rob Pikeaaa3a622010-03-20 22:32:34 -0700765 // build required counts
Rob Pikeaaa3a622010-03-20 22:32:34 -0700766 // build tags
767 reqCount := 0
David Symonds2bba1b22012-09-26 14:53:08 +1000768 prop.decoderOrigNames = make(map[string]int)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700769 for i, p := range prop.Prop {
David Symonds6e50db52012-02-11 15:56:22 +1100770 if strings.HasPrefix(p.Name, "XXX_") {
771 // Internal fields should not appear in tags/origNames maps.
772 // They are handled specially when encoding and decoding.
773 continue
774 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700775 if p.Required {
776 reqCount++
777 }
David Symonds2bba1b22012-09-26 14:53:08 +1000778 prop.decoderTags.put(p.Tag, i)
779 prop.decoderOrigNames[p.OrigName] = i
Rob Pikeaaa3a622010-03-20 22:32:34 -0700780 }
781 prop.reqCount = reqCount
Rob Pikeaaa3a622010-03-20 22:32:34 -0700782
Rob Pikeaaa3a622010-03-20 22:32:34 -0700783 return prop
784}
785
Rob Pikeaaa3a622010-03-20 22:32:34 -0700786// Return the Properties object for the x[0]'th field of the structure.
Rob Pike97e934d2011-04-11 12:52:49 -0700787func propByIndex(t reflect.Type, x []int) *Properties {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700788 if len(x) != 1 {
789 fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t)
790 return nil
791 }
792 prop := GetProperties(t)
793 return prop.Prop[x[0]]
794}
795
David Symonds7656e742011-07-22 14:54:17 +1000796// Get the address and type of a pointer to a struct from an interface.
Russ Coxd4ce3f12012-09-12 10:36:26 +1000797func getbase(pb Message) (t reflect.Type, b structPointer, err error) {
Rob Pikef1b341e2011-10-20 14:51:10 -0700798 if pb == nil {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700799 err = ErrNil
800 return
801 }
Rob Pikef1b341e2011-10-20 14:51:10 -0700802 // get the reflect type of the pointer to the struct.
Nigel Tao4ede8452011-04-28 11:27:25 +1000803 t = reflect.TypeOf(pb)
Rob Pikef1b341e2011-10-20 14:51:10 -0700804 // get the address of the struct.
805 value := reflect.ValueOf(pb)
Russ Coxd4ce3f12012-09-12 10:36:26 +1000806 b = toStructPointer(value)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700807 return
808}
809
Rob Pikeaaa3a622010-03-20 22:32:34 -0700810// A global registry of enum types.
811// The generated code will register the generated maps by calling RegisterEnum.
812
Rob Pikeaaa3a622010-03-20 22:32:34 -0700813var enumValueMaps = make(map[string]map[string]int32)
814
815// RegisterEnum is called from the generated code to install the enum descriptor
David Symondsf8a1fcc2013-05-03 08:51:23 +1000816// maps into the global table to aid parsing text format protocol buffers.
817func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[string]int32) {
818 if _, ok := enumValueMaps[typeName]; ok {
Rob Pike79c63792010-03-24 17:48:35 -0700819 panic("proto: duplicate enum registered: " + typeName)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700820 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700821 enumValueMaps[typeName] = valueMap
822}
David Symonds5d7f79b2015-10-19 11:37:00 +1100823
824// EnumValueMap returns the mapping from names to integers of the
825// enum type enumType, or a nil if not found.
826func EnumValueMap(enumType string) map[string]int32 {
827 return enumValueMaps[enumType]
828}
David Symondsa7f1e752015-11-02 15:31:00 +1100829
830// A registry of all linked message types.
David Symondsd3d78382015-11-05 09:41:00 +1100831// The string is a fully-qualified proto name ("pkg.Message").
832var (
833 protoTypes = make(map[string]reflect.Type)
834 revProtoTypes = make(map[reflect.Type]string)
835)
David Symondsa7f1e752015-11-02 15:31:00 +1100836
837// RegisterType is called from generated code and maps from the fully qualified
838// proto name to the type (pointer to struct) of the protocol buffer.
David Symondsd3d78382015-11-05 09:41:00 +1100839func RegisterType(x Message, name string) {
David Symondsa7f1e752015-11-02 15:31:00 +1100840 if _, ok := protoTypes[name]; ok {
841 // TODO: Some day, make this a panic.
842 log.Printf("proto: duplicate proto type registered: %s", name)
843 return
844 }
David Symondsd3d78382015-11-05 09:41:00 +1100845 t := reflect.TypeOf(x)
846 protoTypes[name] = t
847 revProtoTypes[t] = name
David Symondsa7f1e752015-11-02 15:31:00 +1100848}
David Symondsd3d78382015-11-05 09:41:00 +1100849
850// MessageName returns the fully-qualified proto name for the given message type.
851func MessageName(x Message) string { return revProtoTypes[reflect.TypeOf(x)] }
852
853// MessageType returns the message type (pointer to struct) for a named message.
854func MessageType(name string) reflect.Type { return protoTypes[name] }