github.com/lianghucheng/zrddz@v0.0.0-20200923083010-c71f680932e2/src/gopkg.in/mgo.v2/bson/bson.go (about) 1 // BSON library for Go 2 // 3 // Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net> 4 // 5 // All rights reserved. 6 // 7 // Redistribution and use in source and binary forms, with or without 8 // modification, are permitted provided that the following conditions are met: 9 // 10 // 1. Redistributions of source code must retain the above copyright notice, this 11 // list of conditions and the following disclaimer. 12 // 2. Redistributions in binary form must reproduce the above copyright notice, 13 // this list of conditions and the following disclaimer in the documentation 14 // and/or other materials provided with the distribution. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 27 // Package bson is an implementation of the BSON specification for Go: 28 // 29 // http://bsonspec.org 30 // 31 // It was created as part of the mgo MongoDB driver for Go, but is standalone 32 // and may be used on its own without the driver. 33 package bson 34 35 import ( 36 "bytes" 37 "crypto/md5" 38 "encoding/binary" 39 "encoding/hex" 40 "encoding/json" 41 "errors" 42 "fmt" 43 "os" 44 "reflect" 45 "runtime" 46 "strings" 47 "sync" 48 "sync/atomic" 49 "time" 50 ) 51 52 // -------------------------------------------------------------------------- 53 // The public API. 54 55 // A value implementing the bson.Getter interface will have its GetBSON 56 // method called when the given value has to be marshalled, and the result 57 // of this method will be marshaled in place of the actual object. 58 // 59 // If GetBSON returns return a non-nil error, the marshalling procedure 60 // will stop and error out with the provided value. 61 type Getter interface { 62 GetBSON() (interface{}, error) 63 } 64 65 // A value implementing the bson.Setter interface will receive the BSON 66 // value via the SetBSON method during unmarshaling, and the object 67 // itself will not be changed as usual. 68 // 69 // If setting the value works, the method should return nil or alternatively 70 // bson.SetZero to set the respective field to its zero value (nil for 71 // pointer types). If SetBSON returns a value of type bson.TypeError, the 72 // BSON value will be omitted from a map or slice being decoded and the 73 // unmarshalling will continue. If it returns any other non-nil error, the 74 // unmarshalling procedure will stop and error out with the provided value. 75 // 76 // This interface is generally useful in pointer receivers, since the method 77 // will want to change the receiver. A type field that implements the Setter 78 // interface doesn't have to be a pointer, though. 79 // 80 // Unlike the usual behavior, unmarshalling onto a value that implements a 81 // Setter interface will NOT reset the value to its zero state. This allows 82 // the value to decide by itself how to be unmarshalled. 83 // 84 // For example: 85 // 86 // type MyString string 87 // 88 // func (s *MyString) SetBSON(raw bson.Raw) error { 89 // return raw.Unmarshal(s) 90 // } 91 // 92 type Setter interface { 93 SetBSON(raw Raw) error 94 } 95 96 // SetZero may be returned from a SetBSON method to have the value set to 97 // its respective zero value. When used in pointer values, this will set the 98 // field to nil rather than to the pre-allocated value. 99 var SetZero = errors.New("set to zero") 100 101 // M is a convenient alias for a map[string]interface{} map, useful for 102 // dealing with BSON in a native way. For instance: 103 // 104 // bson.M{"a": 1, "b": true} 105 // 106 // There's no special handling for this type in addition to what's done anyway 107 // for an equivalent map type. Elements in the map will be dumped in an 108 // undefined ordered. See also the bson.D type for an ordered alternative. 109 type M map[string]interface{} 110 111 // D represents a BSON document containing ordered elements. For example: 112 // 113 // bson.D{{"a", 1}, {"b", true}} 114 // 115 // In some situations, such as when creating indexes for MongoDB, the order in 116 // which the elements are defined is important. If the order is not important, 117 // using a map is generally more comfortable. See bson.M and bson.RawD. 118 type D []DocElem 119 120 // DocElem is an element of the bson.D document representation. 121 type DocElem struct { 122 Name string 123 Value interface{} 124 } 125 126 // Map returns a map out of the ordered element name/value pairs in d. 127 func (d D) Map() (m M) { 128 m = make(M, len(d)) 129 for _, item := range d { 130 m[item.Name] = item.Value 131 } 132 return m 133 } 134 135 // The Raw type represents raw unprocessed BSON documents and elements. 136 // Kind is the kind of element as defined per the BSON specification, and 137 // Data is the raw unprocessed data for the respective element. 138 // Using this type it is possible to unmarshal or marshal values partially. 139 // 140 // Relevant documentation: 141 // 142 // http://bsonspec.org/#/specification 143 // 144 type Raw struct { 145 Kind byte 146 Data []byte 147 } 148 149 // RawD represents a BSON document containing raw unprocessed elements. 150 // This low-level representation may be useful when lazily processing 151 // documents of uncertain content, or when manipulating the raw content 152 // documents in general. 153 type RawD []RawDocElem 154 155 // See the RawD type. 156 type RawDocElem struct { 157 Name string 158 Value Raw 159 } 160 161 // ObjectId is a unique ID identifying a BSON value. It must be exactly 12 bytes 162 // long. MongoDB objects by default have such a property set in their "_id" 163 // property. 164 // 165 // http://www.mongodb.org/display/DOCS/Object+IDs 166 type ObjectId string 167 168 // ObjectIdHex returns an ObjectId from the provided hex representation. 169 // Calling this function with an invalid hex representation will 170 // cause a runtime panic. See the IsObjectIdHex function. 171 func ObjectIdHex(s string) ObjectId { 172 d, err := hex.DecodeString(s) 173 if err != nil || len(d) != 12 { 174 panic(fmt.Sprintf("invalid input to ObjectIdHex: %q", s)) 175 } 176 return ObjectId(d) 177 } 178 179 // IsObjectIdHex returns whether s is a valid hex representation of 180 // an ObjectId. See the ObjectIdHex function. 181 func IsObjectIdHex(s string) bool { 182 if len(s) != 24 { 183 return false 184 } 185 _, err := hex.DecodeString(s) 186 return err == nil 187 } 188 189 // objectIdCounter is atomically incremented when generating a new ObjectId 190 // using NewObjectId() function. It's used as a counter part of an id. 191 var objectIdCounter uint32 = readRandomUint32() 192 193 // readRandomUint32 returns a random objectIdCounter. 194 func readRandomUint32() uint32 { 195 // We've found systems hanging in this function due to lack of entropy. 196 // The randomness of these bytes is just preventing nearby clashes, so 197 // just look at the time. 198 return uint32(time.Now().UnixNano()) 199 } 200 201 // machineId stores machine id generated once and used in subsequent calls 202 // to NewObjectId function. 203 var machineId = readMachineId() 204 var processId = os.Getpid() 205 206 // readMachineId generates and returns a machine id. 207 // If this function fails to get the hostname it will cause a runtime error. 208 func readMachineId() []byte { 209 var sum [3]byte 210 id := sum[:] 211 hostname, err1 := os.Hostname() 212 if err1 != nil { 213 n := uint32(time.Now().UnixNano()) 214 sum[0] = byte(n >> 0) 215 sum[1] = byte(n >> 8) 216 sum[2] = byte(n >> 16) 217 return id 218 } 219 hw := md5.New() 220 hw.Write([]byte(hostname)) 221 copy(id, hw.Sum(nil)) 222 return id 223 } 224 225 // NewObjectId returns a new unique ObjectId. 226 func NewObjectId() ObjectId { 227 var b [12]byte 228 // Timestamp, 4 bytes, big endian 229 binary.BigEndian.PutUint32(b[:], uint32(time.Now().Unix())) 230 // Machine, first 3 bytes of md5(hostname) 231 b[4] = machineId[0] 232 b[5] = machineId[1] 233 b[6] = machineId[2] 234 // Pid, 2 bytes, specs don't specify endianness, but we use big endian. 235 b[7] = byte(processId >> 8) 236 b[8] = byte(processId) 237 // Increment, 3 bytes, big endian 238 i := atomic.AddUint32(&objectIdCounter, 1) 239 b[9] = byte(i >> 16) 240 b[10] = byte(i >> 8) 241 b[11] = byte(i) 242 return ObjectId(b[:]) 243 } 244 245 // NewObjectIdWithTime returns a dummy ObjectId with the timestamp part filled 246 // with the provided number of seconds from epoch UTC, and all other parts 247 // filled with zeroes. It's not safe to insert a document with an id generated 248 // by this method, it is useful only for queries to find documents with ids 249 // generated before or after the specified timestamp. 250 func NewObjectIdWithTime(t time.Time) ObjectId { 251 var b [12]byte 252 binary.BigEndian.PutUint32(b[:4], uint32(t.Unix())) 253 return ObjectId(string(b[:])) 254 } 255 256 // String returns a hex string representation of the id. 257 // Example: ObjectIdHex("4d88e15b60f486e428412dc9"). 258 func (id ObjectId) String() string { 259 return fmt.Sprintf(`ObjectIdHex("%x")`, string(id)) 260 } 261 262 // Hex returns a hex representation of the ObjectId. 263 func (id ObjectId) Hex() string { 264 return hex.EncodeToString([]byte(id)) 265 } 266 267 // MarshalJSON turns a bson.ObjectId into a json.Marshaller. 268 func (id ObjectId) MarshalJSON() ([]byte, error) { 269 return []byte(fmt.Sprintf(`"%x"`, string(id))), nil 270 } 271 272 var nullBytes = []byte("null") 273 274 // UnmarshalJSON turns *bson.ObjectId into a json.Unmarshaller. 275 func (id *ObjectId) UnmarshalJSON(data []byte) error { 276 if len(data) > 0 && (data[0] == '{' || data[0] == 'O') { 277 var v struct { 278 Id json.RawMessage `json:"$oid"` 279 Func struct { 280 Id json.RawMessage 281 } `json:"$oidFunc"` 282 } 283 err := jdec(data, &v) 284 if err == nil { 285 if len(v.Id) > 0 { 286 data = []byte(v.Id) 287 } else { 288 data = []byte(v.Func.Id) 289 } 290 } 291 } 292 if len(data) == 2 && data[0] == '"' && data[1] == '"' || bytes.Equal(data, nullBytes) { 293 *id = "" 294 return nil 295 } 296 if len(data) != 26 || data[0] != '"' || data[25] != '"' { 297 return errors.New(fmt.Sprintf("invalid ObjectId in JSON: %s", string(data))) 298 } 299 var buf [12]byte 300 _, err := hex.Decode(buf[:], data[1:25]) 301 if err != nil { 302 return errors.New(fmt.Sprintf("invalid ObjectId in JSON: %s (%s)", string(data), err)) 303 } 304 *id = ObjectId(string(buf[:])) 305 return nil 306 } 307 308 // MarshalText turns bson.ObjectId into an encoding.TextMarshaler. 309 func (id ObjectId) MarshalText() ([]byte, error) { 310 return []byte(fmt.Sprintf("%x", string(id))), nil 311 } 312 313 // UnmarshalText turns *bson.ObjectId into an encoding.TextUnmarshaler. 314 func (id *ObjectId) UnmarshalText(data []byte) error { 315 if len(data) == 1 && data[0] == ' ' || len(data) == 0 { 316 *id = "" 317 return nil 318 } 319 if len(data) != 24 { 320 return fmt.Errorf("invalid ObjectId: %s", data) 321 } 322 var buf [12]byte 323 _, err := hex.Decode(buf[:], data[:]) 324 if err != nil { 325 return fmt.Errorf("invalid ObjectId: %s (%s)", data, err) 326 } 327 *id = ObjectId(string(buf[:])) 328 return nil 329 } 330 331 // Valid returns true if id is valid. A valid id must contain exactly 12 bytes. 332 func (id ObjectId) Valid() bool { 333 return len(id) == 12 334 } 335 336 // byteSlice returns byte slice of id from start to end. 337 // Calling this function with an invalid id will cause a runtime panic. 338 func (id ObjectId) byteSlice(start, end int) []byte { 339 if len(id) != 12 { 340 panic(fmt.Sprintf("invalid ObjectId: %q", string(id))) 341 } 342 return []byte(string(id)[start:end]) 343 } 344 345 // Time returns the timestamp part of the id. 346 // It's a runtime error to call this method with an invalid id. 347 func (id ObjectId) Time() time.Time { 348 // First 4 bytes of ObjectId is 32-bit big-endian seconds from epoch. 349 secs := int64(binary.BigEndian.Uint32(id.byteSlice(0, 4))) 350 return time.Unix(secs, 0) 351 } 352 353 // Machine returns the 3-byte machine id part of the id. 354 // It's a runtime error to call this method with an invalid id. 355 func (id ObjectId) Machine() []byte { 356 return id.byteSlice(4, 7) 357 } 358 359 // Pid returns the process id part of the id. 360 // It's a runtime error to call this method with an invalid id. 361 func (id ObjectId) Pid() uint16 { 362 return binary.BigEndian.Uint16(id.byteSlice(7, 9)) 363 } 364 365 // Counter returns the incrementing value part of the id. 366 // It's a runtime error to call this method with an invalid id. 367 func (id ObjectId) Counter() int32 { 368 b := id.byteSlice(9, 12) 369 // Counter is stored as big-endian 3-byte value 370 return int32(uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2])) 371 } 372 373 // The Symbol type is similar to a string and is used in languages with a 374 // distinct symbol type. 375 type Symbol string 376 377 // Now returns the current time with millisecond precision. MongoDB stores 378 // timestamps with the same precision, so a Time returned from this method 379 // will not change after a roundtrip to the database. That's the only reason 380 // why this function exists. Using the time.Now function also works fine 381 // otherwise. 382 func Now() time.Time { 383 return time.Unix(0, time.Now().UnixNano()/1e6*1e6) 384 } 385 386 // MongoTimestamp is a special internal type used by MongoDB that for some 387 // strange reason has its own datatype defined in BSON. 388 type MongoTimestamp int64 389 390 type orderKey int64 391 392 // MaxKey is a special value that compares higher than all other possible BSON 393 // values in a MongoDB database. 394 var MaxKey = orderKey(1<<63 - 1) 395 396 // MinKey is a special value that compares lower than all other possible BSON 397 // values in a MongoDB database. 398 var MinKey = orderKey(-1 << 63) 399 400 type undefined struct{} 401 402 // Undefined represents the undefined BSON value. 403 var Undefined undefined 404 405 // Binary is a representation for non-standard binary values. Any kind should 406 // work, but the following are known as of this writing: 407 // 408 // 0x00 - Generic. This is decoded as []byte(data), not Binary{0x00, data}. 409 // 0x01 - Function (!?) 410 // 0x02 - Obsolete generic. 411 // 0x03 - UUID 412 // 0x05 - MD5 413 // 0x80 - User defined. 414 // 415 type Binary struct { 416 Kind byte 417 Data []byte 418 } 419 420 // RegEx represents a regular expression. The Options field may contain 421 // individual characters defining the way in which the pattern should be 422 // applied, and must be sorted. Valid options as of this writing are 'i' for 423 // case insensitive matching, 'm' for multi-line matching, 'x' for verbose 424 // mode, 'l' to make \w, \W, and similar be locale-dependent, 's' for dot-all 425 // mode (a '.' matches everything), and 'u' to make \w, \W, and similar match 426 // unicode. The value of the Options parameter is not verified before being 427 // marshaled into the BSON format. 428 type RegEx struct { 429 Pattern string 430 Options string 431 } 432 433 // JavaScript is a type that holds JavaScript code. If Scope is non-nil, it 434 // will be marshaled as a mapping from identifiers to values that may be 435 // used when evaluating the provided Code. 436 type JavaScript struct { 437 Code string 438 Scope interface{} 439 } 440 441 // DBPointer refers to a document id in a namespace. 442 // 443 // This type is deprecated in the BSON specification and should not be used 444 // except for backwards compatibility with ancient applications. 445 type DBPointer struct { 446 Namespace string 447 Id ObjectId 448 } 449 450 const initialBufferSize = 64 451 452 func handleErr(err *error) { 453 if r := recover(); r != nil { 454 if _, ok := r.(runtime.Error); ok { 455 panic(r) 456 } else if _, ok := r.(externalPanic); ok { 457 panic(r) 458 } else if s, ok := r.(string); ok { 459 *err = errors.New(s) 460 } else if e, ok := r.(error); ok { 461 *err = e 462 } else { 463 panic(r) 464 } 465 } 466 } 467 468 // Marshal serializes the in value, which may be a map or a struct value. 469 // In the case of struct values, only exported fields will be serialized, 470 // and the order of serialized fields will match that of the struct itself. 471 // The lowercased field name is used as the key for each exported field, 472 // but this behavior may be changed using the respective field tag. 473 // The tag may also contain flags to tweak the marshalling behavior for 474 // the field. The tag formats accepted are: 475 // 476 // "[<key>][,<flag1>[,<flag2>]]" 477 // 478 // `(...) bson:"[<key>][,<flag1>[,<flag2>]]" (...)` 479 // 480 // The following flags are currently supported: 481 // 482 // omitempty Only include the field if it's not set to the zero 483 // value for the type or to empty slices or maps. 484 // 485 // minsize Marshal an int64 value as an int32, if that's feasible 486 // while preserving the numeric value. 487 // 488 // inline Inline the field, which must be a struct or a map, 489 // causing all of its fields or keys to be processed as if 490 // they were part of the outer struct. For maps, keys must 491 // not conflict with the bson keys of other struct fields. 492 // 493 // Some examples: 494 // 495 // type T struct { 496 // A bool 497 // B int "myb" 498 // C string "myc,omitempty" 499 // D string `bson:",omitempty" json:"jsonkey"` 500 // E int64 ",minsize" 501 // F int64 "myf,omitempty,minsize" 502 // } 503 // 504 func Marshal(in interface{}) (out []byte, err error) { 505 defer handleErr(&err) 506 e := &encoder{make([]byte, 0, initialBufferSize)} 507 e.addDoc(reflect.ValueOf(in)) 508 return e.out, nil 509 } 510 511 // Unmarshal deserializes data from in into the out value. The out value 512 // must be a map, a pointer to a struct, or a pointer to a bson.D value. 513 // In the case of struct values, only exported fields will be deserialized. 514 // The lowercased field name is used as the key for each exported field, 515 // but this behavior may be changed using the respective field tag. 516 // The tag may also contain flags to tweak the marshalling behavior for 517 // the field. The tag formats accepted are: 518 // 519 // "[<key>][,<flag1>[,<flag2>]]" 520 // 521 // `(...) bson:"[<key>][,<flag1>[,<flag2>]]" (...)` 522 // 523 // The following flags are currently supported during unmarshal (see the 524 // Marshal method for other flags): 525 // 526 // inline Inline the field, which must be a struct or a map. 527 // Inlined structs are handled as if its fields were part 528 // of the outer struct. An inlined map causes keys that do 529 // not match any other struct field to be inserted in the 530 // map rather than being discarded as usual. 531 // 532 // The target field or element types of out may not necessarily match 533 // the BSON values of the provided data. The following conversions are 534 // made automatically: 535 // 536 // - Numeric types are converted if at least the integer part of the 537 // value would be preserved correctly 538 // - Bools are converted to numeric types as 1 or 0 539 // - Numeric types are converted to bools as true if not 0 or false otherwise 540 // - Binary and string BSON data is converted to a string, array or byte slice 541 // 542 // If the value would not fit the type and cannot be converted, it's 543 // silently skipped. 544 // 545 // Pointer values are initialized when necessary. 546 func Unmarshal(in []byte, out interface{}) (err error) { 547 if raw, ok := out.(*Raw); ok { 548 raw.Kind = 3 549 raw.Data = in 550 return nil 551 } 552 defer handleErr(&err) 553 v := reflect.ValueOf(out) 554 switch v.Kind() { 555 case reflect.Ptr: 556 fallthrough 557 case reflect.Map: 558 d := newDecoder(in) 559 d.readDocTo(v) 560 case reflect.Struct: 561 return errors.New("Unmarshal can't deal with struct values. Use a pointer.") 562 default: 563 return errors.New("Unmarshal needs a map or a pointer to a struct.") 564 } 565 return nil 566 } 567 568 // Unmarshal deserializes raw into the out value. If the out value type 569 // is not compatible with raw, a *bson.TypeError is returned. 570 // 571 // See the Unmarshal function documentation for more details on the 572 // unmarshalling process. 573 func (raw Raw) Unmarshal(out interface{}) (err error) { 574 defer handleErr(&err) 575 v := reflect.ValueOf(out) 576 switch v.Kind() { 577 case reflect.Ptr: 578 v = v.Elem() 579 fallthrough 580 case reflect.Map: 581 d := newDecoder(raw.Data) 582 good := d.readElemTo(v, raw.Kind) 583 if !good { 584 return &TypeError{v.Type(), raw.Kind} 585 } 586 case reflect.Struct: 587 return errors.New("Raw Unmarshal can't deal with struct values. Use a pointer.") 588 default: 589 return errors.New("Raw Unmarshal needs a map or a valid pointer.") 590 } 591 return nil 592 } 593 594 type TypeError struct { 595 Type reflect.Type 596 Kind byte 597 } 598 599 func (e *TypeError) Error() string { 600 return fmt.Sprintf("BSON kind 0x%02x isn't compatible with type %s", e.Kind, e.Type.String()) 601 } 602 603 // -------------------------------------------------------------------------- 604 // Maintain a mapping of keys to structure field indexes 605 606 type structInfo struct { 607 FieldsMap map[string]fieldInfo 608 FieldsList []fieldInfo 609 InlineMap int 610 Zero reflect.Value 611 } 612 613 type fieldInfo struct { 614 Key string 615 Num int 616 OmitEmpty bool 617 MinSize bool 618 Inline []int 619 } 620 621 var structMap = make(map[reflect.Type]*structInfo) 622 var structMapMutex sync.RWMutex 623 624 type externalPanic string 625 626 func (e externalPanic) String() string { 627 return string(e) 628 } 629 630 func getStructInfo(st reflect.Type) (*structInfo, error) { 631 structMapMutex.RLock() 632 sinfo, found := structMap[st] 633 structMapMutex.RUnlock() 634 if found { 635 return sinfo, nil 636 } 637 n := st.NumField() 638 fieldsMap := make(map[string]fieldInfo) 639 fieldsList := make([]fieldInfo, 0, n) 640 inlineMap := -1 641 for i := 0; i != n; i++ { 642 field := st.Field(i) 643 if field.PkgPath != "" && !field.Anonymous { 644 continue // Private field 645 } 646 647 info := fieldInfo{Num: i} 648 649 tag := field.Tag.Get("bson") 650 if tag == "" && strings.Index(string(field.Tag), ":") < 0 { 651 tag = string(field.Tag) 652 } 653 if tag == "-" { 654 continue 655 } 656 657 inline := false 658 fields := strings.Split(tag, ",") 659 if len(fields) > 1 { 660 for _, flag := range fields[1:] { 661 switch flag { 662 case "omitempty": 663 info.OmitEmpty = true 664 case "minsize": 665 info.MinSize = true 666 case "inline": 667 inline = true 668 default: 669 msg := fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st) 670 panic(externalPanic(msg)) 671 } 672 } 673 tag = fields[0] 674 } 675 676 if inline { 677 switch field.Type.Kind() { 678 case reflect.Map: 679 if inlineMap >= 0 { 680 return nil, errors.New("Multiple ,inline maps in struct " + st.String()) 681 } 682 if field.Type.Key() != reflect.TypeOf("") { 683 return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String()) 684 } 685 inlineMap = info.Num 686 case reflect.Struct: 687 sinfo, err := getStructInfo(field.Type) 688 if err != nil { 689 return nil, err 690 } 691 for _, finfo := range sinfo.FieldsList { 692 if _, found := fieldsMap[finfo.Key]; found { 693 msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String() 694 return nil, errors.New(msg) 695 } 696 if finfo.Inline == nil { 697 finfo.Inline = []int{i, finfo.Num} 698 } else { 699 finfo.Inline = append([]int{i}, finfo.Inline...) 700 } 701 fieldsMap[finfo.Key] = finfo 702 fieldsList = append(fieldsList, finfo) 703 } 704 default: 705 panic("Option ,inline needs a struct value or map field") 706 } 707 continue 708 } 709 710 if tag != "" { 711 info.Key = tag 712 } else { 713 info.Key = strings.ToLower(field.Name) 714 } 715 716 if _, found = fieldsMap[info.Key]; found { 717 msg := "Duplicated key '" + info.Key + "' in struct " + st.String() 718 return nil, errors.New(msg) 719 } 720 721 fieldsList = append(fieldsList, info) 722 fieldsMap[info.Key] = info 723 } 724 sinfo = &structInfo{ 725 fieldsMap, 726 fieldsList, 727 inlineMap, 728 reflect.New(st).Elem(), 729 } 730 structMapMutex.Lock() 731 structMap[st] = sinfo 732 structMapMutex.Unlock() 733 return sinfo, nil 734 }