github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/third_party/labix.org/v2/mgo/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  	"crypto/md5"
    37  	"crypto/rand"
    38  	"encoding/binary"
    39  	"encoding/hex"
    40  	"errors"
    41  	"fmt"
    42  	"io"
    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  // See the D type.
   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 = 0
   192  
   193  // machineId stores machine id generated once and used in subsequent calls
   194  // to NewObjectId function.
   195  var machineId = readMachineId()
   196  
   197  // initMachineId generates machine id and puts it into the machineId global
   198  // variable. If this function fails to get the hostname, it will cause
   199  // a runtime error.
   200  func readMachineId() []byte {
   201  	var sum [3]byte
   202  	id := sum[:]
   203  	hostname, err1 := os.Hostname()
   204  	if err1 != nil {
   205  		_, err2 := io.ReadFull(rand.Reader, id)
   206  		if err2 != nil {
   207  			panic(fmt.Errorf("cannot get hostname: %v; %v", err1, err2))
   208  		}
   209  		return id
   210  	}
   211  	hw := md5.New()
   212  	hw.Write([]byte(hostname))
   213  	copy(id, hw.Sum(nil))
   214  	return id
   215  }
   216  
   217  // NewObjectId returns a new unique ObjectId.
   218  // This function causes a runtime error if it fails to get the hostname
   219  // of the current machine.
   220  func NewObjectId() ObjectId {
   221  	var b [12]byte
   222  	// Timestamp, 4 bytes, big endian
   223  	binary.BigEndian.PutUint32(b[:], uint32(time.Now().Unix()))
   224  	// Machine, first 3 bytes of md5(hostname)
   225  	b[4] = machineId[0]
   226  	b[5] = machineId[1]
   227  	b[6] = machineId[2]
   228  	// Pid, 2 bytes, specs don't specify endianness, but we use big endian.
   229  	pid := os.Getpid()
   230  	b[7] = byte(pid >> 8)
   231  	b[8] = byte(pid)
   232  	// Increment, 3 bytes, big endian
   233  	i := atomic.AddUint32(&objectIdCounter, 1)
   234  	b[9] = byte(i >> 16)
   235  	b[10] = byte(i >> 8)
   236  	b[11] = byte(i)
   237  	return ObjectId(b[:])
   238  }
   239  
   240  // NewObjectIdWithTime returns a dummy ObjectId with the timestamp part filled
   241  // with the provided number of seconds from epoch UTC, and all other parts
   242  // filled with zeroes. It's not safe to insert a document with an id generated
   243  // by this method, it is useful only for queries to find documents with ids
   244  // generated before or after the specified timestamp.
   245  func NewObjectIdWithTime(t time.Time) ObjectId {
   246  	var b [12]byte
   247  	binary.BigEndian.PutUint32(b[:4], uint32(t.Unix()))
   248  	return ObjectId(string(b[:]))
   249  }
   250  
   251  // String returns a hex string representation of the id.
   252  // Example: ObjectIdHex("4d88e15b60f486e428412dc9").
   253  func (id ObjectId) String() string {
   254  	return fmt.Sprintf(`ObjectIdHex("%x")`, string(id))
   255  }
   256  
   257  // Hex returns a hex representation of the ObjectId.
   258  func (id ObjectId) Hex() string {
   259  	return hex.EncodeToString([]byte(id))
   260  }
   261  
   262  // MarshalJSON turns a bson.ObjectId into a json.Marshaller.
   263  func (id ObjectId) MarshalJSON() ([]byte, error) {
   264  	return []byte(fmt.Sprintf(`"%x"`, string(id))), nil
   265  }
   266  
   267  // UnmarshalJSON turns *bson.ObjectId into a json.Unmarshaller.
   268  func (id *ObjectId) UnmarshalJSON(data []byte) error {
   269  	if len(data) != 26 || data[0] != '"' || data[25] != '"' {
   270  		return errors.New(fmt.Sprintf("Invalid ObjectId in JSON: %s", string(data)))
   271  	}
   272  	var buf [12]byte
   273  	_, err := hex.Decode(buf[:], data[1:25])
   274  	if err != nil {
   275  		return errors.New(fmt.Sprintf("Invalid ObjectId in JSON: %s (%s)", string(data), err))
   276  	}
   277  	*id = ObjectId(string(buf[:]))
   278  	return nil
   279  }
   280  
   281  // Valid returns true if id is valid. A valid id must contain exactly 12 bytes.
   282  func (id ObjectId) Valid() bool {
   283  	return len(id) == 12
   284  }
   285  
   286  // byteSlice returns byte slice of id from start to end.
   287  // Calling this function with an invalid id will cause a runtime panic.
   288  func (id ObjectId) byteSlice(start, end int) []byte {
   289  	if len(id) != 12 {
   290  		panic(fmt.Sprintf("Invalid ObjectId: %q", string(id)))
   291  	}
   292  	return []byte(string(id)[start:end])
   293  }
   294  
   295  // Time returns the timestamp part of the id.
   296  // It's a runtime error to call this method with an invalid id.
   297  func (id ObjectId) Time() time.Time {
   298  	// First 4 bytes of ObjectId is 32-bit big-endian seconds from epoch.
   299  	secs := int64(binary.BigEndian.Uint32(id.byteSlice(0, 4)))
   300  	return time.Unix(secs, 0)
   301  }
   302  
   303  // Machine returns the 3-byte machine id part of the id.
   304  // It's a runtime error to call this method with an invalid id.
   305  func (id ObjectId) Machine() []byte {
   306  	return id.byteSlice(4, 7)
   307  }
   308  
   309  // Pid returns the process id part of the id.
   310  // It's a runtime error to call this method with an invalid id.
   311  func (id ObjectId) Pid() uint16 {
   312  	return binary.BigEndian.Uint16(id.byteSlice(7, 9))
   313  }
   314  
   315  // Counter returns the incrementing value part of the id.
   316  // It's a runtime error to call this method with an invalid id.
   317  func (id ObjectId) Counter() int32 {
   318  	b := id.byteSlice(9, 12)
   319  	// Counter is stored as big-endian 3-byte value
   320  	return int32(uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2]))
   321  }
   322  
   323  // The Symbol type is similar to a string and is used in languages with a
   324  // distinct symbol type.
   325  type Symbol string
   326  
   327  // Now returns the current time with millisecond precision. MongoDB stores
   328  // timestamps with the same precision, so a Time returned from this method
   329  // will not change after a roundtrip to the database. That's the only reason
   330  // why this function exists. Using the time.Now function also works fine
   331  // otherwise.
   332  func Now() time.Time {
   333  	return time.Unix(0, time.Now().UnixNano()/1e6*1e6)
   334  }
   335  
   336  // MongoTimestamp is a special internal type used by MongoDB that for some
   337  // strange reason has its own datatype defined in BSON.
   338  type MongoTimestamp int64
   339  
   340  type orderKey int64
   341  
   342  // MaxKey is a special value that compares higher than all other possible BSON
   343  // values in a MongoDB database.
   344  var MaxKey = orderKey(1<<63 - 1)
   345  
   346  // MinKey is a special value that compares lower than all other possible BSON
   347  // values in a MongoDB database.
   348  var MinKey = orderKey(-1 << 63)
   349  
   350  type undefined struct{}
   351  
   352  // Undefined represents the undefined BSON value.
   353  var Undefined undefined
   354  
   355  // Binary is a representation for non-standard binary values.  Any kind should
   356  // work, but the following are known as of this writing:
   357  //
   358  //   0x00 - Generic. This is decoded as []byte(data), not Binary{0x00, data}.
   359  //   0x01 - Function (!?)
   360  //   0x02 - Obsolete generic.
   361  //   0x03 - UUID
   362  //   0x05 - MD5
   363  //   0x80 - User defined.
   364  //
   365  type Binary struct {
   366  	Kind byte
   367  	Data []byte
   368  }
   369  
   370  // RegEx represents a regular expression.  The Options field may contain
   371  // individual characters defining the way in which the pattern should be
   372  // applied, and must be sorted. Valid options as of this writing are 'i' for
   373  // case insensitive matching, 'm' for multi-line matching, 'x' for verbose
   374  // mode, 'l' to make \w, \W, and similar be locale-dependent, 's' for dot-all
   375  // mode (a '.' matches everything), and 'u' to make \w, \W, and similar match
   376  // unicode. The value of the Options parameter is not verified before being
   377  // marshaled into the BSON format.
   378  type RegEx struct {
   379  	Pattern string
   380  	Options string
   381  }
   382  
   383  // JavaScript is a type that holds JavaScript code. If Scope is non-nil, it
   384  // will be marshaled as a mapping from identifiers to values that may be
   385  // used when evaluating the provided Code.
   386  type JavaScript struct {
   387  	Code  string
   388  	Scope interface{}
   389  }
   390  
   391  const initialBufferSize = 64
   392  
   393  func handleErr(err *error) {
   394  	if r := recover(); r != nil {
   395  		if _, ok := r.(runtime.Error); ok {
   396  			panic(r)
   397  		} else if _, ok := r.(externalPanic); ok {
   398  			panic(r)
   399  		} else if s, ok := r.(string); ok {
   400  			*err = errors.New(s)
   401  		} else if e, ok := r.(error); ok {
   402  			*err = e
   403  		} else {
   404  			panic(r)
   405  		}
   406  	}
   407  }
   408  
   409  // Marshal serializes the in value, which may be a map or a struct value.
   410  // In the case of struct values, only exported fields will be serialized.
   411  // The lowercased field name is used as the key for each exported field,
   412  // but this behavior may be changed using the respective field tag.
   413  // The tag may also contain flags to tweak the marshalling behavior for
   414  // the field. The tag formats accepted are:
   415  //
   416  //     "[<key>][,<flag1>[,<flag2>]]"
   417  //
   418  //     `(...) bson:"[<key>][,<flag1>[,<flag2>]]" (...)`
   419  //
   420  // The following flags are currently supported:
   421  //
   422  //     omitempty  Only include the field if it's not set to the zero
   423  //                value for the type or to empty slices or maps.
   424  //
   425  //     minsize    Marshal an int64 value as an int32, if that's feasible
   426  //                while preserving the numeric value.
   427  //
   428  //     inline     Inline the field, which must be a struct or a map,
   429  //                causing all of its fields or keys to be processed as if
   430  //                they were part of the outer struct. For maps, keys must
   431  //                not conflict with the bson keys of other struct fields.
   432  //
   433  // Some examples:
   434  //
   435  //     type T struct {
   436  //         A bool
   437  //         B int    "myb"
   438  //         C string "myc,omitempty"
   439  //         D string `bson:",omitempty" json:"jsonkey"`
   440  //         E int64  ",minsize"
   441  //         F int64  "myf,omitempty,minsize"
   442  //     }
   443  //
   444  func Marshal(in interface{}) (out []byte, err error) {
   445  	defer handleErr(&err)
   446  	e := &encoder{make([]byte, 0, initialBufferSize)}
   447  	e.addDoc(reflect.ValueOf(in))
   448  	return e.out, nil
   449  }
   450  
   451  // Unmarshal deserializes data from in into the out value.  The out value
   452  // must be a map, a pointer to a struct, or a pointer to a bson.D value.
   453  // The lowercased field name is used as the key for each exported field,
   454  // but this behavior may be changed using the respective field tag.
   455  // The tag may also contain flags to tweak the marshalling behavior for
   456  // the field. The tag formats accepted are:
   457  //
   458  //     "[<key>][,<flag1>[,<flag2>]]"
   459  //
   460  //     `(...) bson:"[<key>][,<flag1>[,<flag2>]]" (...)`
   461  //
   462  // The following flags are currently supported during unmarshal (see the
   463  // Marshal method for other flags):
   464  //
   465  //     inline     Inline the field, which must be a struct or a map.
   466  //                Inlined structs are handled as if its fields were part
   467  //                of the outer struct. An inlined map causes keys that do
   468  //                not match any other struct field to be inserted in the
   469  //                map rather than being discarded as usual.
   470  //
   471  // The target field or element types of out may not necessarily match
   472  // the BSON values of the provided data.  The following conversions are
   473  // made automatically:
   474  //
   475  // - Numeric types are converted if at least the integer part of the
   476  //   value would be preserved correctly
   477  // - Bools are converted to numeric types as 1 or 0
   478  // - Numeric types are converted to bools as true if not 0 or false otherwise
   479  // - Binary and string BSON data is converted to a string, array or byte slice
   480  //
   481  // If the value would not fit the type and cannot be converted, it's
   482  // silently skipped.
   483  //
   484  // Pointer values are initialized when necessary.
   485  func Unmarshal(in []byte, out interface{}) (err error) {
   486  	defer handleErr(&err)
   487  	v := reflect.ValueOf(out)
   488  	switch v.Kind() {
   489  	case reflect.Map, reflect.Ptr:
   490  		d := newDecoder(in)
   491  		d.readDocTo(v)
   492  	case reflect.Struct:
   493  		return errors.New("Unmarshal can't deal with struct values. Use a pointer.")
   494  	default:
   495  		return errors.New("Unmarshal needs a map or a pointer to a struct.")
   496  	}
   497  	return nil
   498  }
   499  
   500  // Unmarshal deserializes raw into the out value.  If the out value type
   501  // is not compatible with raw, a *bson.TypeError is returned.
   502  //
   503  // See the Unmarshal function documentation for more details on the
   504  // unmarshalling process.
   505  func (raw Raw) Unmarshal(out interface{}) (err error) {
   506  	defer handleErr(&err)
   507  	v := reflect.ValueOf(out)
   508  	switch v.Kind() {
   509  	case reflect.Ptr:
   510  		v = v.Elem()
   511  		fallthrough
   512  	case reflect.Map:
   513  		d := newDecoder(raw.Data)
   514  		good := d.readElemTo(v, raw.Kind)
   515  		if !good {
   516  			return &TypeError{v.Type(), raw.Kind}
   517  		}
   518  	case reflect.Struct:
   519  		return errors.New("Raw Unmarshal can't deal with struct values. Use a pointer.")
   520  	default:
   521  		return errors.New("Raw Unmarshal needs a map or a valid pointer.")
   522  	}
   523  	return nil
   524  }
   525  
   526  type TypeError struct {
   527  	Type reflect.Type
   528  	Kind byte
   529  }
   530  
   531  func (e *TypeError) Error() string {
   532  	return fmt.Sprintf("BSON kind 0x%02x isn't compatible with type %s", e.Kind, e.Type.String())
   533  }
   534  
   535  // --------------------------------------------------------------------------
   536  // Maintain a mapping of keys to structure field indexes
   537  
   538  type structInfo struct {
   539  	FieldsMap  map[string]fieldInfo
   540  	FieldsList []fieldInfo
   541  	InlineMap  int
   542  	Zero       reflect.Value
   543  }
   544  
   545  type fieldInfo struct {
   546  	Key       string
   547  	Num       int
   548  	OmitEmpty bool
   549  	MinSize   bool
   550  	Inline    []int
   551  }
   552  
   553  var structMap = make(map[reflect.Type]*structInfo)
   554  var structMapMutex sync.RWMutex
   555  
   556  type externalPanic string
   557  
   558  func (e externalPanic) String() string {
   559  	return string(e)
   560  }
   561  
   562  func getStructInfo(st reflect.Type) (*structInfo, error) {
   563  	structMapMutex.RLock()
   564  	sinfo, found := structMap[st]
   565  	structMapMutex.RUnlock()
   566  	if found {
   567  		return sinfo, nil
   568  	}
   569  	n := st.NumField()
   570  	fieldsMap := make(map[string]fieldInfo)
   571  	fieldsList := make([]fieldInfo, 0, n)
   572  	inlineMap := -1
   573  	for i := 0; i != n; i++ {
   574  		field := st.Field(i)
   575  		if field.PkgPath != "" {
   576  			continue // Private field
   577  		}
   578  
   579  		info := fieldInfo{Num: i}
   580  
   581  		tag := field.Tag.Get("bson")
   582  		if tag == "" && strings.Index(string(field.Tag), ":") < 0 {
   583  			tag = string(field.Tag)
   584  		}
   585  		if tag == "-" {
   586  			continue
   587  		}
   588  
   589  		// XXX Drop this after a few releases.
   590  		if s := strings.Index(tag, "/"); s >= 0 {
   591  			recommend := tag[:s]
   592  			for _, c := range tag[s+1:] {
   593  				switch c {
   594  				case 'c':
   595  					recommend += ",omitempty"
   596  				case 's':
   597  					recommend += ",minsize"
   598  				default:
   599  					msg := fmt.Sprintf("Unsupported flag %q in tag %q of type %s", string([]byte{uint8(c)}), tag, st)
   600  					panic(externalPanic(msg))
   601  				}
   602  			}
   603  			msg := fmt.Sprintf("Replace tag %q in field %s of type %s by %q", tag, field.Name, st, recommend)
   604  			panic(externalPanic(msg))
   605  		}
   606  
   607  		inline := false
   608  		fields := strings.Split(tag, ",")
   609  		if len(fields) > 1 {
   610  			for _, flag := range fields[1:] {
   611  				switch flag {
   612  				case "omitempty":
   613  					info.OmitEmpty = true
   614  				case "minsize":
   615  					info.MinSize = true
   616  				case "inline":
   617  					inline = true
   618  				default:
   619  					msg := fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st)
   620  					panic(externalPanic(msg))
   621  				}
   622  			}
   623  			tag = fields[0]
   624  		}
   625  
   626  		if inline {
   627  			switch field.Type.Kind() {
   628  			case reflect.Map:
   629  				if inlineMap >= 0 {
   630  					return nil, errors.New("Multiple ,inline maps in struct " + st.String())
   631  				}
   632  				if field.Type.Key() != reflect.TypeOf("") {
   633  					return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String())
   634  				}
   635  				inlineMap = info.Num
   636  			case reflect.Struct:
   637  				sinfo, err := getStructInfo(field.Type)
   638  				if err != nil {
   639  					return nil, err
   640  				}
   641  				for _, finfo := range sinfo.FieldsList {
   642  					if _, found := fieldsMap[finfo.Key]; found {
   643  						msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String()
   644  						return nil, errors.New(msg)
   645  					}
   646  					if finfo.Inline == nil {
   647  						finfo.Inline = []int{i, finfo.Num}
   648  					} else {
   649  						finfo.Inline = append([]int{i}, finfo.Inline...)
   650  					}
   651  					fieldsMap[finfo.Key] = finfo
   652  					fieldsList = append(fieldsList, finfo)
   653  				}
   654  			default:
   655  				panic("Option ,inline needs a struct value or map field")
   656  			}
   657  			continue
   658  		}
   659  
   660  		if tag != "" {
   661  			info.Key = tag
   662  		} else {
   663  			info.Key = strings.ToLower(field.Name)
   664  		}
   665  
   666  		if _, found = fieldsMap[info.Key]; found {
   667  			msg := "Duplicated key '" + info.Key + "' in struct " + st.String()
   668  			return nil, errors.New(msg)
   669  		}
   670  
   671  		fieldsList = append(fieldsList, info)
   672  		fieldsMap[info.Key] = info
   673  	}
   674  	sinfo = &structInfo{
   675  		fieldsMap,
   676  		fieldsList,
   677  		inlineMap,
   678  		reflect.New(st).Elem(),
   679  	}
   680  	structMapMutex.Lock()
   681  	structMap[st] = sinfo
   682  	structMapMutex.Unlock()
   683  	return sinfo, nil
   684  }