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  }