github.com/gogo/protobuf@v1.3.2/proto/properties.go (about) 1 // Protocol Buffers for Go with Gadgets 2 // 3 // Copyright (c) 2013, The GoGo Authors. All rights reserved. 4 // http://github.com/gogo/protobuf 5 // 6 // Go support for Protocol Buffers - Google's data interchange format 7 // 8 // Copyright 2010 The Go Authors. All rights reserved. 9 // https://github.com/golang/protobuf 10 // 11 // Redistribution and use in source and binary forms, with or without 12 // modification, are permitted provided that the following conditions are 13 // met: 14 // 15 // * Redistributions of source code must retain the above copyright 16 // notice, this list of conditions and the following disclaimer. 17 // * Redistributions in binary form must reproduce the above 18 // copyright notice, this list of conditions and the following disclaimer 19 // in the documentation and/or other materials provided with the 20 // distribution. 21 // * Neither the name of Google Inc. nor the names of its 22 // contributors may be used to endorse or promote products derived from 23 // this software without specific prior written permission. 24 // 25 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 37 package proto 38 39 /* 40 * Routines for encoding data into the wire format for protocol buffers. 41 */ 42 43 import ( 44 "fmt" 45 "log" 46 "reflect" 47 "sort" 48 "strconv" 49 "strings" 50 "sync" 51 ) 52 53 const debug bool = false 54 55 // Constants that identify the encoding of a value on the wire. 56 const ( 57 WireVarint = 0 58 WireFixed64 = 1 59 WireBytes = 2 60 WireStartGroup = 3 61 WireEndGroup = 4 62 WireFixed32 = 5 63 ) 64 65 // tagMap is an optimization over map[int]int for typical protocol buffer 66 // use-cases. Encoded protocol buffers are often in tag order with small tag 67 // numbers. 68 type tagMap struct { 69 fastTags []int 70 slowTags map[int]int 71 } 72 73 // tagMapFastLimit is the upper bound on the tag number that will be stored in 74 // the tagMap slice rather than its map. 75 const tagMapFastLimit = 1024 76 77 func (p *tagMap) get(t int) (int, bool) { 78 if t > 0 && t < tagMapFastLimit { 79 if t >= len(p.fastTags) { 80 return 0, false 81 } 82 fi := p.fastTags[t] 83 return fi, fi >= 0 84 } 85 fi, ok := p.slowTags[t] 86 return fi, ok 87 } 88 89 func (p *tagMap) put(t int, fi int) { 90 if t > 0 && t < tagMapFastLimit { 91 for len(p.fastTags) < t+1 { 92 p.fastTags = append(p.fastTags, -1) 93 } 94 p.fastTags[t] = fi 95 return 96 } 97 if p.slowTags == nil { 98 p.slowTags = make(map[int]int) 99 } 100 p.slowTags[t] = fi 101 } 102 103 // StructProperties represents properties for all the fields of a struct. 104 // decoderTags and decoderOrigNames should only be used by the decoder. 105 type StructProperties struct { 106 Prop []*Properties // properties for each field 107 reqCount int // required count 108 decoderTags tagMap // map from proto tag to struct field number 109 decoderOrigNames map[string]int // map from original name to struct field number 110 order []int // list of struct field numbers in tag order 111 112 // OneofTypes contains information about the oneof fields in this message. 113 // It is keyed by the original name of a field. 114 OneofTypes map[string]*OneofProperties 115 } 116 117 // OneofProperties represents information about a specific field in a oneof. 118 type OneofProperties struct { 119 Type reflect.Type // pointer to generated struct type for this oneof field 120 Field int // struct field number of the containing oneof in the message 121 Prop *Properties 122 } 123 124 // Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec. 125 // See encode.go, (*Buffer).enc_struct. 126 127 func (sp *StructProperties) Len() int { return len(sp.order) } 128 func (sp *StructProperties) Less(i, j int) bool { 129 return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag 130 } 131 func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] } 132 133 // Properties represents the protocol-specific behavior of a single struct field. 134 type Properties struct { 135 Name string // name of the field, for error messages 136 OrigName string // original name before protocol compiler (always set) 137 JSONName string // name to use for JSON; determined by protoc 138 Wire string 139 WireType int 140 Tag int 141 Required bool 142 Optional bool 143 Repeated bool 144 Packed bool // relevant for repeated primitives only 145 Enum string // set for enum types only 146 proto3 bool // whether this is known to be a proto3 field 147 oneof bool // whether this is a oneof field 148 149 Default string // default value 150 HasDefault bool // whether an explicit default was provided 151 CustomType string 152 CastType string 153 StdTime bool 154 StdDuration bool 155 WktPointer bool 156 157 stype reflect.Type // set for struct types only 158 ctype reflect.Type // set for custom types only 159 sprop *StructProperties // set for struct types only 160 161 mtype reflect.Type // set for map types only 162 MapKeyProp *Properties // set for map types only 163 MapValProp *Properties // set for map types only 164 } 165 166 // String formats the properties in the protobuf struct field tag style. 167 func (p *Properties) String() string { 168 s := p.Wire 169 s += "," 170 s += strconv.Itoa(p.Tag) 171 if p.Required { 172 s += ",req" 173 } 174 if p.Optional { 175 s += ",opt" 176 } 177 if p.Repeated { 178 s += ",rep" 179 } 180 if p.Packed { 181 s += ",packed" 182 } 183 s += ",name=" + p.OrigName 184 if p.JSONName != p.OrigName { 185 s += ",json=" + p.JSONName 186 } 187 if p.proto3 { 188 s += ",proto3" 189 } 190 if p.oneof { 191 s += ",oneof" 192 } 193 if len(p.Enum) > 0 { 194 s += ",enum=" + p.Enum 195 } 196 if p.HasDefault { 197 s += ",def=" + p.Default 198 } 199 return s 200 } 201 202 // Parse populates p by parsing a string in the protobuf struct field tag style. 203 func (p *Properties) Parse(s string) { 204 // "bytes,49,opt,name=foo,def=hello!" 205 fields := strings.Split(s, ",") // breaks def=, but handled below. 206 if len(fields) < 2 { 207 log.Printf("proto: tag has too few fields: %q", s) 208 return 209 } 210 211 p.Wire = fields[0] 212 switch p.Wire { 213 case "varint": 214 p.WireType = WireVarint 215 case "fixed32": 216 p.WireType = WireFixed32 217 case "fixed64": 218 p.WireType = WireFixed64 219 case "zigzag32": 220 p.WireType = WireVarint 221 case "zigzag64": 222 p.WireType = WireVarint 223 case "bytes", "group": 224 p.WireType = WireBytes 225 // no numeric converter for non-numeric types 226 default: 227 log.Printf("proto: tag has unknown wire type: %q", s) 228 return 229 } 230 231 var err error 232 p.Tag, err = strconv.Atoi(fields[1]) 233 if err != nil { 234 return 235 } 236 237 outer: 238 for i := 2; i < len(fields); i++ { 239 f := fields[i] 240 switch { 241 case f == "req": 242 p.Required = true 243 case f == "opt": 244 p.Optional = true 245 case f == "rep": 246 p.Repeated = true 247 case f == "packed": 248 p.Packed = true 249 case strings.HasPrefix(f, "name="): 250 p.OrigName = f[5:] 251 case strings.HasPrefix(f, "json="): 252 p.JSONName = f[5:] 253 case strings.HasPrefix(f, "enum="): 254 p.Enum = f[5:] 255 case f == "proto3": 256 p.proto3 = true 257 case f == "oneof": 258 p.oneof = true 259 case strings.HasPrefix(f, "def="): 260 p.HasDefault = true 261 p.Default = f[4:] // rest of string 262 if i+1 < len(fields) { 263 // Commas aren't escaped, and def is always last. 264 p.Default += "," + strings.Join(fields[i+1:], ",") 265 break outer 266 } 267 case strings.HasPrefix(f, "embedded="): 268 p.OrigName = strings.Split(f, "=")[1] 269 case strings.HasPrefix(f, "customtype="): 270 p.CustomType = strings.Split(f, "=")[1] 271 case strings.HasPrefix(f, "casttype="): 272 p.CastType = strings.Split(f, "=")[1] 273 case f == "stdtime": 274 p.StdTime = true 275 case f == "stdduration": 276 p.StdDuration = true 277 case f == "wktptr": 278 p.WktPointer = true 279 } 280 } 281 } 282 283 var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem() 284 285 // setFieldProps initializes the field properties for submessages and maps. 286 func (p *Properties) setFieldProps(typ reflect.Type, f *reflect.StructField, lockGetProp bool) { 287 isMap := typ.Kind() == reflect.Map 288 if len(p.CustomType) > 0 && !isMap { 289 p.ctype = typ 290 p.setTag(lockGetProp) 291 return 292 } 293 if p.StdTime && !isMap { 294 p.setTag(lockGetProp) 295 return 296 } 297 if p.StdDuration && !isMap { 298 p.setTag(lockGetProp) 299 return 300 } 301 if p.WktPointer && !isMap { 302 p.setTag(lockGetProp) 303 return 304 } 305 switch t1 := typ; t1.Kind() { 306 case reflect.Struct: 307 p.stype = typ 308 case reflect.Ptr: 309 if t1.Elem().Kind() == reflect.Struct { 310 p.stype = t1.Elem() 311 } 312 case reflect.Slice: 313 switch t2 := t1.Elem(); t2.Kind() { 314 case reflect.Ptr: 315 switch t3 := t2.Elem(); t3.Kind() { 316 case reflect.Struct: 317 p.stype = t3 318 } 319 case reflect.Struct: 320 p.stype = t2 321 } 322 323 case reflect.Map: 324 325 p.mtype = t1 326 p.MapKeyProp = &Properties{} 327 p.MapKeyProp.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp) 328 p.MapValProp = &Properties{} 329 vtype := p.mtype.Elem() 330 if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice { 331 // The value type is not a message (*T) or bytes ([]byte), 332 // so we need encoders for the pointer to this type. 333 vtype = reflect.PtrTo(vtype) 334 } 335 336 p.MapValProp.CustomType = p.CustomType 337 p.MapValProp.StdDuration = p.StdDuration 338 p.MapValProp.StdTime = p.StdTime 339 p.MapValProp.WktPointer = p.WktPointer 340 p.MapValProp.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp) 341 } 342 p.setTag(lockGetProp) 343 } 344 345 func (p *Properties) setTag(lockGetProp bool) { 346 if p.stype != nil { 347 if lockGetProp { 348 p.sprop = GetProperties(p.stype) 349 } else { 350 p.sprop = getPropertiesLocked(p.stype) 351 } 352 } 353 } 354 355 var ( 356 marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() 357 ) 358 359 // Init populates the properties from a protocol buffer struct tag. 360 func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) { 361 p.init(typ, name, tag, f, true) 362 } 363 364 func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) { 365 // "bytes,49,opt,def=hello!" 366 p.Name = name 367 p.OrigName = name 368 if tag == "" { 369 return 370 } 371 p.Parse(tag) 372 p.setFieldProps(typ, f, lockGetProp) 373 } 374 375 var ( 376 propertiesMu sync.RWMutex 377 propertiesMap = make(map[reflect.Type]*StructProperties) 378 ) 379 380 // GetProperties returns the list of properties for the type represented by t. 381 // t must represent a generated struct type of a protocol message. 382 func GetProperties(t reflect.Type) *StructProperties { 383 if t.Kind() != reflect.Struct { 384 panic("proto: type must have kind struct") 385 } 386 387 // Most calls to GetProperties in a long-running program will be 388 // retrieving details for types we have seen before. 389 propertiesMu.RLock() 390 sprop, ok := propertiesMap[t] 391 propertiesMu.RUnlock() 392 if ok { 393 return sprop 394 } 395 396 propertiesMu.Lock() 397 sprop = getPropertiesLocked(t) 398 propertiesMu.Unlock() 399 return sprop 400 } 401 402 type ( 403 oneofFuncsIface interface { 404 XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{}) 405 } 406 oneofWrappersIface interface { 407 XXX_OneofWrappers() []interface{} 408 } 409 ) 410 411 // getPropertiesLocked requires that propertiesMu is held. 412 func getPropertiesLocked(t reflect.Type) *StructProperties { 413 if prop, ok := propertiesMap[t]; ok { 414 return prop 415 } 416 417 prop := new(StructProperties) 418 // in case of recursive protos, fill this in now. 419 propertiesMap[t] = prop 420 421 // build properties 422 prop.Prop = make([]*Properties, t.NumField()) 423 prop.order = make([]int, t.NumField()) 424 425 isOneofMessage := false 426 for i := 0; i < t.NumField(); i++ { 427 f := t.Field(i) 428 p := new(Properties) 429 name := f.Name 430 p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false) 431 432 oneof := f.Tag.Get("protobuf_oneof") // special case 433 if oneof != "" { 434 isOneofMessage = true 435 // Oneof fields don't use the traditional protobuf tag. 436 p.OrigName = oneof 437 } 438 prop.Prop[i] = p 439 prop.order[i] = i 440 if debug { 441 print(i, " ", f.Name, " ", t.String(), " ") 442 if p.Tag > 0 { 443 print(p.String()) 444 } 445 print("\n") 446 } 447 } 448 449 // Re-order prop.order. 450 sort.Sort(prop) 451 452 if isOneofMessage { 453 var oots []interface{} 454 switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) { 455 case oneofFuncsIface: 456 _, _, _, oots = m.XXX_OneofFuncs() 457 case oneofWrappersIface: 458 oots = m.XXX_OneofWrappers() 459 } 460 if len(oots) > 0 { 461 // Interpret oneof metadata. 462 prop.OneofTypes = make(map[string]*OneofProperties) 463 for _, oot := range oots { 464 oop := &OneofProperties{ 465 Type: reflect.ValueOf(oot).Type(), // *T 466 Prop: new(Properties), 467 } 468 sft := oop.Type.Elem().Field(0) 469 oop.Prop.Name = sft.Name 470 oop.Prop.Parse(sft.Tag.Get("protobuf")) 471 // There will be exactly one interface field that 472 // this new value is assignable to. 473 for i := 0; i < t.NumField(); i++ { 474 f := t.Field(i) 475 if f.Type.Kind() != reflect.Interface { 476 continue 477 } 478 if !oop.Type.AssignableTo(f.Type) { 479 continue 480 } 481 oop.Field = i 482 break 483 } 484 prop.OneofTypes[oop.Prop.OrigName] = oop 485 } 486 } 487 } 488 489 // build required counts 490 // build tags 491 reqCount := 0 492 prop.decoderOrigNames = make(map[string]int) 493 for i, p := range prop.Prop { 494 if strings.HasPrefix(p.Name, "XXX_") { 495 // Internal fields should not appear in tags/origNames maps. 496 // They are handled specially when encoding and decoding. 497 continue 498 } 499 if p.Required { 500 reqCount++ 501 } 502 prop.decoderTags.put(p.Tag, i) 503 prop.decoderOrigNames[p.OrigName] = i 504 } 505 prop.reqCount = reqCount 506 507 return prop 508 } 509 510 // A global registry of enum types. 511 // The generated code will register the generated maps by calling RegisterEnum. 512 513 var enumValueMaps = make(map[string]map[string]int32) 514 var enumStringMaps = make(map[string]map[int32]string) 515 516 // RegisterEnum is called from the generated code to install the enum descriptor 517 // maps into the global table to aid parsing text format protocol buffers. 518 func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[string]int32) { 519 if _, ok := enumValueMaps[typeName]; ok { 520 panic("proto: duplicate enum registered: " + typeName) 521 } 522 enumValueMaps[typeName] = valueMap 523 if _, ok := enumStringMaps[typeName]; ok { 524 panic("proto: duplicate enum registered: " + typeName) 525 } 526 enumStringMaps[typeName] = unusedNameMap 527 } 528 529 // EnumValueMap returns the mapping from names to integers of the 530 // enum type enumType, or a nil if not found. 531 func EnumValueMap(enumType string) map[string]int32 { 532 return enumValueMaps[enumType] 533 } 534 535 // A registry of all linked message types. 536 // The string is a fully-qualified proto name ("pkg.Message"). 537 var ( 538 protoTypedNils = make(map[string]Message) // a map from proto names to typed nil pointers 539 protoMapTypes = make(map[string]reflect.Type) // a map from proto names to map types 540 revProtoTypes = make(map[reflect.Type]string) 541 ) 542 543 // RegisterType is called from generated code and maps from the fully qualified 544 // proto name to the type (pointer to struct) of the protocol buffer. 545 func RegisterType(x Message, name string) { 546 if _, ok := protoTypedNils[name]; ok { 547 // TODO: Some day, make this a panic. 548 log.Printf("proto: duplicate proto type registered: %s", name) 549 return 550 } 551 t := reflect.TypeOf(x) 552 if v := reflect.ValueOf(x); v.Kind() == reflect.Ptr && v.Pointer() == 0 { 553 // Generated code always calls RegisterType with nil x. 554 // This check is just for extra safety. 555 protoTypedNils[name] = x 556 } else { 557 protoTypedNils[name] = reflect.Zero(t).Interface().(Message) 558 } 559 revProtoTypes[t] = name 560 } 561 562 // RegisterMapType is called from generated code and maps from the fully qualified 563 // proto name to the native map type of the proto map definition. 564 func RegisterMapType(x interface{}, name string) { 565 if reflect.TypeOf(x).Kind() != reflect.Map { 566 panic(fmt.Sprintf("RegisterMapType(%T, %q); want map", x, name)) 567 } 568 if _, ok := protoMapTypes[name]; ok { 569 log.Printf("proto: duplicate proto type registered: %s", name) 570 return 571 } 572 t := reflect.TypeOf(x) 573 protoMapTypes[name] = t 574 revProtoTypes[t] = name 575 } 576 577 // MessageName returns the fully-qualified proto name for the given message type. 578 func MessageName(x Message) string { 579 type xname interface { 580 XXX_MessageName() string 581 } 582 if m, ok := x.(xname); ok { 583 return m.XXX_MessageName() 584 } 585 return revProtoTypes[reflect.TypeOf(x)] 586 } 587 588 // MessageType returns the message type (pointer to struct) for a named message. 589 // The type is not guaranteed to implement proto.Message if the name refers to a 590 // map entry. 591 func MessageType(name string) reflect.Type { 592 if t, ok := protoTypedNils[name]; ok { 593 return reflect.TypeOf(t) 594 } 595 return protoMapTypes[name] 596 } 597 598 // A registry of all linked proto files. 599 var ( 600 protoFiles = make(map[string][]byte) // file name => fileDescriptor 601 ) 602 603 // RegisterFile is called from generated code and maps from the 604 // full file name of a .proto file to its compressed FileDescriptorProto. 605 func RegisterFile(filename string, fileDescriptor []byte) { 606 protoFiles[filename] = fileDescriptor 607 } 608 609 // FileDescriptor returns the compressed FileDescriptorProto for a .proto file. 610 func FileDescriptor(filename string) []byte { return protoFiles[filename] }