blob: d0c6b2a855f85f7502cb5511859c8cb15eb241ca [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// gobson - BSON library for Go.
27
28package bson
29
30import (
31 "encoding/json"
32 "fmt"
33 "math"
34 "net/url"
35 "reflect"
36 "sort"
37 "strconv"
38 "sync"
39 "time"
40)
41
42// --------------------------------------------------------------------------
43// Some internal infrastructure.
44
45var (
46 typeBinary = reflect.TypeOf(Binary{})
47 typeObjectId = reflect.TypeOf(ObjectId(""))
48 typeDBPointer = reflect.TypeOf(DBPointer{"", ObjectId("")})
49 typeSymbol = reflect.TypeOf(Symbol(""))
50 typeMongoTimestamp = reflect.TypeOf(MongoTimestamp(0))
51 typeOrderKey = reflect.TypeOf(MinKey)
52 typeDocElem = reflect.TypeOf(DocElem{})
53 typeRawDocElem = reflect.TypeOf(RawDocElem{})
54 typeRaw = reflect.TypeOf(Raw{})
55 typeRawPtr = reflect.PtrTo(reflect.TypeOf(Raw{}))
56 typeURL = reflect.TypeOf(url.URL{})
57 typeTime = reflect.TypeOf(time.Time{})
58 typeString = reflect.TypeOf("")
59 typeJSONNumber = reflect.TypeOf(json.Number(""))
60 typeTimeDuration = reflect.TypeOf(time.Duration(0))
61)
62
63var (
64 // spec for []uint8 or []byte encoding
65 arrayOps = map[string]bool{
66 "$in": true,
67 "$nin": true,
68 "$all": true,
69 }
70)
71
72const itoaCacheSize = 32
73
74const (
75 getterUnknown = iota
76 getterNone
77 getterTypeVal
78 getterTypePtr
79 getterAddr
80)
81
82var itoaCache []string
83
84var getterStyles map[reflect.Type]int
85var getterIface reflect.Type
86var getterMutex sync.RWMutex
87
88func init() {
89 itoaCache = make([]string, itoaCacheSize)
90 for i := 0; i != itoaCacheSize; i++ {
91 itoaCache[i] = strconv.Itoa(i)
92 }
93 var iface Getter
94 getterIface = reflect.TypeOf(&iface).Elem()
95 getterStyles = make(map[reflect.Type]int)
96}
97
98func itoa(i int) string {
99 if i < itoaCacheSize {
100 return itoaCache[i]
101 }
102 return strconv.Itoa(i)
103}
104
105func getterStyle(outt reflect.Type) int {
106 getterMutex.RLock()
107 style := getterStyles[outt]
108 getterMutex.RUnlock()
109 if style != getterUnknown {
110 return style
111 }
112
113 getterMutex.Lock()
114 defer getterMutex.Unlock()
115 if outt.Implements(getterIface) {
116 vt := outt
117 for vt.Kind() == reflect.Ptr {
118 vt = vt.Elem()
119 }
120 if vt.Implements(getterIface) {
121 style = getterTypeVal
122 } else {
123 style = getterTypePtr
124 }
125 } else if reflect.PtrTo(outt).Implements(getterIface) {
126 style = getterAddr
127 } else {
128 style = getterNone
129 }
130 getterStyles[outt] = style
131 return style
132}
133
134func getGetter(outt reflect.Type, out reflect.Value) Getter {
135 style := getterStyle(outt)
136 if style == getterNone {
137 return nil
138 }
139 if style == getterAddr {
140 if !out.CanAddr() {
141 return nil
142 }
143 return out.Addr().Interface().(Getter)
144 }
145 if style == getterTypeVal && out.Kind() == reflect.Ptr && out.IsNil() {
146 return nil
147 }
148 return out.Interface().(Getter)
149}
150
151// --------------------------------------------------------------------------
152// Marshaling of the document value itself.
153
154type encoder struct {
155 out []byte
156}
157
158func (e *encoder) addDoc(v reflect.Value) {
159 for {
160 if vi, ok := v.Interface().(Getter); ok {
161 getv, err := vi.GetBSON()
162 if err != nil {
163 panic(err)
164 }
165 v = reflect.ValueOf(getv)
166 continue
167 }
168 if v.Kind() == reflect.Ptr {
169 v = v.Elem()
170 continue
171 }
172 break
173 }
174
175 if v.Type() == typeRaw {
176 raw := v.Interface().(Raw)
177 if raw.Kind != 0x03 && raw.Kind != 0x00 {
178 panic("Attempted to marshal Raw kind " + strconv.Itoa(int(raw.Kind)) + " as a document")
179 }
180 if len(raw.Data) == 0 {
181 panic("Attempted to marshal empty Raw document")
182 }
183 e.addBytes(raw.Data...)
184 return
185 }
186
187 start := e.reserveInt32()
188
189 switch v.Kind() {
190 case reflect.Map:
191 e.addMap(v)
192 case reflect.Struct:
193 e.addStruct(v)
194 case reflect.Array, reflect.Slice:
195 e.addSlice(v)
196 default:
197 panic("Can't marshal " + v.Type().String() + " as a BSON document")
198 }
199
200 e.addBytes(0)
201 e.setInt32(start, int32(len(e.out)-start))
202}
203
204func (e *encoder) addMap(v reflect.Value) {
205 for _, k := range v.MapKeys() {
206 e.addElem(fmt.Sprint(k), v.MapIndex(k), false)
207 }
208}
209
210func (e *encoder) addStruct(v reflect.Value) {
211 sinfo, err := getStructInfo(v.Type())
212 if err != nil {
213 panic(err)
214 }
215 var value reflect.Value
216 if sinfo.InlineMap >= 0 {
217 m := v.Field(sinfo.InlineMap)
218 if m.Len() > 0 {
219 for _, k := range m.MapKeys() {
220 ks := k.String()
221 if _, found := sinfo.FieldsMap[ks]; found {
222 panic(fmt.Sprintf("Can't have key %q in inlined map; conflicts with struct field", ks))
223 }
224 e.addElem(ks, m.MapIndex(k), false)
225 }
226 }
227 }
228 for _, info := range sinfo.FieldsList {
229 if info.Inline == nil {
230 value = v.Field(info.Num)
231 } else {
232 // as pointers to struct are allowed here,
233 // there is no guarantee that pointer won't be nil.
234 //
235 // It is expected allowed behaviour
236 // so info.Inline MAY consist index to a nil pointer
237 // and that is why we safely call v.FieldByIndex and just continue on panic
238 field, errField := safeFieldByIndex(v, info.Inline)
239 if errField != nil {
240 continue
241 }
242
243 value = field
244 }
245 if info.OmitEmpty && isZero(value) {
246 continue
247 }
248 if useRespectNilValues &&
249 (value.Kind() == reflect.Slice || value.Kind() == reflect.Map) &&
250 value.IsNil() {
251 e.addElem(info.Key, reflect.ValueOf(nil), info.MinSize)
252 continue
253 }
254 e.addElem(info.Key, value, info.MinSize)
255 }
256}
257
258func safeFieldByIndex(v reflect.Value, index []int) (result reflect.Value, err error) {
259 defer func() {
260 if recovered := recover(); recovered != nil {
261 switch r := recovered.(type) {
262 case string:
263 err = fmt.Errorf("%s", r)
264 case error:
265 err = r
266 }
267 }
268 }()
269
270 result = v.FieldByIndex(index)
271 return
272}
273
274func isZero(v reflect.Value) bool {
275 switch v.Kind() {
276 case reflect.String:
277 return len(v.String()) == 0
278 case reflect.Ptr, reflect.Interface:
279 return v.IsNil()
280 case reflect.Slice:
281 return v.Len() == 0
282 case reflect.Map:
283 return v.Len() == 0
284 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
285 return v.Int() == 0
286 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
287 return v.Uint() == 0
288 case reflect.Float32, reflect.Float64:
289 return v.Float() == 0
290 case reflect.Bool:
291 return !v.Bool()
292 case reflect.Struct:
293 vt := v.Type()
294 if vt == typeTime {
295 return v.Interface().(time.Time).IsZero()
296 }
297 for i := 0; i < v.NumField(); i++ {
298 if vt.Field(i).PkgPath != "" && !vt.Field(i).Anonymous {
299 continue // Private field
300 }
301 if !isZero(v.Field(i)) {
302 return false
303 }
304 }
305 return true
306 }
307 return false
308}
309
310func (e *encoder) addSlice(v reflect.Value) {
311 vi := v.Interface()
312 if d, ok := vi.(D); ok {
313 for _, elem := range d {
314 e.addElem(elem.Name, reflect.ValueOf(elem.Value), false)
315 }
316 return
317 }
318 if d, ok := vi.(RawD); ok {
319 for _, elem := range d {
320 e.addElem(elem.Name, reflect.ValueOf(elem.Value), false)
321 }
322 return
323 }
324 l := v.Len()
325 et := v.Type().Elem()
326 if et == typeDocElem {
327 for i := 0; i < l; i++ {
328 elem := v.Index(i).Interface().(DocElem)
329 e.addElem(elem.Name, reflect.ValueOf(elem.Value), false)
330 }
331 return
332 }
333 if et == typeRawDocElem {
334 for i := 0; i < l; i++ {
335 elem := v.Index(i).Interface().(RawDocElem)
336 e.addElem(elem.Name, reflect.ValueOf(elem.Value), false)
337 }
338 return
339 }
340 for i := 0; i < l; i++ {
341 e.addElem(itoa(i), v.Index(i), false)
342 }
343}
344
345// --------------------------------------------------------------------------
346// Marshaling of elements in a document.
347
348func (e *encoder) addElemName(kind byte, name string) {
349 e.addBytes(kind)
350 e.addBytes([]byte(name)...)
351 e.addBytes(0)
352}
353
354func (e *encoder) addElem(name string, v reflect.Value, minSize bool) {
355
356 if !v.IsValid() {
357 e.addElemName(0x0A, name)
358 return
359 }
360
361 if getter := getGetter(v.Type(), v); getter != nil {
362 getv, err := getter.GetBSON()
363 if err != nil {
364 panic(err)
365 }
366 e.addElem(name, reflect.ValueOf(getv), minSize)
367 return
368 }
369
370 switch v.Kind() {
371
372 case reflect.Interface:
373 e.addElem(name, v.Elem(), minSize)
374
375 case reflect.Ptr:
376 e.addElem(name, v.Elem(), minSize)
377
378 case reflect.String:
379 s := v.String()
380 switch v.Type() {
381 case typeObjectId:
382 if len(s) != 12 {
383 panic("ObjectIDs must be exactly 12 bytes long (got " +
384 strconv.Itoa(len(s)) + ")")
385 }
386 e.addElemName(0x07, name)
387 e.addBytes([]byte(s)...)
388 case typeSymbol:
389 e.addElemName(0x0E, name)
390 e.addStr(s)
391 case typeJSONNumber:
392 n := v.Interface().(json.Number)
393 if i, err := n.Int64(); err == nil {
394 e.addElemName(0x12, name)
395 e.addInt64(i)
396 } else if f, err := n.Float64(); err == nil {
397 e.addElemName(0x01, name)
398 e.addFloat64(f)
399 } else {
400 panic("failed to convert json.Number to a number: " + s)
401 }
402 default:
403 e.addElemName(0x02, name)
404 e.addStr(s)
405 }
406
407 case reflect.Float32, reflect.Float64:
408 e.addElemName(0x01, name)
409 e.addFloat64(v.Float())
410
411 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
412 u := v.Uint()
413 if int64(u) < 0 {
414 panic("BSON has no uint64 type, and value is too large to fit correctly in an int64")
415 } else if u <= math.MaxInt32 && (minSize || v.Kind() <= reflect.Uint32) {
416 e.addElemName(0x10, name)
417 e.addInt32(int32(u))
418 } else {
419 e.addElemName(0x12, name)
420 e.addInt64(int64(u))
421 }
422
423 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
424 switch v.Type() {
425 case typeMongoTimestamp:
426 e.addElemName(0x11, name)
427 e.addInt64(v.Int())
428
429 case typeOrderKey:
430 if v.Int() == int64(MaxKey) {
431 e.addElemName(0x7F, name)
432 } else {
433 e.addElemName(0xFF, name)
434 }
435 case typeTimeDuration:
436 // Stored as int64
437 e.addElemName(0x12, name)
438
439 e.addInt64(int64(v.Int() / 1e6))
440 default:
441 i := v.Int()
442 if (minSize || v.Type().Kind() != reflect.Int64) && i >= math.MinInt32 && i <= math.MaxInt32 {
443 // It fits into an int32, encode as such.
444 e.addElemName(0x10, name)
445 e.addInt32(int32(i))
446 } else {
447 e.addElemName(0x12, name)
448 e.addInt64(i)
449 }
450 }
451
452 case reflect.Bool:
453 e.addElemName(0x08, name)
454 if v.Bool() {
455 e.addBytes(1)
456 } else {
457 e.addBytes(0)
458 }
459
460 case reflect.Map:
461 e.addElemName(0x03, name)
462 e.addDoc(v)
463
464 case reflect.Slice:
465 vt := v.Type()
466 et := vt.Elem()
467 if et.Kind() == reflect.Uint8 {
468 if arrayOps[name] {
469 e.addElemName(0x04, name)
470 e.addDoc(v)
471 } else {
472 e.addElemName(0x05, name)
473 e.addBinary(0x00, v.Bytes())
474 }
475 } else if et == typeDocElem || et == typeRawDocElem {
476 e.addElemName(0x03, name)
477 e.addDoc(v)
478 } else {
479 e.addElemName(0x04, name)
480 e.addDoc(v)
481 }
482
483 case reflect.Array:
484 et := v.Type().Elem()
485 if et.Kind() == reflect.Uint8 {
486 if arrayOps[name] {
487 e.addElemName(0x04, name)
488 e.addDoc(v)
489 } else {
490 e.addElemName(0x05, name)
491 if v.CanAddr() {
492 e.addBinary(0x00, v.Slice(0, v.Len()).Interface().([]byte))
493 } else {
494 n := v.Len()
495 e.addInt32(int32(n))
496 e.addBytes(0x00)
497 for i := 0; i < n; i++ {
498 el := v.Index(i)
499 e.addBytes(byte(el.Uint()))
500 }
501 }
502 }
503 } else {
504 e.addElemName(0x04, name)
505 e.addDoc(v)
506 }
507
508 case reflect.Struct:
509 switch s := v.Interface().(type) {
510
511 case Raw:
512 kind := s.Kind
513 if kind == 0x00 {
514 kind = 0x03
515 }
516 if len(s.Data) == 0 && kind != 0x06 && kind != 0x0A && kind != 0xFF && kind != 0x7F {
517 panic("Attempted to marshal empty Raw document")
518 }
519 e.addElemName(kind, name)
520 e.addBytes(s.Data...)
521
522 case Binary:
523 e.addElemName(0x05, name)
524 e.addBinary(s.Kind, s.Data)
525
526 case Decimal128:
527 e.addElemName(0x13, name)
528 e.addInt64(int64(s.l))
529 e.addInt64(int64(s.h))
530
531 case DBPointer:
532 e.addElemName(0x0C, name)
533 e.addStr(s.Namespace)
534 if len(s.Id) != 12 {
535 panic("ObjectIDs must be exactly 12 bytes long (got " +
536 strconv.Itoa(len(s.Id)) + ")")
537 }
538 e.addBytes([]byte(s.Id)...)
539
540 case RegEx:
541 e.addElemName(0x0B, name)
542 e.addCStr(s.Pattern)
543 options := runes(s.Options)
544 sort.Sort(options)
545 e.addCStr(string(options))
546
547 case JavaScript:
548 if s.Scope == nil {
549 e.addElemName(0x0D, name)
550 e.addStr(s.Code)
551 } else {
552 e.addElemName(0x0F, name)
553 start := e.reserveInt32()
554 e.addStr(s.Code)
555 e.addDoc(reflect.ValueOf(s.Scope))
556 e.setInt32(start, int32(len(e.out)-start))
557 }
558
559 case time.Time:
560 // MongoDB handles timestamps as milliseconds.
561 e.addElemName(0x09, name)
562 e.addInt64(s.Unix()*1000 + int64(s.Nanosecond()/1e6))
563
564 case url.URL:
565 e.addElemName(0x02, name)
566 e.addStr(s.String())
567
568 case undefined:
569 e.addElemName(0x06, name)
570
571 default:
572 e.addElemName(0x03, name)
573 e.addDoc(v)
574 }
575
576 default:
577 panic("Can't marshal " + v.Type().String() + " in a BSON document")
578 }
579}
580
581// -------------
582// Helper method for sorting regex options
583type runes []rune
584
585func (a runes) Len() int { return len(a) }
586func (a runes) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
587func (a runes) Less(i, j int) bool { return a[i] < a[j] }
588
589// --------------------------------------------------------------------------
590// Marshaling of base types.
591
592func (e *encoder) addBinary(subtype byte, v []byte) {
593 if subtype == 0x02 {
594 // Wonder how that brilliant idea came to life. Obsolete, luckily.
595 e.addInt32(int32(len(v) + 4))
596 e.addBytes(subtype)
597 e.addInt32(int32(len(v)))
598 } else {
599 e.addInt32(int32(len(v)))
600 e.addBytes(subtype)
601 }
602 e.addBytes(v...)
603}
604
605func (e *encoder) addStr(v string) {
606 e.addInt32(int32(len(v) + 1))
607 e.addCStr(v)
608}
609
610func (e *encoder) addCStr(v string) {
611 e.addBytes([]byte(v)...)
612 e.addBytes(0)
613}
614
615func (e *encoder) reserveInt32() (pos int) {
616 pos = len(e.out)
617 e.addBytes(0, 0, 0, 0)
618 return pos
619}
620
621func (e *encoder) setInt32(pos int, v int32) {
622 e.out[pos+0] = byte(v)
623 e.out[pos+1] = byte(v >> 8)
624 e.out[pos+2] = byte(v >> 16)
625 e.out[pos+3] = byte(v >> 24)
626}
627
628func (e *encoder) addInt32(v int32) {
629 u := uint32(v)
630 e.addBytes(byte(u), byte(u>>8), byte(u>>16), byte(u>>24))
631}
632
633func (e *encoder) addInt64(v int64) {
634 u := uint64(v)
635 e.addBytes(byte(u), byte(u>>8), byte(u>>16), byte(u>>24),
636 byte(u>>32), byte(u>>40), byte(u>>48), byte(u>>56))
637}
638
639func (e *encoder) addFloat64(v float64) {
640 e.addInt64(int64(math.Float64bits(v)))
641}
642
643func (e *encoder) addBytes(v ...byte) {
644 e.out = append(e.out, v...)
645}