blob: eb87ef6208a2b431f7fb352b8182b636c64a036d [file] [log] [blame]
Serge Bazanskicc25bdf2018-10-25 14:02:58 +02001// 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.
33package bson
34
35import (
36 "bytes"
37 "crypto/md5"
38 "crypto/rand"
39 "encoding/binary"
40 "encoding/hex"
41 "encoding/json"
42 "errors"
43 "fmt"
44 "io"
45 "math"
46 "os"
47 "reflect"
48 "runtime"
49 "strings"
50 "sync"
51 "sync/atomic"
52 "time"
53)
54
55//go:generate go run bson_corpus_spec_test_generator.go
56
57// --------------------------------------------------------------------------
58// The public API.
59
60// Element types constants from BSON specification.
61const (
62 ElementFloat64 byte = 0x01
63 ElementString byte = 0x02
64 ElementDocument byte = 0x03
65 ElementArray byte = 0x04
66 ElementBinary byte = 0x05
67 Element06 byte = 0x06
68 ElementObjectId byte = 0x07
69 ElementBool byte = 0x08
70 ElementDatetime byte = 0x09
71 ElementNil byte = 0x0A
72 ElementRegEx byte = 0x0B
73 ElementDBPointer byte = 0x0C
74 ElementJavaScriptWithoutScope byte = 0x0D
75 ElementSymbol byte = 0x0E
76 ElementJavaScriptWithScope byte = 0x0F
77 ElementInt32 byte = 0x10
78 ElementTimestamp byte = 0x11
79 ElementInt64 byte = 0x12
80 ElementDecimal128 byte = 0x13
81 ElementMinKey byte = 0xFF
82 ElementMaxKey byte = 0x7F
83
84 BinaryGeneric byte = 0x00
85 BinaryFunction byte = 0x01
86 BinaryBinaryOld byte = 0x02
87 BinaryUUIDOld byte = 0x03
88 BinaryUUID byte = 0x04
89 BinaryMD5 byte = 0x05
90 BinaryUserDefined byte = 0x80
91)
92
93// Getter interface: a value implementing the bson.Getter interface will have its GetBSON
94// method called when the given value has to be marshalled, and the result
95// of this method will be marshaled in place of the actual object.
96//
97// If GetBSON returns return a non-nil error, the marshalling procedure
98// will stop and error out with the provided value.
99type Getter interface {
100 GetBSON() (interface{}, error)
101}
102
103// Setter interface: a value implementing the bson.Setter interface will receive the BSON
104// value via the SetBSON method during unmarshaling, and the object
105// itself will not be changed as usual.
106//
107// If setting the value works, the method should return nil or alternatively
108// bson.ErrSetZero to set the respective field to its zero value (nil for
109// pointer types). If SetBSON returns a value of type bson.TypeError, the
110// BSON value will be omitted from a map or slice being decoded and the
111// unmarshalling will continue. If it returns any other non-nil error, the
112// unmarshalling procedure will stop and error out with the provided value.
113//
114// This interface is generally useful in pointer receivers, since the method
115// will want to change the receiver. A type field that implements the Setter
116// interface doesn't have to be a pointer, though.
117//
118// Unlike the usual behavior, unmarshalling onto a value that implements a
119// Setter interface will NOT reset the value to its zero state. This allows
120// the value to decide by itself how to be unmarshalled.
121//
122// For example:
123//
124// type MyString string
125//
126// func (s *MyString) SetBSON(raw bson.Raw) error {
127// return raw.Unmarshal(s)
128// }
129//
130type Setter interface {
131 SetBSON(raw Raw) error
132}
133
134// ErrSetZero may be returned from a SetBSON method to have the value set to
135// its respective zero value. When used in pointer values, this will set the
136// field to nil rather than to the pre-allocated value.
137var ErrSetZero = errors.New("set to zero")
138
139// M is a convenient alias for a map[string]interface{} map, useful for
140// dealing with BSON in a native way. For instance:
141//
142// bson.M{"a": 1, "b": true}
143//
144// There's no special handling for this type in addition to what's done anyway
145// for an equivalent map type. Elements in the map will be dumped in an
146// undefined ordered. See also the bson.D type for an ordered alternative.
147type M map[string]interface{}
148
149// D represents a BSON document containing ordered elements. For example:
150//
151// bson.D{{"a", 1}, {"b", true}}
152//
153// In some situations, such as when creating indexes for MongoDB, the order in
154// which the elements are defined is important. If the order is not important,
155// using a map is generally more comfortable. See bson.M and bson.RawD.
156type D []DocElem
157
158// DocElem is an element of the bson.D document representation.
159type DocElem struct {
160 Name string
161 Value interface{}
162}
163
164// Map returns a map out of the ordered element name/value pairs in d.
165func (d D) Map() (m M) {
166 m = make(M, len(d))
167 for _, item := range d {
168 m[item.Name] = item.Value
169 }
170 return m
171}
172
173// The Raw type represents raw unprocessed BSON documents and elements.
174// Kind is the kind of element as defined per the BSON specification, and
175// Data is the raw unprocessed data for the respective element.
176// Using this type it is possible to unmarshal or marshal values partially.
177//
178// Relevant documentation:
179//
180// http://bsonspec.org/#/specification
181//
182type Raw struct {
183 Kind byte
184 Data []byte
185}
186
187// RawD represents a BSON document containing raw unprocessed elements.
188// This low-level representation may be useful when lazily processing
189// documents of uncertain content, or when manipulating the raw content
190// documents in general.
191type RawD []RawDocElem
192
193// RawDocElem elements of RawD type.
194type RawDocElem struct {
195 Name string
196 Value Raw
197}
198
199// ObjectId is a unique ID identifying a BSON value. It must be exactly 12 bytes
200// long. MongoDB objects by default have such a property set in their "_id"
201// property.
202//
203// http://www.mongodb.org/display/DOCS/Object+Ids
204type ObjectId string
205
206// ObjectIdHex returns an ObjectId from the provided hex representation.
207// Calling this function with an invalid hex representation will
208// cause a runtime panic. See the IsObjectIdHex function.
209func ObjectIdHex(s string) ObjectId {
210 d, err := hex.DecodeString(s)
211 if err != nil || len(d) != 12 {
212 panic(fmt.Sprintf("invalid input to ObjectIdHex: %q", s))
213 }
214 return ObjectId(d)
215}
216
217// IsObjectIdHex returns whether s is a valid hex representation of
218// an ObjectId. See the ObjectIdHex function.
219func IsObjectIdHex(s string) bool {
220 if len(s) != 24 {
221 return false
222 }
223 _, err := hex.DecodeString(s)
224 return err == nil
225}
226
227// objectIdCounter is atomically incremented when generating a new ObjectId
228// using NewObjectId() function. It's used as a counter part of an id.
229var objectIdCounter = readRandomUint32()
230
231// readRandomUint32 returns a random objectIdCounter.
232func readRandomUint32() uint32 {
233 var b [4]byte
234 _, err := io.ReadFull(rand.Reader, b[:])
235 if err != nil {
236 panic(fmt.Errorf("cannot read random object id: %v", err))
237 }
238 return uint32((uint32(b[0]) << 0) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24))
239}
240
241// machineId stores machine id generated once and used in subsequent calls
242// to NewObjectId function.
243var machineId = readMachineId()
244var processId = os.Getpid()
245
246// readMachineId generates and returns a machine id.
247// If this function fails to get the hostname it will cause a runtime error.
248func readMachineId() []byte {
249 var sum [3]byte
250 id := sum[:]
251 hostname, err1 := os.Hostname()
252 if err1 != nil {
253 _, err2 := io.ReadFull(rand.Reader, id)
254 if err2 != nil {
255 panic(fmt.Errorf("cannot get hostname: %v; %v", err1, err2))
256 }
257 return id
258 }
259 hw := md5.New()
260 hw.Write([]byte(hostname))
261 copy(id, hw.Sum(nil))
262 return id
263}
264
265// NewObjectId returns a new unique ObjectId.
266func NewObjectId() ObjectId {
267 var b [12]byte
268 // Timestamp, 4 bytes, big endian
269 binary.BigEndian.PutUint32(b[:], uint32(time.Now().Unix()))
270 // Machine, first 3 bytes of md5(hostname)
271 b[4] = machineId[0]
272 b[5] = machineId[1]
273 b[6] = machineId[2]
274 // Pid, 2 bytes, specs don't specify endianness, but we use big endian.
275 b[7] = byte(processId >> 8)
276 b[8] = byte(processId)
277 // Increment, 3 bytes, big endian
278 i := atomic.AddUint32(&objectIdCounter, 1)
279 b[9] = byte(i >> 16)
280 b[10] = byte(i >> 8)
281 b[11] = byte(i)
282 return ObjectId(b[:])
283}
284
285// NewObjectIdWithTime returns a dummy ObjectId with the timestamp part filled
286// with the provided number of seconds from epoch UTC, and all other parts
287// filled with zeroes. It's not safe to insert a document with an id generated
288// by this method, it is useful only for queries to find documents with ids
289// generated before or after the specified timestamp.
290func NewObjectIdWithTime(t time.Time) ObjectId {
291 var b [12]byte
292 binary.BigEndian.PutUint32(b[:4], uint32(t.Unix()))
293 return ObjectId(string(b[:]))
294}
295
296// String returns a hex string representation of the id.
297// Example: ObjectIdHex("4d88e15b60f486e428412dc9").
298func (id ObjectId) String() string {
299 return fmt.Sprintf(`ObjectIdHex("%x")`, string(id))
300}
301
302// Hex returns a hex representation of the ObjectId.
303func (id ObjectId) Hex() string {
304 return hex.EncodeToString([]byte(id))
305}
306
307// MarshalJSON turns a bson.ObjectId into a json.Marshaller.
308func (id ObjectId) MarshalJSON() ([]byte, error) {
309 return []byte(fmt.Sprintf(`"%x"`, string(id))), nil
310}
311
312var nullBytes = []byte("null")
313
314// UnmarshalJSON turns *bson.ObjectId into a json.Unmarshaller.
315func (id *ObjectId) UnmarshalJSON(data []byte) error {
316 if len(data) > 0 && (data[0] == '{' || data[0] == 'O') {
317 var v struct {
318 Id json.RawMessage `json:"$oid"`
319 Func struct {
320 Id json.RawMessage
321 } `json:"$oidFunc"`
322 }
323 err := jdec(data, &v)
324 if err == nil {
325 if len(v.Id) > 0 {
326 data = []byte(v.Id)
327 } else {
328 data = []byte(v.Func.Id)
329 }
330 }
331 }
332 if len(data) == 2 && data[0] == '"' && data[1] == '"' || bytes.Equal(data, nullBytes) {
333 *id = ""
334 return nil
335 }
336 if len(data) != 26 || data[0] != '"' || data[25] != '"' {
337 return fmt.Errorf("invalid ObjectId in JSON: %s", string(data))
338 }
339 var buf [12]byte
340 _, err := hex.Decode(buf[:], data[1:25])
341 if err != nil {
342 return fmt.Errorf("invalid ObjectId in JSON: %s (%s)", string(data), err)
343 }
344 *id = ObjectId(string(buf[:]))
345 return nil
346}
347
348// MarshalText turns bson.ObjectId into an encoding.TextMarshaler.
349func (id ObjectId) MarshalText() ([]byte, error) {
350 return []byte(fmt.Sprintf("%x", string(id))), nil
351}
352
353// UnmarshalText turns *bson.ObjectId into an encoding.TextUnmarshaler.
354func (id *ObjectId) UnmarshalText(data []byte) error {
355 if len(data) == 1 && data[0] == ' ' || len(data) == 0 {
356 *id = ""
357 return nil
358 }
359 if len(data) != 24 {
360 return fmt.Errorf("invalid ObjectId: %s", data)
361 }
362 var buf [12]byte
363 _, err := hex.Decode(buf[:], data[:])
364 if err != nil {
365 return fmt.Errorf("invalid ObjectId: %s (%s)", data, err)
366 }
367 *id = ObjectId(string(buf[:]))
368 return nil
369}
370
371// Valid returns true if id is valid. A valid id must contain exactly 12 bytes.
372func (id ObjectId) Valid() bool {
373 return len(id) == 12
374}
375
376// byteSlice returns byte slice of id from start to end.
377// Calling this function with an invalid id will cause a runtime panic.
378func (id ObjectId) byteSlice(start, end int) []byte {
379 if len(id) != 12 {
380 panic(fmt.Sprintf("invalid ObjectId: %q", string(id)))
381 }
382 return []byte(string(id)[start:end])
383}
384
385// Time returns the timestamp part of the id.
386// It's a runtime error to call this method with an invalid id.
387func (id ObjectId) Time() time.Time {
388 // First 4 bytes of ObjectId is 32-bit big-endian seconds from epoch.
389 secs := int64(binary.BigEndian.Uint32(id.byteSlice(0, 4)))
390 return time.Unix(secs, 0)
391}
392
393// Machine returns the 3-byte machine id part of the id.
394// It's a runtime error to call this method with an invalid id.
395func (id ObjectId) Machine() []byte {
396 return id.byteSlice(4, 7)
397}
398
399// Pid returns the process id part of the id.
400// It's a runtime error to call this method with an invalid id.
401func (id ObjectId) Pid() uint16 {
402 return binary.BigEndian.Uint16(id.byteSlice(7, 9))
403}
404
405// Counter returns the incrementing value part of the id.
406// It's a runtime error to call this method with an invalid id.
407func (id ObjectId) Counter() int32 {
408 b := id.byteSlice(9, 12)
409 // Counter is stored as big-endian 3-byte value
410 return int32(uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2]))
411}
412
413// The Symbol type is similar to a string and is used in languages with a
414// distinct symbol type.
415type Symbol string
416
417// Now returns the current time with millisecond precision. MongoDB stores
418// timestamps with the same precision, so a Time returned from this method
419// will not change after a roundtrip to the database. That's the only reason
420// why this function exists. Using the time.Now function also works fine
421// otherwise.
422func Now() time.Time {
423 return time.Unix(0, time.Now().UnixNano()/1e6*1e6)
424}
425
426// MongoTimestamp is a special internal type used by MongoDB that for some
427// strange reason has its own datatype defined in BSON.
428type MongoTimestamp int64
429
430// Time returns the time part of ts which is stored with second precision.
431func (ts MongoTimestamp) Time() time.Time {
432 return time.Unix(int64(uint64(ts)>>32), 0)
433}
434
435// Counter returns the counter part of ts.
436func (ts MongoTimestamp) Counter() uint32 {
437 return uint32(ts)
438}
439
440// NewMongoTimestamp creates a timestamp using the given
441// date `t` (with second precision) and counter `c` (unique for `t`).
442//
443// Returns an error if time `t` is not between 1970-01-01T00:00:00Z
444// and 2106-02-07T06:28:15Z (inclusive).
445//
446// Note that two MongoTimestamps should never have the same (time, counter) combination:
447// the caller must ensure the counter `c` is increased if creating multiple MongoTimestamp
448// values for the same time `t` (ignoring fractions of seconds).
449func NewMongoTimestamp(t time.Time, c uint32) (MongoTimestamp, error) {
450 u := t.Unix()
451 if u < 0 || u > math.MaxUint32 {
452 return -1, errors.New("invalid value for time")
453 }
454
455 i := int64(u<<32 | int64(c))
456
457 return MongoTimestamp(i), nil
458}
459
460type orderKey int64
461
462// MaxKey is a special value that compares higher than all other possible BSON
463// values in a MongoDB database.
464var MaxKey = orderKey(1<<63 - 1)
465
466// MinKey is a special value that compares lower than all other possible BSON
467// values in a MongoDB database.
468var MinKey = orderKey(-1 << 63)
469
470type undefined struct{}
471
472// Undefined represents the undefined BSON value.
473var Undefined undefined
474
475// Binary is a representation for non-standard binary values. Any kind should
476// work, but the following are known as of this writing:
477//
478// 0x00 - Generic. This is decoded as []byte(data), not Binary{0x00, data}.
479// 0x01 - Function (!?)
480// 0x02 - Obsolete generic.
481// 0x03 - UUID
482// 0x05 - MD5
483// 0x80 - User defined.
484//
485type Binary struct {
486 Kind byte
487 Data []byte
488}
489
490// RegEx represents a regular expression. The Options field may contain
491// individual characters defining the way in which the pattern should be
492// applied, and must be sorted. Valid options as of this writing are 'i' for
493// case insensitive matching, 'm' for multi-line matching, 'x' for verbose
494// mode, 'l' to make \w, \W, and similar be locale-dependent, 's' for dot-all
495// mode (a '.' matches everything), and 'u' to make \w, \W, and similar match
496// unicode. The value of the Options parameter is not verified before being
497// marshaled into the BSON format.
498type RegEx struct {
499 Pattern string
500 Options string
501}
502
503// JavaScript is a type that holds JavaScript code. If Scope is non-nil, it
504// will be marshaled as a mapping from identifiers to values that may be
505// used when evaluating the provided Code.
506type JavaScript struct {
507 Code string
508 Scope interface{}
509}
510
511// DBPointer refers to a document id in a namespace.
512//
513// This type is deprecated in the BSON specification and should not be used
514// except for backwards compatibility with ancient applications.
515type DBPointer struct {
516 Namespace string
517 Id ObjectId
518}
519
520const initialBufferSize = 64
521
522func handleErr(err *error) {
523 if r := recover(); r != nil {
524 if _, ok := r.(runtime.Error); ok {
525 panic(r)
526 } else if _, ok := r.(externalPanic); ok {
527 panic(r)
528 } else if s, ok := r.(string); ok {
529 *err = errors.New(s)
530 } else if e, ok := r.(error); ok {
531 *err = e
532 } else {
533 panic(r)
534 }
535 }
536}
537
538// Marshal serializes the in value, which may be a map or a struct value.
539// In the case of struct values, only exported fields will be serialized,
540// and the order of serialized fields will match that of the struct itself.
541// The lowercased field name is used as the key for each exported field,
542// but this behavior may be changed using the respective field tag.
543// The tag may also contain flags to tweak the marshalling behavior for
544// the field. The tag formats accepted are:
545//
546// "[<key>][,<flag1>[,<flag2>]]"
547//
548// `(...) bson:"[<key>][,<flag1>[,<flag2>]]" (...)`
549//
550// The following flags are currently supported:
551//
552// omitempty Only include the field if it's not set to the zero
553// value for the type or to empty slices or maps.
554//
555// minsize Marshal an int64 value as an int32, if that's feasible
556// while preserving the numeric value.
557//
558// inline Inline the field, which must be a struct or a map,
559// causing all of its fields or keys to be processed as if
560// they were part of the outer struct. For maps, keys must
561// not conflict with the bson keys of other struct fields.
562//
563// Some examples:
564//
565// type T struct {
566// A bool
567// B int "myb"
568// C string "myc,omitempty"
569// D string `bson:",omitempty" json:"jsonkey"`
570// E int64 ",minsize"
571// F int64 "myf,omitempty,minsize"
572// }
573//
574func Marshal(in interface{}) (out []byte, err error) {
575 return MarshalBuffer(in, make([]byte, 0, initialBufferSize))
576}
577
578// MarshalBuffer behaves the same way as Marshal, except that instead of
579// allocating a new byte slice it tries to use the received byte slice and
580// only allocates more memory if necessary to fit the marshaled value.
581func MarshalBuffer(in interface{}, buf []byte) (out []byte, err error) {
582 defer handleErr(&err)
583 e := &encoder{buf}
584 e.addDoc(reflect.ValueOf(in))
585 return e.out, nil
586}
587
588// Unmarshal deserializes data from in into the out value. The out value
589// must be a map, a pointer to a struct, or a pointer to a bson.D value.
590// In the case of struct values, only exported fields will be deserialized.
591// The lowercased field name is used as the key for each exported field,
592// but this behavior may be changed using the respective field tag.
593// The tag may also contain flags to tweak the marshalling behavior for
594// the field. The tag formats accepted are:
595//
596// "[<key>][,<flag1>[,<flag2>]]"
597//
598// `(...) bson:"[<key>][,<flag1>[,<flag2>]]" (...)`
599//
600// The following flags are currently supported during unmarshal (see the
601// Marshal method for other flags):
602//
603// inline Inline the field, which must be a struct or a map.
604// Inlined structs are handled as if its fields were part
605// of the outer struct. An inlined map causes keys that do
606// not match any other struct field to be inserted in the
607// map rather than being discarded as usual.
608//
609// The target field or element types of out may not necessarily match
610// the BSON values of the provided data. The following conversions are
611// made automatically:
612//
613// - Numeric types are converted if at least the integer part of the
614// value would be preserved correctly
615// - Bools are converted to numeric types as 1 or 0
616// - Numeric types are converted to bools as true if not 0 or false otherwise
617// - Binary and string BSON data is converted to a string, array or byte slice
618//
619// If the value would not fit the type and cannot be converted, it's
620// silently skipped.
621//
622// Pointer values are initialized when necessary.
623func Unmarshal(in []byte, out interface{}) (err error) {
624 if raw, ok := out.(*Raw); ok {
625 raw.Kind = 3
626 raw.Data = in
627 return nil
628 }
629 defer handleErr(&err)
630 v := reflect.ValueOf(out)
631 switch v.Kind() {
632 case reflect.Ptr:
633 fallthrough
634 case reflect.Map:
635 d := newDecoder(in)
636 d.readDocTo(v)
637 if d.i < len(d.in) {
638 return errors.New("document is corrupted")
639 }
640 case reflect.Struct:
641 return errors.New("unmarshal can't deal with struct values. Use a pointer")
642 default:
643 return errors.New("unmarshal needs a map or a pointer to a struct")
644 }
645 return nil
646}
647
648// Unmarshal deserializes raw into the out value. If the out value type
649// is not compatible with raw, a *bson.TypeError is returned.
650//
651// See the Unmarshal function documentation for more details on the
652// unmarshalling process.
653func (raw Raw) Unmarshal(out interface{}) (err error) {
654 defer handleErr(&err)
655 v := reflect.ValueOf(out)
656 switch v.Kind() {
657 case reflect.Ptr:
658 v = v.Elem()
659 fallthrough
660 case reflect.Map:
661 d := newDecoder(raw.Data)
662 good := d.readElemTo(v, raw.Kind)
663 if !good {
664 return &TypeError{v.Type(), raw.Kind}
665 }
666 case reflect.Struct:
667 return errors.New("raw Unmarshal can't deal with struct values. Use a pointer")
668 default:
669 return errors.New("raw Unmarshal needs a map or a valid pointer")
670 }
671 return nil
672}
673
674// TypeError store details for type error occuring
675// during unmarshaling
676type TypeError struct {
677 Type reflect.Type
678 Kind byte
679}
680
681func (e *TypeError) Error() string {
682 return fmt.Sprintf("BSON kind 0x%02x isn't compatible with type %s", e.Kind, e.Type.String())
683}
684
685// --------------------------------------------------------------------------
686// Maintain a mapping of keys to structure field indexes
687
688type structInfo struct {
689 FieldsMap map[string]fieldInfo
690 FieldsList []fieldInfo
691 InlineMap int
692 Zero reflect.Value
693}
694
695type fieldInfo struct {
696 Key string
697 Num int
698 OmitEmpty bool
699 MinSize bool
700 Inline []int
701}
702
703var structMap = make(map[reflect.Type]*structInfo)
704var structMapMutex sync.RWMutex
705
706type externalPanic string
707
708func (e externalPanic) String() string {
709 return string(e)
710}
711
712func getStructInfo(st reflect.Type) (*structInfo, error) {
713 structMapMutex.RLock()
714 sinfo, found := structMap[st]
715 structMapMutex.RUnlock()
716 if found {
717 return sinfo, nil
718 }
719 n := st.NumField()
720 fieldsMap := make(map[string]fieldInfo)
721 fieldsList := make([]fieldInfo, 0, n)
722 inlineMap := -1
723 for i := 0; i != n; i++ {
724 field := st.Field(i)
725 if field.PkgPath != "" && !field.Anonymous {
726 continue // Private field
727 }
728
729 info := fieldInfo{Num: i}
730
731 tag := field.Tag.Get("bson")
732
733 // Fall-back to JSON struct tag, if feature flag is set.
734 if tag == "" && useJSONTagFallback {
735 tag = field.Tag.Get("json")
736 }
737
738 // If there's no bson/json tag available.
739 if tag == "" {
740 // If there's no tag, and also no tag: value splits (i.e. no colon)
741 // then assume the entire tag is the value
742 if strings.Index(string(field.Tag), ":") < 0 {
743 tag = string(field.Tag)
744 }
745 }
746
747 if tag == "-" {
748 continue
749 }
750
751 inline := false
752 fields := strings.Split(tag, ",")
753 if len(fields) > 1 {
754 for _, flag := range fields[1:] {
755 switch flag {
756 case "omitempty":
757 info.OmitEmpty = true
758 case "minsize":
759 info.MinSize = true
760 case "inline":
761 inline = true
762 default:
763 msg := fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st)
764 panic(externalPanic(msg))
765 }
766 }
767 tag = fields[0]
768 }
769
770 if inline {
771 switch field.Type.Kind() {
772 case reflect.Map:
773 if inlineMap >= 0 {
774 return nil, errors.New("Multiple ,inline maps in struct " + st.String())
775 }
776 if field.Type.Key() != reflect.TypeOf("") {
777 return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String())
778 }
779 inlineMap = info.Num
780 case reflect.Ptr:
781 // allow only pointer to struct
782 if kind := field.Type.Elem().Kind(); kind != reflect.Struct {
783 return nil, errors.New("Option ,inline allows a pointer only to a struct, was given pointer to " + kind.String())
784 }
785
786 field.Type = field.Type.Elem()
787 fallthrough
788 case reflect.Struct:
789 sinfo, err := getStructInfo(field.Type)
790 if err != nil {
791 return nil, err
792 }
793 for _, finfo := range sinfo.FieldsList {
794 if _, found := fieldsMap[finfo.Key]; found {
795 msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String()
796 return nil, errors.New(msg)
797 }
798 if finfo.Inline == nil {
799 finfo.Inline = []int{i, finfo.Num}
800 } else {
801 finfo.Inline = append([]int{i}, finfo.Inline...)
802 }
803 fieldsMap[finfo.Key] = finfo
804 fieldsList = append(fieldsList, finfo)
805 }
806 default:
807 panic("Option ,inline needs a struct value or a pointer to a struct or map field")
808 }
809 continue
810 }
811
812 if tag != "" {
813 info.Key = tag
814 } else {
815 info.Key = strings.ToLower(field.Name)
816 }
817
818 if _, found = fieldsMap[info.Key]; found {
819 msg := "Duplicated key '" + info.Key + "' in struct " + st.String()
820 return nil, errors.New(msg)
821 }
822
823 fieldsList = append(fieldsList, info)
824 fieldsMap[info.Key] = info
825 }
826 sinfo = &structInfo{
827 fieldsMap,
828 fieldsList,
829 inlineMap,
830 reflect.New(st).Elem(),
831 }
832 structMapMutex.Lock()
833 structMap[st] = sinfo
834 structMapMutex.Unlock()
835 return sinfo, nil
836}