mgo

Merge lp:~miki-tebeka/mgo/string-compile into lp:~niemeyer/mgo/trunk

Proposed by tebeka
Status: Needs review
Proposed branch: lp:~miki-tebeka/mgo/string-compile
Merge into: lp:~niemeyer/mgo/trunk
Diff against target: 2677 lines (+2646/-0) (has conflicts)
6 files modified
LICENSE (+29/-0)
Makefile (+22/-0)
decode.go (+596/-0)
encode.go (+420/-0)
gobson.go (+483/-0)
gobson_test.go (+1096/-0)
Conflict adding file LICENSE.  Moved existing file to LICENSE.moved.
Conflict adding file Makefile.  Moved existing file to Makefile.moved.
To merge this branch: bzr merge lp:~miki-tebeka/mgo/string-compile
Reviewer Review Type Date Requested Status
Gustavo Niemeyer Pending
Review via email: mp+69689@code.launchpad.net

Description of the change

Fix compilation error with current go head (e3cd47e9748d)

To post a comment you must log in.
Revision history for this message
Gustavo Niemeyer (niemeyer) wrote :

Please check out the diff from this branch (below in the merge proposal). Looks like quite a few things have changed unintendedly.

Also, please note that mgo will follow the stable release of Go. Once these changes make into the stable release, mgo will be immediately changed accordingly.

We'll likely need a way to enable people to use mgo with the head, though. I've been thinking about some convention around that. Please pop up in the mailing list to talk about this if you have ideas.

Revision history for this message
tebeka (miki-tebeka) wrote :

Greetings,

> Please check out the diff from this branch (below in the merge proposal). Looks like quite a few things have changed unintendedly.
This it a patch to gobson, I did a mistake when creating the branch.
Attached the right patch.

> Also, please note that mgo will follow the stable release of Go.  Once these changes make into the stable release, mgo will be immediately changed accordingly.
I guessed so and it's the right thing to do. I run from tip since I mostly play.

All the best,
--
Miki

1------------------------------------------------------------
2revno: 29
3committer: Miki Tebeka <miki.tebeka@gmail.com>
4branch nick: gobson
5timestamp: Thu 2011-07-28 10:06:14 -0700
6message:
7 Compile with go head
8diff:
9=== modified file 'gobson.go'
10--- gobson.go 2011-06-24 23:48:23 +0000
11+++ gobson.go 2011-07-28 17:06:14 +0000
12@@ -442,7 +442,7 @@
13
14 info := fieldInfo{Num: i}
15
16- if s := strings.LastIndex(field.Tag, "/"); s != -1 {
17+ if s := strings.LastIndex(string(field.Tag), "/"); s != -1 {
18 for _, c := range field.Tag[s+1:] {
19 switch c {
20 case int('c'):
21@@ -457,7 +457,7 @@
22 }
23
24 if field.Tag != "" {
25- info.Key = field.Tag
26+ info.Key = string(field.Tag)
27 } else {
28 info.Key = strings.ToLower(field.Name)
29 }

Unmerged revisions

29. By tebeka

Compile with go head

28. By Gustavo Niemeyer

Some inlining and tweaks for decoding performance.

27. By Gustavo Niemeyer

os.ErrorString => os.NewError

26. By Gustavo Niemeyer

Raw.Unmarshal and "/s" support.

25. By Gustavo Niemeyer

Updated to current weekly and binary array support.

24. By Gustavo Niemeyer

Better handling of pointers.

23. By Gustavo Niemeyer

Added Raw type.

22. By Gustavo Niemeyer

Encode (u)int64 as int32 if the value fits.

21. By Gustavo Niemeyer

s/Milliseconds/Timestamp/ and use ns. Added Now().

20. By Gustavo Niemeyer

Ported to current weekly.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'LICENSE'
2--- LICENSE 1970-01-01 00:00:00 +0000
3+++ LICENSE 2011-07-28 17:08:30 +0000
4@@ -0,0 +1,29 @@
5+gobson - BSON library for Go.
6+
7+Copyright (c) 2010-2011 - Gustavo Niemeyer <gustavo@niemeyer.net>
8+
9+All rights reserved.
10+
11+Redistribution and use in source and binary forms, with or without
12+modification, are permitted provided that the following conditions are met:
13+
14+ * Redistributions of source code must retain the above copyright notice,
15+ this list of conditions and the following disclaimer.
16+ * Redistributions in binary form must reproduce the above copyright notice,
17+ this list of conditions and the following disclaimer in the documentation
18+ and/or other materials provided with the distribution.
19+ * Neither the name of the copyright holder nor the names of its
20+ contributors may be used to endorse or promote products derived from
21+ this software without specific prior written permission.
22+
23+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
27+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
35=== renamed file 'LICENSE' => 'LICENSE.moved'
36=== added file 'Makefile'
37--- Makefile 1970-01-01 00:00:00 +0000
38+++ Makefile 2011-07-28 17:08:30 +0000
39@@ -0,0 +1,22 @@
40+include $(GOROOT)/src/Make.inc
41+
42+TARG=launchpad.net/gobson/bson
43+
44+GOFILES=\
45+ gobson.go\
46+ encode.go\
47+ decode.go\
48+
49+include $(GOROOT)/src/Make.pkg
50+
51+GOFMT=gofmt
52+BADFMT=$(shell $(GOFMT) -l $(GOFILES) $(wildcard *_test.go) 2> /dev/null)
53+
54+gofmt: $(BADFMT)
55+ @for F in $(BADFMT); do $(GOFMT) -w $$F && echo $$F; done
56+
57+ifneq ($(BADFMT),)
58+ifneq ($(MAKECMDGOALS),gofmt)
59+$(warning WARNING: make gofmt: $(BADFMT))
60+endif
61+endif
62
63=== renamed file 'Makefile' => 'Makefile.moved'
64=== added file 'decode.go'
65--- decode.go 1970-01-01 00:00:00 +0000
66+++ decode.go 2011-07-28 17:08:30 +0000
67@@ -0,0 +1,596 @@
68+// gobson - BSON library for Go.
69+//
70+// Copyright (c) 2010-2011 - Gustavo Niemeyer <gustavo@niemeyer.net>
71+//
72+// All rights reserved.
73+//
74+// Redistribution and use in source and binary forms, with or without
75+// modification, are permitted provided that the following conditions are met:
76+//
77+// * Redistributions of source code must retain the above copyright notice,
78+// this list of conditions and the following disclaimer.
79+// * Redistributions in binary form must reproduce the above copyright notice,
80+// this list of conditions and the following disclaimer in the documentation
81+// and/or other materials provided with the distribution.
82+// * Neither the name of the copyright holder nor the names of its
83+// contributors may be used to endorse or promote products derived from
84+// this software without specific prior written permission.
85+//
86+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
87+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
88+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
89+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
90+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
91+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
92+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
93+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
94+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
95+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
96+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
97+
98+package bson
99+
100+import (
101+ "reflect"
102+ "math"
103+ "fmt"
104+)
105+
106+type decoder struct {
107+ in []byte
108+ i int
109+}
110+
111+// --------------------------------------------------------------------------
112+// Some helper functions.
113+
114+func corrupted() {
115+ panic("Document is corrupted")
116+}
117+
118+func zeroNilPtr(v reflect.Value) (changed bool) {
119+ if v.Kind() == reflect.Ptr && v.IsNil() {
120+ v.Set(reflect.New(v.Type().Elem()))
121+ return true
122+ }
123+ return false
124+}
125+
126+func settableValueOf(i interface{}) reflect.Value {
127+ v := reflect.ValueOf(i)
128+ sv := reflect.New(v.Type()).Elem()
129+ sv.Set(v)
130+ return sv
131+}
132+
133+// --------------------------------------------------------------------------
134+// Unmarshaling of documents.
135+
136+func (d *decoder) readDocTo(out reflect.Value) {
137+ var elemType reflect.Type
138+ outt := out.Type()
139+ outk := outt.Kind()
140+
141+ for {
142+ if outk == reflect.Ptr && out.IsNil() {
143+ out.Set(reflect.New(outt.Elem()))
144+ }
145+ if setter, ok := out.Interface().(Setter); ok {
146+ setter.SetBSON(d.readDocD())
147+ return
148+ }
149+ if outk == reflect.Ptr {
150+ out = out.Elem()
151+ outt = out.Type()
152+ outk = out.Kind()
153+ continue
154+ }
155+ break
156+ }
157+
158+ var fieldsMap map[string]fieldInfo
159+ start := d.i
160+
161+ switch outk {
162+ case reflect.Interface:
163+ if !out.IsNil() {
164+ panic("Found non-nil interface. Please contact the developers.")
165+ }
166+ mv := reflect.ValueOf(make(M))
167+ out.Set(mv)
168+ out = mv
169+ outt = out.Type()
170+ outk = outt.Kind()
171+ fallthrough
172+ case reflect.Map:
173+ if outt.Key().Kind() != reflect.String {
174+ panic("BSON map must have string keys. Got: " + outt.String())
175+ }
176+ elemType = outt.Elem()
177+ if out.IsNil() {
178+ out.Set(reflect.MakeMap(out.Type()))
179+ }
180+ case reflect.Struct:
181+ if outt != typeRaw {
182+ fields, err := getStructFields(out.Type())
183+ if err != nil {
184+ panic(err)
185+ }
186+ fieldsMap = fields.Map
187+ }
188+ default:
189+ panic("TESTME:" + reflect.ValueOf(out).Type().String())
190+ }
191+
192+ end := d.i - 4 + int(d.readInt32())
193+ if end <= d.i || end > len(d.in) || d.in[end-1] != '\x00' {
194+ corrupted()
195+ }
196+ for d.in[d.i] != '\x00' {
197+ kind := d.readByte()
198+ name := d.readCStr()
199+ if d.i >= end {
200+ corrupted()
201+ }
202+
203+ switch outk {
204+ case reflect.Map:
205+ e := reflect.New(elemType).Elem()
206+ if d.readElemTo(e, kind) {
207+ out.SetMapIndex(reflect.ValueOf(name), e)
208+ }
209+ case reflect.Struct:
210+ if outt == typeRaw {
211+ d.readElemTo(blackHole, kind)
212+ } else {
213+ if info, ok := fieldsMap[name]; ok {
214+ d.readElemTo(out.Field(info.Num), kind)
215+ } else {
216+ d.dropElem(kind)
217+ }
218+ }
219+ }
220+
221+ if d.i >= end {
222+ corrupted()
223+ }
224+ }
225+ d.i++ // '\x00'
226+ if d.i != end {
227+ corrupted()
228+ }
229+
230+ switch outk {
231+ case reflect.Struct:
232+ if outt == typeRaw {
233+ out.Set(reflect.ValueOf(Raw{0x03, d.in[start:d.i]}))
234+ }
235+ }
236+}
237+
238+func (d *decoder) readArrayDoc(t reflect.Type) interface{} {
239+ tmp := make([]reflect.Value, 0, 8)
240+ elemType := t.Elem()
241+
242+ end := d.i - 4 + int(d.readInt32())
243+ if end <= d.i || end > len(d.in) || d.in[end-1] != '\x00' {
244+ corrupted()
245+ }
246+ for d.in[d.i] != '\x00' {
247+ kind := d.readByte()
248+ for d.i < end && d.in[d.i] != '\x00' {
249+ d.i++
250+ }
251+ if d.i >= end {
252+ corrupted()
253+ }
254+ d.i++
255+ e := reflect.New(elemType).Elem()
256+ if d.readElemTo(e, kind) {
257+ tmp = append(tmp, e)
258+ }
259+ if d.i >= end {
260+ corrupted()
261+ }
262+ }
263+ d.i++ // '\x00'
264+ if d.i != end {
265+ corrupted()
266+ }
267+
268+ n := len(tmp)
269+ slice := reflect.MakeSlice(t, n, n)
270+ for i := 0; i != n; i++ {
271+ slice.Index(i).Set(tmp[i])
272+ }
273+ return slice.Interface()
274+}
275+
276+var typeD = reflect.TypeOf(D{})
277+var typeSlice = reflect.TypeOf([]interface{}{})
278+
279+func (d *decoder) readDocD() interface{} {
280+ slice := make(D, 0, 8)
281+ d.readDocWith(func(kind byte, name string) {
282+ e := DocElem{Name: name}
283+ v := reflect.ValueOf(&e.Value)
284+ if d.readElemTo(v.Elem(), kind) {
285+ slice = append(slice, e)
286+ }
287+ })
288+ return slice
289+}
290+
291+func (d *decoder) readDocWith(f func(kind byte, name string)) {
292+ end := d.i - 4 + int(d.readInt32())
293+ if end <= d.i || end > len(d.in) || d.in[end-1] != '\x00' {
294+ corrupted()
295+ }
296+ for d.in[d.i] != '\x00' {
297+ kind := d.readByte()
298+ name := d.readCStr()
299+ if d.i >= end {
300+ corrupted()
301+ }
302+ f(kind, name)
303+ if d.i >= end {
304+ corrupted()
305+ }
306+ }
307+ d.i++ // '\x00'
308+ if d.i != end {
309+ corrupted()
310+ }
311+}
312+
313+// --------------------------------------------------------------------------
314+// Unmarshaling of individual elements within a document.
315+
316+var blackHole = settableValueOf(struct{}{})
317+
318+func (d *decoder) dropElem(kind byte) {
319+ d.readElemTo(blackHole, kind)
320+}
321+
322+// Attempt to decode an element from the document and put it into out.
323+// If the types are not compatible, the returned ok value will be
324+// false and out will be unchanged.
325+func (d *decoder) readElemTo(out reflect.Value, kind byte) (good bool) {
326+
327+ start := d.i
328+
329+ if kind == '\x03' {
330+ // Special case for documents. Delegate to readDocTo().
331+ switch out.Kind() {
332+ case reflect.Interface, reflect.Ptr, reflect.Struct, reflect.Map:
333+ d.readDocTo(out)
334+ default:
335+ if _, ok := out.Interface().(D); ok {
336+ out.Set(reflect.ValueOf(d.readDocD()))
337+ } else {
338+ d.readDocTo(blackHole)
339+ }
340+ }
341+ return true
342+ }
343+
344+ var in interface{}
345+
346+ switch kind {
347+ case '\x01': // Float64
348+ in = d.readFloat64()
349+ case '\x02': // UTF-8 string
350+ in = d.readStr()
351+ case '\x03': // Document
352+ panic("Can't happen. Handled above.")
353+ case '\x04': // Array
354+ outt := out.Type()
355+ for outt.Kind() == reflect.Ptr {
356+ outt = outt.Elem()
357+ }
358+ switch outt.Kind() {
359+ case reflect.Slice:
360+ in = d.readArrayDoc(outt)
361+ default:
362+ in = d.readArrayDoc(typeSlice)
363+ }
364+ case '\x05': // Binary
365+ b := d.readBinary()
366+ if b.Kind == 0x00 {
367+ in = b.Data
368+ } else {
369+ in = b
370+ }
371+ case '\x06': // Undefined (obsolete, but still seen in the wild)
372+ in = Undefined
373+ case '\x07': // ObjectId
374+ in = ObjectId(d.readBytes(12))
375+ case '\x08': // Bool
376+ in = d.readBool()
377+ case '\x09': // Timestamp
378+ // MongoDB wants timestamps as milliseconds.
379+ // Go likes nanoseconds. Convert them.
380+ in = Timestamp(d.readInt64() * 1e6)
381+ case '\x0A': // Nil
382+ in = nil
383+ case '\x0B': // RegEx
384+ in = d.readRegEx()
385+ case '\x0D': // JavaScript without scope
386+ in = JS{Code: d.readStr()}
387+ case '\x0E': // Symbol
388+ in = Symbol(d.readStr())
389+ case '\x0F': // JavaScript with scope
390+ d.i += 4 // Skip length
391+ js := JS{d.readStr(), make(M)}
392+ d.readDocTo(reflect.ValueOf(js.Scope))
393+ in = js
394+ case '\x10': // Int32
395+ in = int(d.readInt32())
396+ case '\x11': // Mongo-specific timestamp
397+ in = MongoTimestamp(d.readInt64())
398+ case '\x12': // Int64
399+ in = d.readInt64()
400+ case '\x7F': // Max key
401+ in = MaxKey
402+ case '\xFF': // Min key
403+ in = MinKey
404+ default:
405+ panic(fmt.Sprintf("Unknown element kind (0x%02X)", kind))
406+ }
407+
408+ outt := out.Type()
409+
410+ if outt == typeRaw {
411+ out.Set(reflect.ValueOf(Raw{kind, d.in[start:d.i]}))
412+ return true
413+ }
414+
415+ if setter, ok := out.Interface().(Setter); ok {
416+ if zeroNilPtr(out) {
417+ setter = out.Interface().(Setter)
418+ }
419+ return setter.SetBSON(in)
420+ }
421+
422+ if in == nil {
423+ out.Set(reflect.Zero(outt))
424+ return true
425+ }
426+
427+ outk := outt.Kind()
428+
429+ // Dereference and initialize pointer if necessary.
430+ first := true
431+ for outk == reflect.Ptr {
432+ if !out.IsNil() {
433+ out = out.Elem()
434+ } else {
435+ elem := reflect.New(outt.Elem())
436+ if first {
437+ // Only set if value is compatible.
438+ first = false
439+ defer func(out, elem reflect.Value) {
440+ if good {
441+ out.Set(elem)
442+ }
443+ }(out, elem)
444+ } else {
445+ out.Set(elem)
446+ }
447+ out = elem
448+ }
449+ outt = out.Type()
450+ outk = outt.Kind()
451+ }
452+
453+ inv := reflect.ValueOf(in)
454+ if outt == inv.Type() {
455+ out.Set(inv)
456+ return true
457+ }
458+
459+ switch outk {
460+ case reflect.Interface:
461+ out.Set(inv)
462+ return true
463+ case reflect.String:
464+ switch inv.Kind() {
465+ case reflect.String:
466+ out.SetString(inv.String())
467+ return true
468+ case reflect.Slice:
469+ if b, ok := in.([]byte); ok {
470+ out.SetString(string(b))
471+ return true
472+ }
473+ }
474+ case reflect.Slice, reflect.Array:
475+ // Remember, array (0x04) slices are built with the correct element
476+ // type. If we are here, must be a cross BSON kind conversion.
477+ if outt.Elem().Kind() == reflect.Uint8 {
478+ switch inv.Kind() {
479+ case reflect.String:
480+ slice := []byte(inv.String())
481+ out.Set(reflect.ValueOf(slice))
482+ return true
483+ case reflect.Slice:
484+ // out must be an array. A slice would trigger
485+ // inv.Type() == out.Type() above.
486+ reflect.Copy(out, inv)
487+ return true
488+ }
489+ }
490+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
491+ switch inv.Kind() {
492+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
493+ // MongoDB wants timestamps as milliseconds.
494+ // Go likes nanoseconds. Convert them.
495+ // out.Type() == inv.Type() has been handled above.
496+ if outt == typeTimestamp {
497+ out.SetInt(inv.Int() * 1e6)
498+ } else if inv.Type() == typeTimestamp {
499+ out.SetInt(inv.Int() / 1e6)
500+ } else {
501+ out.SetInt(inv.Int())
502+ }
503+ return true
504+ case reflect.Float32, reflect.Float64:
505+ out.SetInt(int64(inv.Float()))
506+ return true
507+ case reflect.Bool:
508+ if inv.Bool() {
509+ out.SetInt(1)
510+ } else {
511+ out.SetInt(0)
512+ }
513+ return true
514+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
515+ panic("Can't happen. No uint types in BSON?")
516+ }
517+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
518+ switch inv.Kind() {
519+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
520+ out.SetUint(uint64(inv.Int()))
521+ return true
522+ case reflect.Float32, reflect.Float64:
523+ out.SetUint(uint64(inv.Float()))
524+ return true
525+ case reflect.Bool:
526+ if inv.Bool() {
527+ out.SetUint(1)
528+ } else {
529+ out.SetUint(0)
530+ }
531+ return true
532+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
533+ panic("Can't happen. No uint types in BSON?")
534+ }
535+ case reflect.Float32, reflect.Float64:
536+ switch inv.Kind() {
537+ case reflect.Float32, reflect.Float64:
538+ out.SetFloat(inv.Float())
539+ return true
540+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
541+ out.SetFloat(float64(inv.Int()))
542+ return true
543+ case reflect.Bool:
544+ if inv.Bool() {
545+ out.SetFloat(1)
546+ } else {
547+ out.SetFloat(0)
548+ }
549+ return true
550+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
551+ panic("Can't happen. No uint types in BSON?")
552+ }
553+ case reflect.Bool:
554+ switch inv.Kind() {
555+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
556+ out.SetBool(inv.Int() != 0)
557+ return true
558+ case reflect.Float32, reflect.Float64:
559+ out.SetBool(inv.Float() != 0)
560+ return true
561+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
562+ panic("Can't happen. No uint types in BSON?")
563+ }
564+ }
565+
566+ return false
567+}
568+
569+// --------------------------------------------------------------------------
570+// Parsers of basic types.
571+
572+func (d *decoder) readRegEx() RegEx {
573+ re := RegEx{}
574+ re.Pattern = d.readCStr()
575+ re.Options = d.readCStr()
576+ return re
577+}
578+
579+func (d *decoder) readBinary() Binary {
580+ l := d.readInt32()
581+ b := Binary{}
582+ b.Kind = d.readByte()
583+ b.Data = d.readBytes(l)
584+ if b.Kind == 0x02 {
585+ // Weird obsolete format with redundant length.
586+ b.Data = b.Data[4:]
587+ }
588+ return b
589+}
590+
591+func (d *decoder) readStr() string {
592+ l := d.readInt32()
593+ b := d.readBytes(l - 1)
594+ if d.readByte() != '\x00' {
595+ corrupted()
596+ }
597+ return string(b)
598+}
599+
600+func (d *decoder) readCStr() string {
601+ start := d.i
602+ end := start
603+ l := len(d.in)
604+ for ; end != l; end++ {
605+ if d.in[end] == '\x00' {
606+ break
607+ }
608+ }
609+ d.i = end + 1
610+ if d.i > l {
611+ corrupted()
612+ }
613+ return string(d.in[start:end])
614+}
615+
616+func (d *decoder) readBool() bool {
617+ if d.readByte() == 1 {
618+ return true
619+ }
620+ return false
621+}
622+
623+func (d *decoder) readFloat64() float64 {
624+ return math.Float64frombits(uint64(d.readInt64()))
625+}
626+
627+func (d *decoder) readInt32() int32 {
628+ b := d.readBytes(4)
629+ return int32((uint32(b[0]) << 0) |
630+ (uint32(b[1]) << 8) |
631+ (uint32(b[2]) << 16) |
632+ (uint32(b[3]) << 24))
633+}
634+
635+func (d *decoder) readInt64() int64 {
636+ b := d.readBytes(8)
637+ return int64((uint64(b[0]) << 0) |
638+ (uint64(b[1]) << 8) |
639+ (uint64(b[2]) << 16) |
640+ (uint64(b[3]) << 24) |
641+ (uint64(b[4]) << 32) |
642+ (uint64(b[5]) << 40) |
643+ (uint64(b[6]) << 48) |
644+ (uint64(b[7]) << 56))
645+}
646+
647+func (d *decoder) readByte() byte {
648+ i := d.i
649+ d.i++
650+ if d.i > len(d.in) {
651+ corrupted()
652+ }
653+ return d.in[i]
654+}
655+
656+func (d *decoder) readBytes(length int32) []byte {
657+ start := d.i
658+ d.i += int(length)
659+ if d.i > len(d.in) {
660+ corrupted()
661+ }
662+ return d.in[start : start+int(length)]
663+}
664
665=== added file 'encode.go'
666--- encode.go 1970-01-01 00:00:00 +0000
667+++ encode.go 2011-07-28 17:08:30 +0000
668@@ -0,0 +1,420 @@
669+// gobson - BSON library for Go.
670+//
671+// Copyright (c) 2010-2011 - Gustavo Niemeyer <gustavo@niemeyer.net>
672+//
673+// All rights reserved.
674+//
675+// Redistribution and use in source and binary forms, with or without
676+// modification, are permitted provided that the following conditions are met:
677+//
678+// * Redistributions of source code must retain the above copyright notice,
679+// this list of conditions and the following disclaimer.
680+// * Redistributions in binary form must reproduce the above copyright notice,
681+// this list of conditions and the following disclaimer in the documentation
682+// and/or other materials provided with the distribution.
683+// * Neither the name of the copyright holder nor the names of its
684+// contributors may be used to endorse or promote products derived from
685+// this software without specific prior written permission.
686+//
687+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
688+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
689+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
690+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
691+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
692+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
693+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
694+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
695+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
696+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
697+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
698+
699+package bson
700+
701+import (
702+ "strconv"
703+ "reflect"
704+ "math"
705+)
706+
707+// --------------------------------------------------------------------------
708+// Some internal infrastructure.
709+
710+var (
711+ typeRegEx reflect.Type
712+ typeBinary reflect.Type
713+ typeObjectId reflect.Type
714+ typeSymbol reflect.Type
715+ typeTimestamp reflect.Type
716+ typeMongoTimestamp reflect.Type
717+ typeOrderKey reflect.Type
718+ typeDocElem reflect.Type
719+ typeRaw reflect.Type
720+)
721+
722+const itoaCacheSize = 32
723+
724+var itoaCache []string
725+
726+func init() {
727+ typeBinary = reflect.TypeOf(Binary{})
728+ typeObjectId = reflect.TypeOf(ObjectId(""))
729+ typeSymbol = reflect.TypeOf(Symbol(""))
730+ typeTimestamp = reflect.TypeOf(Timestamp(0))
731+ typeMongoTimestamp = reflect.TypeOf(MongoTimestamp(0))
732+ typeOrderKey = reflect.TypeOf(MinKey)
733+ typeDocElem = reflect.TypeOf(DocElem{})
734+ typeRaw = reflect.TypeOf(Raw{})
735+
736+ itoaCache = make([]string, itoaCacheSize)
737+ for i := 0; i != itoaCacheSize; i++ {
738+ itoaCache[i] = strconv.Itoa(i)
739+ }
740+}
741+
742+func itoa(i int) string {
743+ if i < itoaCacheSize {
744+ return itoaCache[i]
745+ }
746+ return strconv.Itoa(i)
747+}
748+
749+
750+// --------------------------------------------------------------------------
751+// Marshaling of the document value itself.
752+
753+type encoder struct {
754+ out []byte
755+}
756+
757+func (e *encoder) addDoc(v reflect.Value) {
758+ for {
759+ if vi, ok := v.Interface().(Getter); ok {
760+ v = reflect.ValueOf(vi.GetBSON())
761+ continue
762+ }
763+ if v.Kind() == reflect.Ptr {
764+ v = v.Elem()
765+ continue
766+ }
767+ break
768+ }
769+
770+ if v.Type() == typeRaw {
771+ raw := v.Interface().(Raw)
772+ if raw.Kind != 0x03 && raw.Kind != 0x00 {
773+ panic("Attempted to unmarshal Raw kind " + strconv.Itoa(int(raw.Kind)) + " as a document")
774+ }
775+ e.addBytes(raw.Data...)
776+ return
777+ }
778+
779+ start := e.reserveInt32()
780+
781+ switch v.Kind() {
782+ case reflect.Map:
783+ e.addMap(v)
784+ case reflect.Struct:
785+ e.addStruct(v)
786+ case reflect.Array, reflect.Slice:
787+ e.addSlice(v)
788+ default:
789+ panic("Can't marshal " + v.Type().String() + " as a BSON document")
790+ }
791+
792+ e.addBytes(0)
793+ e.setInt32(start, int32(len(e.out)-start))
794+}
795+
796+func (e *encoder) addMap(v reflect.Value) {
797+ for _, k := range v.MapKeys() {
798+ e.addElem(k.String(), v.MapIndex(k), false)
799+ }
800+}
801+
802+func (e *encoder) addStruct(v reflect.Value) {
803+ fields, err := getStructFields(v.Type())
804+ if err != nil {
805+ panic(err)
806+ }
807+ for i, info := range fields.List {
808+ value := v.Field(i)
809+ if info.Conditional && isZero(value) {
810+ continue
811+ }
812+ e.addElem(info.Key, value, info.Short)
813+ }
814+}
815+
816+func isZero(v reflect.Value) bool {
817+ switch v.Kind() {
818+ case reflect.String:
819+ return len(v.String()) == 0
820+ case reflect.Ptr, reflect.Interface:
821+ return v.IsNil()
822+ case reflect.Slice:
823+ return v.Len() == 0
824+ case reflect.Map:
825+ return v.Len() == 0
826+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
827+ return v.Int() == 0
828+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
829+ return v.Uint() == 0
830+ case reflect.Bool:
831+ return !v.Bool()
832+ }
833+ return false
834+}
835+
836+func (e *encoder) addSlice(v reflect.Value) {
837+ if d, ok := v.Interface().(D); ok {
838+ for _, elem := range d {
839+ e.addElem(elem.Name, reflect.ValueOf(elem.Value), false)
840+ }
841+ } else {
842+ for i := 0; i != v.Len(); i++ {
843+ e.addElem(itoa(i), v.Index(i), false)
844+ }
845+ }
846+}
847+
848+
849+// --------------------------------------------------------------------------
850+// Marshaling of elements in a document.
851+
852+func (e *encoder) addElemName(kind byte, name string) {
853+ e.addBytes(kind)
854+ e.addBytes([]byte(name)...)
855+ e.addBytes(0)
856+}
857+
858+func (e *encoder) addElem(name string, v reflect.Value, short bool) {
859+
860+ if !v.IsValid() {
861+ e.addElemName('\x0A', name)
862+ return
863+ }
864+
865+ if getter, ok := v.Interface().(Getter); ok {
866+ e.addElem(name, reflect.ValueOf(getter.GetBSON()), short)
867+ return
868+ }
869+
870+ switch v.Kind() {
871+
872+ case reflect.Interface:
873+ e.addElem(name, v.Elem(), short)
874+
875+ case reflect.Ptr:
876+ e.addElem(name, v.Elem(), short)
877+
878+ case reflect.String:
879+ s := v.String()
880+
881+ switch v.Type() {
882+
883+ case typeObjectId:
884+ if len(s) != 12 {
885+ panic("ObjectIDs must be exactly 12 bytes long (got " +
886+ strconv.Itoa(len(s)) + ")")
887+ }
888+ e.addElemName('\x07', name)
889+ e.addBytes([]byte(s)...)
890+
891+ case typeSymbol:
892+ e.addElemName('\x0E', name)
893+ e.addStr(s)
894+
895+ default:
896+ e.addElemName('\x02', name)
897+ e.addStr(s)
898+ }
899+
900+ case reflect.Float32, reflect.Float64:
901+ e.addElemName('\x01', name)
902+ e.addInt64(int64(math.Float64bits(v.Float())))
903+
904+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
905+ u := v.Uint()
906+ if int64(u) < 0 {
907+ panic("BSON has no uint64 type, and value is too large to fit correctly in an int64")
908+ } else if u <= math.MaxInt32 && (short || v.Kind() <= reflect.Uint32) {
909+ e.addElemName('\x10', name)
910+ e.addInt32(int32(u))
911+ } else {
912+ e.addElemName('\x12', name)
913+ e.addInt64(int64(u))
914+ }
915+
916+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
917+ if v.Type().Kind() <= reflect.Int32 {
918+ e.addElemName('\x10', name)
919+ e.addInt32(int32(v.Int()))
920+ } else {
921+ switch v.Type() {
922+
923+ case typeTimestamp:
924+ // MongoDB wants timestamps as milliseconds.
925+ // Go likes nanoseconds. Convert them.
926+ e.addElemName('\x09', name)
927+ e.addInt64(v.Int() / 1e6)
928+
929+ case typeMongoTimestamp:
930+ e.addElemName('\x11', name)
931+ e.addInt64(v.Int())
932+
933+ case typeOrderKey:
934+ if v.Int() == int64(MaxKey) {
935+ e.addElemName('\x7F', name)
936+ } else {
937+ e.addElemName('\xFF', name)
938+ }
939+
940+ default:
941+ i := v.Int()
942+ if short && i >= math.MinInt32 && i <= math.MaxInt32 {
943+ // It fits into an int32, encode as such.
944+ e.addElemName('\x10', name)
945+ e.addInt32(int32(i))
946+ } else {
947+ e.addElemName('\x12', name)
948+ e.addInt64(i)
949+ }
950+ }
951+ }
952+
953+ case reflect.Bool:
954+ e.addElemName('\x08', name)
955+ if v.Bool() {
956+ e.addBytes(1)
957+ } else {
958+ e.addBytes(0)
959+ }
960+
961+ case reflect.Map:
962+ e.addElemName('\x03', name)
963+ e.addDoc(v)
964+
965+ case reflect.Slice:
966+ vt := v.Type()
967+ et := vt.Elem()
968+ if et.Kind() == reflect.Uint8 {
969+ // FIXME: This breaks down with custom types based on []byte
970+ e.addElemName('\x05', name)
971+ e.addBinary('\x00', v.Interface().([]byte))
972+ } else if et == typeDocElem {
973+ e.addElemName('\x03', name)
974+ e.addDoc(v)
975+ } else {
976+ e.addElemName('\x04', name)
977+ e.addDoc(v)
978+ }
979+
980+ case reflect.Array:
981+ et := v.Type().Elem()
982+ if et.Kind() == reflect.Uint8 {
983+ e.addElemName('\x05', name)
984+ e.addBinary('\x00', v.Slice(0, v.Len()).Interface().([]byte))
985+ } else {
986+ e.addElemName('\x04', name)
987+ e.addDoc(v)
988+ }
989+
990+ case reflect.Struct:
991+ switch s := v.Interface().(type) {
992+
993+ case Raw:
994+ kind := s.Kind
995+ if kind == 0x00 {
996+ kind = 0x03
997+ }
998+ e.addElemName(kind, name)
999+ e.addBytes(s.Data...)
1000+
1001+ case Binary:
1002+ e.addElemName('\x05', name)
1003+ e.addBinary(s.Kind, s.Data)
1004+
1005+ case RegEx:
1006+ e.addElemName('\x0B', name)
1007+ e.addCStr(s.Pattern)
1008+ e.addCStr(s.Options)
1009+
1010+ case JS:
1011+ if s.Scope == nil {
1012+ e.addElemName('\x0D', name)
1013+ e.addStr(s.Code)
1014+ } else {
1015+ e.addElemName('\x0F', name)
1016+ start := e.reserveInt32()
1017+ e.addStr(s.Code)
1018+ e.addDoc(reflect.ValueOf(s.Scope))
1019+ e.setInt32(start, int32(len(e.out)-start))
1020+ }
1021+
1022+ case undefined:
1023+ e.addElemName('\x06', name)
1024+
1025+ default:
1026+ e.addElemName('\x03', name)
1027+ e.addDoc(v)
1028+ }
1029+
1030+ default:
1031+ panic("Can't marshal " + v.Type().String() + " in a BSON document")
1032+ }
1033+}
1034+
1035+
1036+// --------------------------------------------------------------------------
1037+// Marshaling of base types.
1038+
1039+func (e *encoder) addBinary(subtype byte, v []byte) {
1040+ if subtype == 0x02 {
1041+ // Wonder how that brilliant idea came to life. Obsolete, luckily.
1042+ e.addInt32(int32(len(v) + 4))
1043+ e.addBytes(subtype)
1044+ e.addInt32(int32(len(v)))
1045+ } else {
1046+ e.addInt32(int32(len(v)))
1047+ e.addBytes(subtype)
1048+ }
1049+ e.addBytes(v...)
1050+}
1051+
1052+func (e *encoder) addStr(v string) {
1053+ e.addInt32(int32(len(v) + 1))
1054+ e.addCStr(v)
1055+}
1056+
1057+func (e *encoder) addCStr(v string) {
1058+ e.addBytes([]byte(v)...)
1059+ e.addBytes(0)
1060+}
1061+
1062+func (e *encoder) reserveInt32() (pos int) {
1063+ pos = len(e.out)
1064+ e.addBytes(0, 0, 0, 0)
1065+ return pos
1066+}
1067+
1068+func (e *encoder) setInt32(pos int, v int32) {
1069+ e.out[pos+0] = byte(v)
1070+ e.out[pos+1] = byte(v >> 8)
1071+ e.out[pos+2] = byte(v >> 16)
1072+ e.out[pos+3] = byte(v >> 24)
1073+}
1074+
1075+func (e *encoder) addInt32(v int32) {
1076+ u := uint32(v)
1077+ e.addBytes(byte(u), byte(u>>8), byte(u>>16), byte(u>>24))
1078+}
1079+
1080+func (e *encoder) addInt64(v int64) {
1081+ u := uint64(v)
1082+ e.addBytes(byte(u), byte(u>>8), byte(u>>16), byte(u>>24),
1083+ byte(u>>32), byte(u>>40), byte(u>>48), byte(u>>56))
1084+}
1085+
1086+func (e *encoder) addBytes(v ...byte) {
1087+ e.out = append(e.out, v...)
1088+}
1089
1090=== added file 'gobson.go'
1091--- gobson.go 1970-01-01 00:00:00 +0000
1092+++ gobson.go 2011-07-28 17:08:30 +0000
1093@@ -0,0 +1,483 @@
1094+// gobson - BSON library for Go.
1095+//
1096+// Copyright (c) 2010-2011 - Gustavo Niemeyer <gustavo@niemeyer.net>
1097+//
1098+// All rights reserved.
1099+//
1100+// Redistribution and use in source and binary forms, with or without
1101+// modification, are permitted provided that the following conditions are met:
1102+//
1103+// * Redistributions of source code must retain the above copyright notice,
1104+// this list of conditions and the following disclaimer.
1105+// * Redistributions in binary form must reproduce the above copyright notice,
1106+// this list of conditions and the following disclaimer in the documentation
1107+// and/or other materials provided with the distribution.
1108+// * Neither the name of the copyright holder nor the names of its
1109+// contributors may be used to endorse or promote products derived from
1110+// this software without specific prior written permission.
1111+//
1112+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1113+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1114+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1115+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
1116+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
1117+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1118+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1119+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
1120+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
1121+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1122+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1123+
1124+package bson
1125+
1126+import (
1127+ "encoding/binary"
1128+ "encoding/hex"
1129+ "crypto/md5"
1130+ "runtime"
1131+ "reflect"
1132+ "strings"
1133+ "sync/atomic"
1134+ "sync"
1135+ "time"
1136+ "fmt"
1137+ "os"
1138+)
1139+
1140+// --------------------------------------------------------------------------
1141+// The public API.
1142+
1143+// Objects implementing the bson.Getter interface will get the GetBSON()
1144+// method called when the given value has to be marshalled, and the result
1145+// of this method will be marshaled in place of the actual object.
1146+type Getter interface {
1147+ GetBSON() interface{}
1148+}
1149+
1150+// Objects implementing the bson.Setter interface will receive the BSON
1151+// value via the SetBSON method during unmarshaling, and will not be
1152+// changed as usual. If setting the value works, the method should
1153+// return true. If it returns false, the given value will be omitted
1154+// from maps and slices.
1155+type Setter interface {
1156+ SetBSON(v interface{}) (ok bool)
1157+}
1158+
1159+// Handy alias for a map[string]interface{} map, useful for dealing with BSON
1160+// in a native way. For instance:
1161+//
1162+// bson.M{"a": 1, "b": true}
1163+//
1164+// There's no special handling for this type in addition to what's done anyway
1165+// for an equivalent map type. Elements in the map will be dumped in an
1166+// undefined ordered. See also the bson.D type for an ordered alternative.
1167+type M map[string]interface{}
1168+
1169+// Type for dealing with documents containing ordered elements in a native
1170+// fashion. For instance:
1171+//
1172+// bson.D{{"a", 1}, {"b", true}}
1173+//
1174+// In some situations, such as when creating indexes for MongoDB, the order in
1175+// which the elements are defined is important. If the order is not important,
1176+// using a map is generally more comfortable (see the bson.M type and the
1177+// Map() method for D).
1178+type D []DocElem
1179+
1180+// See the bson.D type.
1181+type DocElem struct {
1182+ Name string
1183+ Value interface{}
1184+}
1185+
1186+// Raw may be used to work with raw unprocessed BSON documents and elements,
1187+// if necessary in advanced cases. Kind is the kind of element as defined
1188+// per the BSON specification, and Data is the raw unprocessed data for
1189+// the respective element.
1190+//
1191+// Relevant documentation:
1192+//
1193+// http://bsonspec.org/#/specification
1194+//
1195+type Raw struct {
1196+ Kind byte
1197+ Data []byte
1198+}
1199+
1200+// Build a map[string]interface{} out of the ordered element name/value pairs.
1201+func (d D) Map() (m M) {
1202+ m = make(M, len(d))
1203+ for _, item := range d {
1204+ m[item.Name] = item.Value
1205+ }
1206+ return m
1207+}
1208+
1209+// Unique ID identifying the BSON object. Must be exactly 12 bytes long.
1210+// MongoDB objects by default have such a property set in their "_id"
1211+// property.
1212+//
1213+// http://www.mongodb.org/display/DOCS/Object+IDs
1214+type ObjectId string
1215+
1216+// ObjectIdHex returns an ObjectId from the provided hex representation.
1217+// Calling this function with an invalid hex representation will
1218+// cause a runtime panic.
1219+func ObjectIdHex(s string) ObjectId {
1220+ d, err := hex.DecodeString(s)
1221+ if err != nil || len(d) != 12 {
1222+ panic(fmt.Sprintf("Invalid input to ObjectIdHex: %q", s))
1223+ }
1224+ return ObjectId(d)
1225+}
1226+
1227+// objectIdCounter is atomically incremented when generating a new ObjectId
1228+// using NewObjectId() function. It's used as a counter part of an id.
1229+var objectIdCounter uint32 = 0
1230+
1231+// machineId stores machine id generated once and used in subsequent calls
1232+// to NewObjectId function.
1233+var machineId []byte
1234+
1235+// initMachineId generates machine id and puts it into the machineId global
1236+// variable. If this function fails to get the hostname, it will cause
1237+// a runtime error.
1238+func initMachineId() {
1239+ var sum [3]byte
1240+ hostname, err := os.Hostname()
1241+ if err != nil {
1242+ panic("Failed to get hostname: " + err.String())
1243+ }
1244+ hw := md5.New()
1245+ hw.Write([]byte(hostname))
1246+ copy(sum[:3], hw.Sum())
1247+ machineId = sum[:]
1248+}
1249+
1250+// NewObjectId generates and returns a new unique ObjectId.
1251+// This function causes a runtime error if it fails to get the hostname
1252+// of the current machine.
1253+func NewObjectId() ObjectId {
1254+ b := make([]byte, 12)
1255+ // Timestamp, 4 bytes, big endian
1256+ binary.BigEndian.PutUint32(b, uint32(time.Seconds()))
1257+ // Machine, first 3 bytes of md5(hostname)
1258+ if machineId == nil {
1259+ initMachineId()
1260+ }
1261+ b[4] = machineId[0]
1262+ b[5] = machineId[1]
1263+ b[6] = machineId[2]
1264+ // Pid, 2 bytes, specs don't specify endianness, but we use big endian.
1265+ pid := os.Getpid()
1266+ b[7] = byte(pid >> 8)
1267+ b[8] = byte(pid)
1268+ // Increment, 3 bytes, big endian
1269+ i := atomic.AddUint32(&objectIdCounter, 1)
1270+ b[9] = byte(i >> 16)
1271+ b[10] = byte(i >> 8)
1272+ b[11] = byte(i)
1273+ return ObjectId(b)
1274+}
1275+
1276+// NewObjectIdSeconds returns a dummy ObjectId with the timestamp part filled
1277+// with the provided number of seconds from epoch UTC, and all other parts
1278+// filled with zeroes. It's not safe to insert a document with an id generated
1279+// by this method, it is useful only for queries to find documents with ids
1280+// generated before or after the specified timestamp.
1281+func NewObjectIdSeconds(sec int32) ObjectId {
1282+ var b [12]byte
1283+ binary.BigEndian.PutUint32(b[:4], uint32(sec))
1284+ return ObjectId(string(b[:]))
1285+}
1286+
1287+// String returns a hex string representation of the id.
1288+// Example: ObjectIdHex("4d88e15b60f486e428412dc9").
1289+func (id ObjectId) String() string {
1290+ return `ObjectIdHex("` + hex.EncodeToString([]byte(string(id))) + `")`
1291+}
1292+
1293+// Valid returns true if the id is valid (contains exactly 12 bytes)
1294+func (id ObjectId) Valid() bool {
1295+ return len(id) == 12
1296+}
1297+
1298+// byteSlice returns byte slice of id from start to end.
1299+// Calling this function with an invalid id will cause a runtime panic.
1300+func (id ObjectId) byteSlice(start, end int) []byte {
1301+ if len(id) != 12 {
1302+ panic(fmt.Sprintf("Invalid ObjectId: %q", string(id)))
1303+ }
1304+ return []byte(string(id)[start:end])
1305+}
1306+
1307+// Timestamp returns the timestamp part of the id (the number of seconds
1308+// from epoch in UTC).
1309+// It's a runtime error to call this method with an invalid id.
1310+func (id ObjectId) Timestamp() int32 {
1311+ // First 4 bytes of ObjectId is 32-bit big-endian timestamp
1312+ return int32(binary.BigEndian.Uint32(id.byteSlice(0, 4)))
1313+}
1314+
1315+// Machine returns the 3-byte machine id part of the id.
1316+// It's a runtime error to call this method with an invalid id.
1317+func (id ObjectId) Machine() []byte {
1318+ return id.byteSlice(4, 7)
1319+}
1320+
1321+// Pid returns the process id part of the id.
1322+// It's a runtime error to call this method with an invalid id.
1323+func (id ObjectId) Pid() uint16 {
1324+ return binary.BigEndian.Uint16(id.byteSlice(7, 9))
1325+}
1326+
1327+// Counter returns the incrementing value part of the id.
1328+// It's a runtime error to call this method with an invalid id.
1329+func (id ObjectId) Counter() int32 {
1330+ b := id.byteSlice(9, 12)
1331+ // Counter is stored as big-endian 3-byte value
1332+ return int32(uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2]))
1333+}
1334+
1335+// Similar to a string, but used in languages with a distinct symbol type. This
1336+// is an alias to a string type, so it can be used in string contexts and
1337+// string(symbol) will work correctly.
1338+type Symbol string
1339+
1340+// UTC timestamp defined as nanoseconds since the traditional epoch time. The
1341+// internal MongoDB representation stores this value as milliseconds, so some
1342+// precision will be lost when sending a Go value to MongoDB, but given that
1343+// Go most commonly uses nanoseconds in time-related operations, this conversion
1344+// is convenient.
1345+type Timestamp int64
1346+
1347+// Now returns a Timestamp value with the current time in nanoseconds.
1348+func Now() Timestamp {
1349+ // The value is stored in MongoDB as milliseconds, so truncate the value
1350+ // ahead of time to avoid surprises after a roundtrip.
1351+ return Timestamp(time.Nanoseconds() / 1e6 * 1e6)
1352+}
1353+
1354+// Special internal type used by MongoDB which for some strange reason has its
1355+// own datatype defined in BSON.
1356+type MongoTimestamp int64
1357+
1358+type orderKey int64
1359+
1360+// Special value which compares higher than all other possible BSON values.
1361+var MaxKey = orderKey(1<<63 - 1)
1362+
1363+// Special value which compares lower than all other possible BSON values.
1364+var MinKey = orderKey(-1 << 63)
1365+
1366+type undefined struct{}
1367+
1368+var Undefined undefined
1369+
1370+// Representation for non-standard binary values. Any kind should work,
1371+// but the following are known as of this writing:
1372+//
1373+// 0x00 - Generic. This is decoded as []byte(data), not Binary{0x00, data}.
1374+// 0x01 - Function (!?)
1375+// 0x02 - Obsolete generic.
1376+// 0x03 - UUID
1377+// 0x05 - MD5
1378+// 0x80 - User defined.
1379+//
1380+type Binary struct {
1381+ Kind byte
1382+ Data []byte
1383+}
1384+
1385+// A special type for regular expressions. The Options field should contain
1386+// individual characters defining the way in which the pattern should be
1387+// applied, and must be sorted. Valid options as of this writing are 'i' for
1388+// case insensitive matching, 'm' for multi-line matching, 'x' for verbose
1389+// mode, 'l' to make \w, \W, and similar be locale-dependent, 's' for dot-all
1390+// mode (a '.' matches everything), and 'u' to make \w, \W, and similar match
1391+// unicode. The value of the Options parameter is not verified before being
1392+// marshaled into the BSON format.
1393+type RegEx struct {
1394+ Pattern string
1395+ Options string
1396+}
1397+
1398+// Special type for JavaScript code. If Scope is non-nil, it will be marshaled
1399+// as a mapping from identifiers to values which should be used when evaluating
1400+// the provided Code.
1401+type JS struct {
1402+ Code string
1403+ Scope interface{}
1404+}
1405+
1406+
1407+const initialBufferSize = 64
1408+
1409+func handleErr(err *os.Error) {
1410+ if r := recover(); r != nil {
1411+ if _, ok := r.(runtime.Error); ok {
1412+ panic(r)
1413+ } else if s, ok := r.(string); ok {
1414+ *err = os.NewError(s)
1415+ } else if e, ok := r.(os.Error); ok {
1416+ *err = e
1417+ } else {
1418+ panic(r)
1419+ }
1420+ }
1421+}
1422+
1423+
1424+// Marshal serializes the in document, which may be a map or a struct value.
1425+// In the case of struct values, only exported fields will be serialized.
1426+// These fields may optionally have tags to define the serialization key for
1427+// the respective fields. Without a tag, the lowercased field name is used
1428+// as the key for each field. If a field tag ends in "/c", that field will
1429+// only be serialized if it's not set to the zero value for the field type.
1430+// If a field tag ends with the "/s" suffix, an int64 value in the given
1431+// field will be serialized as an int32 if possible.
1432+func Marshal(in interface{}) (out []byte, err os.Error) {
1433+ defer handleErr(&err)
1434+ e := &encoder{make([]byte, 0, initialBufferSize)}
1435+ e.addDoc(reflect.ValueOf(in))
1436+ return e.out, nil
1437+}
1438+
1439+// Unmarshal deserializes data from in into the out value. The out value
1440+// must be a map or a pointer to a struct (or a pointer to a struct pointer).
1441+// In the case of struct values, field names are mapped to the struct using
1442+// the field tag as the key. If the field has no tag, its lowercased name
1443+// will be used as the default key. Nil values are properly initialized
1444+// when necessary.
1445+//
1446+// The target field types of out may not necessarily match the BSON values
1447+// of the provided data. If there is a sensible way to unmarshal the values
1448+// into the Go types, they will be converted. Otherwise, the incompatible
1449+// values will be silently skipped.
1450+func Unmarshal(in []byte, out interface{}) (err os.Error) {
1451+ defer handleErr(&err)
1452+ v := reflect.ValueOf(out)
1453+ switch v.Kind() {
1454+ case reflect.Map, reflect.Ptr:
1455+ d := &decoder{in: in}
1456+ d.readDocTo(v)
1457+ case reflect.Struct:
1458+ return os.NewError("Unmarshal can't deal with struct values. Use a pointer.")
1459+ default:
1460+ return os.NewError("Unmarshal needs a map or a pointer to a struct.")
1461+ }
1462+ return nil
1463+}
1464+
1465+// Unmarshal deserializes raw into the out value. In addition to whole
1466+// documents, Raw's Unmarshal may also be used to unmarshal the data for
1467+// individual elements within a partially unmarshalled document. This
1468+// enables parts of a document to be lazily and conditionally deserialized.
1469+//
1470+// If the out value type is not compatible with raw, a *bson.TypeError
1471+// is returned.
1472+func (raw Raw) Unmarshal(out interface{}) (err os.Error) {
1473+ defer handleErr(&err)
1474+ v := reflect.ValueOf(out)
1475+ switch v.Kind() {
1476+ case reflect.Map, reflect.Ptr:
1477+ d := &decoder{in: raw.Data}
1478+ good := d.readElemTo(v, raw.Kind)
1479+ if !good {
1480+ return &TypeError{v.Type(), raw.Kind}
1481+ }
1482+ default:
1483+ return os.NewError("Raw Unmarshal needs a map or a valid pointer.")
1484+ }
1485+ return nil
1486+}
1487+
1488+type TypeError struct {
1489+ Type reflect.Type
1490+ Kind byte
1491+}
1492+
1493+func (e *TypeError) String() string {
1494+ return fmt.Sprintf("BSON kind 0x%02x isn't compatible with type %s", e.Kind, e.Type.String())
1495+}
1496+
1497+// --------------------------------------------------------------------------
1498+// Maintain a mapping of keys to structure field indexes
1499+
1500+type structFields struct {
1501+ Map map[string]fieldInfo
1502+ List []fieldInfo
1503+}
1504+
1505+type fieldInfo struct {
1506+ Key string
1507+ Num int
1508+ Conditional bool
1509+ Short bool
1510+}
1511+
1512+var fieldMap = make(map[string]*structFields)
1513+var fieldMapMutex sync.RWMutex
1514+
1515+func getStructFields(st reflect.Type) (*structFields, os.Error) {
1516+ path := st.PkgPath()
1517+ name := st.Name()
1518+
1519+ fullName := path + "." + name
1520+ fieldMapMutex.RLock()
1521+ fields, found := fieldMap[fullName]
1522+ fieldMapMutex.RUnlock()
1523+ if found {
1524+ return fields, nil
1525+ }
1526+
1527+ n := st.NumField()
1528+ fieldsMap := make(map[string]fieldInfo)
1529+ fieldsList := make([]fieldInfo, n)
1530+ for i := 0; i != n; i++ {
1531+ field := st.Field(i)
1532+ if field.PkgPath != "" {
1533+ continue // Private field
1534+ }
1535+
1536+ info := fieldInfo{Num: i}
1537+
1538+ if s := strings.LastIndex(string(field.Tag), "/"); s != -1 {
1539+ for _, c := range field.Tag[s+1:] {
1540+ switch c {
1541+ case int('c'):
1542+ info.Conditional = true
1543+ case int('s'):
1544+ info.Short = true
1545+ default:
1546+ panic("Unsupported field flag: " + string([]int{c}))
1547+ }
1548+ }
1549+ field.Tag = field.Tag[:s]
1550+ }
1551+
1552+ if field.Tag != "" {
1553+ info.Key = string(field.Tag)
1554+ } else {
1555+ info.Key = strings.ToLower(field.Name)
1556+ }
1557+
1558+ if _, found = fieldsMap[info.Key]; found {
1559+ msg := "Duplicated key '" + info.Key + "' in struct " + st.String()
1560+ return nil, os.NewError(msg)
1561+ }
1562+
1563+ fieldsList[len(fieldsMap)] = info
1564+ fieldsMap[info.Key] = info
1565+ }
1566+
1567+ fields = &structFields{fieldsMap, fieldsList[:len(fieldsMap)]}
1568+
1569+ if fullName != "." {
1570+ fieldMapMutex.Lock()
1571+ fieldMap[fullName] = fields
1572+ fieldMapMutex.Unlock()
1573+ }
1574+
1575+ return fields, nil
1576+}
1577
1578=== added file 'gobson_test.go'
1579--- gobson_test.go 1970-01-01 00:00:00 +0000
1580+++ gobson_test.go 2011-07-28 17:08:30 +0000
1581@@ -0,0 +1,1096 @@
1582+// gobson - BSON library for Go.
1583+//
1584+// Copyright (c) 2010-2011 - Gustavo Niemeyer <gustavo@niemeyer.net>
1585+//
1586+// All rights reserved.
1587+//
1588+// Redistribution and use in source and binary forms, with or without
1589+// modification, are permitted provided that the following conditions are met:
1590+//
1591+// * Redistributions of source code must retain the above copyright notice,
1592+// this list of conditions and the following disclaimer.
1593+// * Redistributions in binary form must reproduce the above copyright notice,
1594+// this list of conditions and the following disclaimer in the documentation
1595+// and/or other materials provided with the distribution.
1596+// * Neither the name of the copyright holder nor the names of its
1597+// contributors may be used to endorse or promote products derived from
1598+// this software without specific prior written permission.
1599+//
1600+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1601+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1602+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1603+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
1604+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
1605+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1606+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1607+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
1608+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
1609+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1610+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1611+
1612+package bson_test
1613+
1614+import (
1615+ . "launchpad.net/gocheck"
1616+ "encoding/binary"
1617+ "testing"
1618+ "reflect"
1619+ "time"
1620+ "launchpad.net/gobson/bson"
1621+)
1622+
1623+
1624+func TestAll(t *testing.T) {
1625+ TestingT(t)
1626+}
1627+
1628+type S struct{}
1629+
1630+var _ = Suite(&S{})
1631+
1632+
1633+// Wrap up the document elements contained in data, prepending the int32
1634+// length of the data, and appending the '\x00' value closing the document.
1635+func wrapInDoc(data string) string {
1636+ result := make([]byte, len(data)+5)
1637+ binary.LittleEndian.PutUint32(result, uint32(len(result)))
1638+ copy(result[4:], []byte(data))
1639+ return string(result)
1640+}
1641+
1642+func makeZeroDoc(value interface{}) (zero interface{}) {
1643+ v := reflect.ValueOf(value)
1644+ t := v.Type()
1645+ if t.Kind() == reflect.Map {
1646+ mv := reflect.MakeMap(t)
1647+ zero = mv.Interface()
1648+ } else {
1649+ pv := reflect.New(v.Type().Elem())
1650+ zero = pv.Interface()
1651+ }
1652+ return zero
1653+}
1654+
1655+func testUnmarshal(c *C, data string, obj interface{}) {
1656+ zero := makeZeroDoc(obj)
1657+ err := bson.Unmarshal([]byte(data), zero)
1658+ c.Assert(err, IsNil)
1659+ c.Assert(zero, Equals, obj)
1660+}
1661+
1662+
1663+type testItemType struct {
1664+ obj interface{}
1665+ data string
1666+}
1667+
1668+// --------------------------------------------------------------------------
1669+// Samples from bsonspec.org:
1670+
1671+var sampleItems = []testItemType{
1672+ {bson.M{"hello": "world"},
1673+ "\x16\x00\x00\x00\x02hello\x00\x06\x00\x00\x00world\x00\x00"},
1674+ {bson.M{"BSON": []interface{}{"awesome", float64(5.05), 1986}},
1675+ "1\x00\x00\x00\x04BSON\x00&\x00\x00\x00\x020\x00\x08\x00\x00\x00" +
1676+ "awesome\x00\x011\x00333333\x14@\x102\x00\xc2\x07\x00\x00\x00\x00"},
1677+}
1678+
1679+func (s *S) TestMarshalSampleItems(c *C) {
1680+ for i, item := range sampleItems {
1681+ data, err := bson.Marshal(item.obj)
1682+ c.Assert(err, IsNil)
1683+ c.Assert(string(data), Equals, item.data,
1684+ Bug("Failed on item %d", i))
1685+ }
1686+}
1687+
1688+func (s *S) TestUnmarshalSampleItems(c *C) {
1689+ for i, item := range sampleItems {
1690+ value := bson.M{}
1691+ err := bson.Unmarshal([]byte(item.data), value)
1692+ c.Assert(err, IsNil)
1693+ c.Assert(value, Equals, item.obj,
1694+ Bug("Failed on item %d", i))
1695+ }
1696+}
1697+
1698+// --------------------------------------------------------------------------
1699+// Every type, ordered by the type flag. These are not wrapped with the
1700+// length and last \x00 from the document. wrapInDoc() computes them.
1701+// Note that all of them should be supported as two-way conversions.
1702+
1703+var allItems = []testItemType{
1704+ {bson.M{},
1705+ ""},
1706+ {bson.M{"_": float64(5.05)},
1707+ "\x01_\x00333333\x14@"},
1708+ {bson.M{"_": "yo"},
1709+ "\x02_\x00\x03\x00\x00\x00yo\x00"},
1710+ {bson.M{"_": bson.M{"a": true}},
1711+ "\x03_\x00\x09\x00\x00\x00\x08a\x00\x01\x00"},
1712+ {bson.M{"_": []interface{}{true, false}},
1713+ "\x04_\x00\r\x00\x00\x00\x080\x00\x01\x081\x00\x00\x00"},
1714+ {bson.M{"_": []byte("yo")},
1715+ "\x05_\x00\x02\x00\x00\x00\x00yo"},
1716+ {bson.M{"_": bson.Binary{0x02, []byte("old")}},
1717+ "\x05_\x00\x07\x00\x00\x00\x02\x03\x00\x00\x00old"},
1718+ {bson.M{"_": bson.Binary{0x80, []byte("udef")}},
1719+ "\x05_\x00\x04\x00\x00\x00\x80udef"},
1720+ {bson.M{"_": bson.Undefined}, // Obsolete, but still seen in the wild.
1721+ "\x06_\x00"},
1722+ {bson.M{"_": bson.ObjectId("0123456789ab")},
1723+ "\x07_\x000123456789ab"},
1724+ {bson.M{"_": false},
1725+ "\x08_\x00\x00"},
1726+ {bson.M{"_": true},
1727+ "\x08_\x00\x01"},
1728+ {bson.M{"_": bson.Timestamp(258e6)}, // Note the NS <=> MS conversion.
1729+ "\x09_\x00\x02\x01\x00\x00\x00\x00\x00\x00"},
1730+ {bson.M{"_": nil},
1731+ "\x0A_\x00"},
1732+ {bson.M{"_": bson.RegEx{"ab", "cd"}},
1733+ "\x0B_\x00ab\x00cd\x00"},
1734+ {bson.M{"_": bson.JS{"code", nil}},
1735+ "\x0D_\x00\x05\x00\x00\x00code\x00"},
1736+ {bson.M{"_": bson.Symbol("sym")},
1737+ "\x0E_\x00\x04\x00\x00\x00sym\x00"},
1738+ {bson.M{"_": bson.JS{"code", bson.M{"": nil}}},
1739+ "\x0F_\x00\x14\x00\x00\x00\x05\x00\x00\x00code\x00" +
1740+ "\x07\x00\x00\x00\x0A\x00\x00"},
1741+ {bson.M{"_": 258},
1742+ "\x10_\x00\x02\x01\x00\x00"},
1743+ {bson.M{"_": bson.MongoTimestamp(258)},
1744+ "\x11_\x00\x02\x01\x00\x00\x00\x00\x00\x00"},
1745+ {bson.M{"_": int64(258)},
1746+ "\x12_\x00\x02\x01\x00\x00\x00\x00\x00\x00"},
1747+ {bson.M{"_": int64(258 << 32)},
1748+ "\x12_\x00\x00\x00\x00\x00\x02\x01\x00\x00"},
1749+ {bson.M{"_": bson.MaxKey},
1750+ "\x7F_\x00"},
1751+ {bson.M{"_": bson.MinKey},
1752+ "\xFF_\x00"},
1753+}
1754+
1755+func (s *S) TestMarshalAllItems(c *C) {
1756+ for i, item := range allItems {
1757+ data, err := bson.Marshal(item.obj)
1758+ c.Assert(err, IsNil)
1759+ c.Assert(string(data), Equals, wrapInDoc(item.data), Bug("Failed on item %d: %#v", i, item))
1760+ }
1761+}
1762+
1763+func (s *S) TestUnmarshalAllItems(c *C) {
1764+ for i, item := range allItems {
1765+ value := bson.M{}
1766+ err := bson.Unmarshal([]byte(wrapInDoc(item.data)), value)
1767+ c.Assert(err, IsNil)
1768+ c.Assert(value, Equals, item.obj, Bug("Failed on item %d: %#v", i, item))
1769+ }
1770+}
1771+
1772+func (s *S) TestUnmarshalRawAllItems(c *C) {
1773+ for i, item := range allItems {
1774+ if len(item.data) == 0 {
1775+ continue
1776+ }
1777+ value := item.obj.(bson.M)["_"]
1778+ if value == nil {
1779+ continue
1780+ }
1781+ pv := reflect.New(reflect.ValueOf(value).Type())
1782+ raw := bson.Raw{item.data[0], []byte(item.data[3:])}
1783+ c.Logf("Unmarshal raw: %#v, %#v", raw, pv.Interface())
1784+ err := raw.Unmarshal(pv.Interface())
1785+ c.Assert(err, IsNil)
1786+ c.Assert(pv.Elem().Interface(), Equals, value, Bug("Failed on item %d: %#v", i, item))
1787+ }
1788+}
1789+
1790+func (s *S) TestUnmarshalRawIncompatible(c *C) {
1791+ raw := bson.Raw{0x08, []byte{0x01}} // true
1792+ err := raw.Unmarshal(&struct{}{})
1793+ c.Assert(err, Matches, `BSON kind 0x08 isn't compatible with type \*struct { }`)
1794+}
1795+
1796+// --------------------------------------------------------------------------
1797+// Some one way marshaling operations which would unmarshal differently.
1798+
1799+var oneWayMarshalItems = []testItemType{
1800+ // These are being passed as pointers, and will unmarshal as values.
1801+ {bson.M{"": &bson.Binary{0x02, []byte("old")}},
1802+ "\x05\x00\x07\x00\x00\x00\x02\x03\x00\x00\x00old"},
1803+ {bson.M{"": &bson.Binary{0x80, []byte("udef")}},
1804+ "\x05\x00\x04\x00\x00\x00\x80udef"},
1805+ {bson.M{"": &bson.RegEx{"ab", "cd"}},
1806+ "\x0B\x00ab\x00cd\x00"},
1807+ {bson.M{"": &bson.JS{"code", nil}},
1808+ "\x0D\x00\x05\x00\x00\x00code\x00"},
1809+ {bson.M{"": &bson.JS{"code", bson.M{"": nil}}},
1810+ "\x0F\x00\x14\x00\x00\x00\x05\x00\x00\x00code\x00" +
1811+ "\x07\x00\x00\x00\x0A\x00\x00"},
1812+
1813+ // There's no float32 type in BSON. Will encode as a float64.
1814+ {bson.M{"": float32(5.05)},
1815+ "\x01\x00\x00\x00\x00@33\x14@"},
1816+
1817+ // The array will be unmarshaled as a slice instead.
1818+ {bson.M{"": [2]bool{true, false}},
1819+ "\x04\x00\r\x00\x00\x00\x080\x00\x01\x081\x00\x00\x00"},
1820+
1821+ // The typed slice will be unmarshaled as []interface{}.
1822+ {bson.M{"": []bool{true, false}},
1823+ "\x04\x00\r\x00\x00\x00\x080\x00\x01\x081\x00\x00\x00"},
1824+
1825+ // Will unmarshal as a []byte.
1826+ {bson.M{"": bson.Binary{0x00, []byte("yo")}},
1827+ "\x05\x00\x02\x00\x00\x00\x00yo"},
1828+
1829+ // No way to preserve the type information here. We might encode as a zero
1830+ // value, but this would mean that pointer values in structs wouldn't be
1831+ // able to correctly distinguish between unset and set to the zero value.
1832+ {bson.M{"": (*byte)(nil)},
1833+ "\x0A\x00"},
1834+
1835+ // No int types smaller than int32 in BSON. Could encode this as a char,
1836+ // but it would still be ambiguous, take more, and be awkward in Go when
1837+ // loaded without typing information.
1838+ {bson.M{"": byte(8)},
1839+ "\x10\x00\x08\x00\x00\x00"},
1840+
1841+ // There are no unsigned types in BSON. Will unmarshal as int32 or int64.
1842+ {bson.M{"": uint32(258)},
1843+ "\x10\x00\x02\x01\x00\x00"},
1844+ {bson.M{"": uint64(258)},
1845+ "\x12\x00\x02\x01\x00\x00\x00\x00\x00\x00"},
1846+ {bson.M{"": uint64(258 << 32)},
1847+ "\x12\x00\x00\x00\x00\x00\x02\x01\x00\x00"},
1848+
1849+ // This will unmarshal as int.
1850+ {bson.M{"": int32(258)},
1851+ "\x10\x00\x02\x01\x00\x00"},
1852+
1853+ // That's a special case. The unsigned value is too large for an int32,
1854+ // so an int64 is used instead.
1855+ {bson.M{"": uint32(1<<32 - 1)},
1856+ "\x12\x00\xFF\xFF\xFF\xFF\x00\x00\x00\x00"},
1857+ {bson.M{"": uint(1<<32 - 1)},
1858+ "\x12\x00\xFF\xFF\xFF\xFF\x00\x00\x00\x00"},
1859+}
1860+
1861+func (s *S) TestOneWayMarshalItems(c *C) {
1862+ for i, item := range oneWayMarshalItems {
1863+ data, err := bson.Marshal(item.obj)
1864+ c.Assert(err, IsNil)
1865+ c.Assert(string(data), Equals, wrapInDoc(item.data),
1866+ Bug("Failed on item %d", i))
1867+ }
1868+}
1869+
1870+
1871+// --------------------------------------------------------------------------
1872+// Two-way tests for user-defined structures using the samples
1873+// from bsonspec.org.
1874+
1875+type specSample1 struct {
1876+ Hello string
1877+}
1878+
1879+type specSample2 struct {
1880+ BSON []interface{} "BSON"
1881+}
1882+
1883+var structSampleItems = []testItemType{
1884+ {&specSample1{"world"},
1885+ "\x16\x00\x00\x00\x02hello\x00\x06\x00\x00\x00world\x00\x00"},
1886+ {&specSample2{[]interface{}{"awesome", float64(5.05), 1986}},
1887+ "1\x00\x00\x00\x04BSON\x00&\x00\x00\x00\x020\x00\x08\x00\x00\x00" +
1888+ "awesome\x00\x011\x00333333\x14@\x102\x00\xc2\x07\x00\x00\x00\x00"},
1889+}
1890+
1891+
1892+func (s *S) TestMarshalStructSampleItems(c *C) {
1893+ for i, item := range structSampleItems {
1894+ data, err := bson.Marshal(item.obj)
1895+ c.Assert(err, IsNil)
1896+ c.Assert(string(data), Equals, item.data,
1897+ Bug("Failed on item %d", i))
1898+ }
1899+}
1900+
1901+func (s *S) TestUnmarshalStructSampleItems(c *C) {
1902+ for _, item := range structSampleItems {
1903+ testUnmarshal(c, item.data, item.obj)
1904+ }
1905+}
1906+
1907+
1908+// --------------------------------------------------------------------------
1909+// Generic two-way struct marshaling tests.
1910+
1911+var bytevar = byte(8)
1912+var byteptr = &bytevar
1913+
1914+var structItems = []testItemType{
1915+ {&struct{ Ptr *byte }{nil},
1916+ "\x0Aptr\x00"},
1917+ {&struct{ Ptr *byte }{&bytevar},
1918+ "\x10ptr\x00\x08\x00\x00\x00"},
1919+ {&struct{ Ptr **byte }{&byteptr},
1920+ "\x10ptr\x00\x08\x00\x00\x00"},
1921+ {&struct{ Byte byte }{8},
1922+ "\x10byte\x00\x08\x00\x00\x00"},
1923+ {&struct{ Byte byte }{0},
1924+ "\x10byte\x00\x00\x00\x00\x00"},
1925+ {&struct {
1926+ V byte "Tag"
1927+ }{8},
1928+ "\x10Tag\x00\x08\x00\x00\x00"},
1929+ {&struct {
1930+ V *struct {
1931+ Byte byte
1932+ }
1933+ }{&struct{ Byte byte }{8}},
1934+ "\x03v\x00" + "\x0f\x00\x00\x00\x10byte\x00\b\x00\x00\x00\x00"},
1935+ {&struct{ priv byte }{}, ""},
1936+
1937+ // The order of the dumped fields should be the same in the struct.
1938+ {&struct{ A, C, B, D, F, E *byte }{},
1939+ "\x0Aa\x00\x0Ac\x00\x0Ab\x00\x0Ad\x00\x0Af\x00\x0Ae\x00"},
1940+
1941+ {&struct{ V bson.Raw }{bson.Raw{0x03, []byte("\x0f\x00\x00\x00\x10byte\x00\b\x00\x00\x00\x00")}},
1942+ "\x03v\x00" + "\x0f\x00\x00\x00\x10byte\x00\b\x00\x00\x00\x00"},
1943+ {&struct{ V bson.Raw }{bson.Raw{0x10, []byte("\x00\x00\x00\x00")}},
1944+ "\x10v\x00" + "\x00\x00\x00\x00"},
1945+
1946+ // Byte arrays.
1947+ {&struct{ V [2]byte }{[2]byte{'y', 'o'}},
1948+ "\x05v\x00\x02\x00\x00\x00\x00yo"},
1949+}
1950+
1951+
1952+func (s *S) TestMarshalStructItems(c *C) {
1953+ for i, item := range structItems {
1954+ data, err := bson.Marshal(item.obj)
1955+ c.Assert(err, IsNil)
1956+ c.Assert(string(data), Equals, wrapInDoc(item.data),
1957+ Bug("Failed on item %d", i))
1958+ }
1959+}
1960+
1961+func (s *S) TestUnmarshalStructItems(c *C) {
1962+ for _, item := range structItems {
1963+ testUnmarshal(c, wrapInDoc(item.data), item.obj)
1964+ }
1965+}
1966+
1967+
1968+// --------------------------------------------------------------------------
1969+// One-way marshaling tests.
1970+
1971+type dOnIface struct {
1972+ D interface{}
1973+}
1974+
1975+var marshalItems = []testItemType{
1976+ // Ordered document dump. Will unmarshal as a dictionary by default.
1977+ {bson.D{{"a", nil}, {"c", nil}, {"b", nil}, {"d", nil}, {"f", nil}, {"e", true}},
1978+ "\x0Aa\x00\x0Ac\x00\x0Ab\x00\x0Ad\x00\x0Af\x00\x08e\x00\x01"},
1979+ {&dOnIface{bson.D{{"a", nil}, {"c", nil}, {"b", nil}, {"d", true}}},
1980+ "\x03d\x00" + wrapInDoc("\x0Aa\x00\x0Ac\x00\x0Ab\x00\x08d\x00\x01")},
1981+
1982+ // Marshalling a Raw document does nothing.
1983+ {bson.Raw{0x03, []byte(wrapInDoc("anything"))},
1984+ "anything"},
1985+ {bson.Raw{Data: []byte(wrapInDoc("anything"))},
1986+ "anything"},
1987+}
1988+
1989+func (s *S) TestMarshalOneWayItems(c *C) {
1990+ for _, item := range marshalItems {
1991+ data, err := bson.Marshal(item.obj)
1992+ c.Assert(err, IsNil)
1993+ c.Assert(string(data), Equals, wrapInDoc(item.data))
1994+ }
1995+}
1996+
1997+// --------------------------------------------------------------------------
1998+// One-way unmarshaling tests.
1999+
2000+var unmarshalItems = []testItemType{
2001+ // Field is private. Should not attempt to unmarshal it.
2002+ {&struct{ priv byte }{},
2003+ "\x10priv\x00\x08\x00\x00\x00"},
2004+
2005+ // Wrong casing. Field names are lowercased.
2006+ {&struct{ Byte byte }{},
2007+ "\x10Byte\x00\x08\x00\x00\x00"},
2008+
2009+ // Ignore non-existing field.
2010+ {&struct{ Byte byte }{9},
2011+ "\x10boot\x00\x08\x00\x00\x00" + "\x10byte\x00\x09\x00\x00\x00"},
2012+
2013+ // Ignore unsuitable types silently.
2014+ {map[string]string{"str": "s"},
2015+ "\x02str\x00\x02\x00\x00\x00s\x00" + "\x10int\x00\x01\x00\x00\x00"},
2016+ {map[string][]int{"array": []int{5, 9}},
2017+ "\x04array\x00" +
2018+ wrapInDoc("\x100\x00\x05\x00\x00\x00"+
2019+ "\x021\x00\x02\x00\x00\x00s\x00"+
2020+ "\x102\x00\x09\x00\x00\x00")},
2021+
2022+ // Wrong type. Shouldn't init pointer.
2023+ {&struct{ Str *byte }{},
2024+ "\x02str\x00\x02\x00\x00\x00s\x00"},
2025+ {&struct{ Str *struct{ Str string } }{},
2026+ "\x02str\x00\x02\x00\x00\x00s\x00"},
2027+
2028+ // Ordered document.
2029+ {&struct{ bson.D }{bson.D{{"a", nil}, {"c", nil}, {"b", nil}, {"d", true}}},
2030+ "\x03d\x00" + wrapInDoc("\x0Aa\x00\x0Ac\x00\x0Ab\x00\x08d\x00\x01")},
2031+
2032+ // Raw document.
2033+ {&bson.Raw{0x03, []byte(wrapInDoc("\x10byte\x00\x08\x00\x00\x00"))},
2034+ "\x10byte\x00\x08\x00\x00\x00"},
2035+}
2036+
2037+
2038+func (s *S) TestUnmarshalOneWayItems(c *C) {
2039+ for _, item := range unmarshalItems {
2040+ testUnmarshal(c, wrapInDoc(item.data), item.obj)
2041+ }
2042+}
2043+
2044+func (s *S) TestUnmarshalNilInStruct(c *C) {
2045+ // Nil is the default value, so we need to ensure it's indeed being set.
2046+ b := byte(1)
2047+ v := &struct{ Ptr *byte }{&b}
2048+ err := bson.Unmarshal([]byte(wrapInDoc("\x0Aptr\x00")), v)
2049+ c.Assert(err, IsNil)
2050+ c.Assert(v, Equals, &struct{ Ptr *byte }{nil})
2051+}
2052+
2053+// --------------------------------------------------------------------------
2054+// Marshalling error cases.
2055+
2056+type structWithDupKeys struct {
2057+ Name byte
2058+ Other byte "name" // Tag should precede.
2059+}
2060+
2061+var marshalErrorItems = []testItemType{
2062+ {bson.M{"": uint64(1 << 63)},
2063+ "BSON has no uint64 type, and value is too large to fit correctly in an int64"},
2064+ {bson.M{"": bson.ObjectId("tooshort")},
2065+ "ObjectIDs must be exactly 12 bytes long \\(got 8\\)"},
2066+ {int64(123),
2067+ "Can't marshal int64 as a BSON document"},
2068+ {bson.M{"": 1i},
2069+ "Can't marshal complex128 in a BSON document"},
2070+ {&structWithDupKeys{},
2071+ "Duplicated key 'name' in struct bson_test.structWithDupKeys"},
2072+ {bson.Raw{0x0A, []byte{}},
2073+ "Attempted to unmarshal Raw kind 10 as a document"},
2074+}
2075+
2076+func (s *S) TestMarshalErrorItems(c *C) {
2077+ for _, item := range marshalErrorItems {
2078+ data, err := bson.Marshal(item.obj)
2079+ c.Assert(err, Matches, item.data)
2080+ c.Assert(data, IsNil)
2081+ }
2082+}
2083+
2084+// --------------------------------------------------------------------------
2085+// Unmarshalling error cases.
2086+
2087+type unmarshalErrorType struct {
2088+ obj interface{}
2089+ data string
2090+ error string
2091+}
2092+
2093+var unmarshalErrorItems = []unmarshalErrorType{
2094+ // Tag name conflicts with existing parameter.
2095+ {&structWithDupKeys{},
2096+ "\x10name\x00\x08\x00\x00\x00",
2097+ "Duplicated key 'name' in struct bson_test.structWithDupKeys"},
2098+
2099+ // Non-string map key.
2100+ {map[int]interface{}{},
2101+ "\x10name\x00\x08\x00\x00\x00",
2102+ "BSON map must have string keys. Got: map\\[int\\] interface \\{ \\}"},
2103+
2104+ {nil,
2105+ "\xEEname\x00",
2106+ "Unknown element kind \\(0xEE\\)"},
2107+
2108+ {struct{ Name bool }{},
2109+ "\x10name\x00\x08\x00\x00\x00",
2110+ "Unmarshal can't deal with struct values. Use a pointer."},
2111+
2112+ {123,
2113+ "\x10name\x00\x08\x00\x00\x00",
2114+ "Unmarshal needs a map or a pointer to a struct."},
2115+}
2116+
2117+
2118+func (s *S) TestUnmarshalErrorItems(c *C) {
2119+ for _, item := range unmarshalErrorItems {
2120+ data := []byte(wrapInDoc(item.data))
2121+ var value interface{}
2122+ switch reflect.ValueOf(item.obj).Kind() {
2123+ case reflect.Map, reflect.Ptr:
2124+ value = makeZeroDoc(item.obj)
2125+ case reflect.Invalid:
2126+ value = bson.M{}
2127+ default:
2128+ value = item.obj
2129+ }
2130+ err := bson.Unmarshal(data, value)
2131+ c.Assert(err, Matches, item.error)
2132+ }
2133+}
2134+
2135+
2136+type unmarshalRawErrorType struct {
2137+ obj interface{}
2138+ raw bson.Raw
2139+ error string
2140+}
2141+
2142+var unmarshalRawErrorItems = []unmarshalRawErrorType{
2143+ // Tag name conflicts with existing parameter.
2144+ {&structWithDupKeys{},
2145+ bson.Raw{0x03, []byte("\x10byte\x00\x08\x00\x00\x00")},
2146+ "Duplicated key 'name' in struct bson_test.structWithDupKeys"},
2147+
2148+ {&struct{}{},
2149+ bson.Raw{0xEE, []byte{}},
2150+ "Unknown element kind \\(0xEE\\)"},
2151+
2152+ {struct{ Name bool }{},
2153+ bson.Raw{0x10, []byte("\x08\x00\x00\x00")},
2154+ "Raw Unmarshal needs a map or a valid pointer."},
2155+
2156+ {123,
2157+ bson.Raw{0x10, []byte("\x08\x00\x00\x00")},
2158+ "Raw Unmarshal needs a map or a valid pointer."},
2159+}
2160+
2161+func (s *S) TestUnmarshalRawErrorItems(c *C) {
2162+ for i, item := range unmarshalRawErrorItems {
2163+ err := item.raw.Unmarshal(item.obj)
2164+ c.Assert(err, Matches, item.error, Bug("Failed on item %d: %#v\n", i, item))
2165+ }
2166+}
2167+
2168+var corruptedData = []string{
2169+ "\x04\x00\x00\x00\x00", // Shorter than minimum
2170+ "\x06\x00\x00\x00\x00", // Not enough data
2171+ "\x05\x00\x00", // Broken length
2172+ "\x05\x00\x00\x00\xff", // Corrupted termination
2173+ "\x0A\x00\x00\x00\x0Aooop\x00", // Unfinished C string
2174+
2175+ // Array end past end of string (s[2]=0x07 is correct)
2176+ wrapInDoc("\x04\x00\x09\x00\x00\x00\x0A\x00\x00"),
2177+
2178+ // Array end within string, but past acceptable.
2179+ wrapInDoc("\x04\x00\x08\x00\x00\x00\x0A\x00\x00"),
2180+
2181+ // Document end within string, but past acceptable.
2182+ wrapInDoc("\x03\x00\x08\x00\x00\x00\x0A\x00\x00"),
2183+
2184+ // String with corrupted end.
2185+ wrapInDoc("\x02\x00\x03\x00\x00\x00yo\xFF"),
2186+}
2187+
2188+
2189+func (s *S) TestUnmarshalMapDocumentTooShort(c *C) {
2190+ for _, data := range corruptedData {
2191+ err := bson.Unmarshal([]byte(data), bson.M{})
2192+ c.Assert(err, Matches, "Document is corrupted")
2193+
2194+ err = bson.Unmarshal([]byte(data), &struct{}{})
2195+ c.Assert(err, Matches, "Document is corrupted")
2196+ }
2197+}
2198+
2199+
2200+// --------------------------------------------------------------------------
2201+// Setter test cases.
2202+
2203+var setterResult = map[string]bool{}
2204+
2205+type typeWithSetter struct {
2206+ received interface{}
2207+}
2208+
2209+func (o *typeWithSetter) SetBSON(value interface{}) (ok bool) {
2210+ o.received = value
2211+ if s, ok := value.(string); ok {
2212+ if result, ok := setterResult[s]; ok {
2213+ return result
2214+ }
2215+ }
2216+ return true
2217+}
2218+
2219+type docWithSetterField struct {
2220+ Field *typeWithSetter "_"
2221+}
2222+
2223+func (s *S) TestUnmarshalAllItemsWithSetter(c *C) {
2224+ for _, item := range allItems {
2225+ obj := &docWithSetterField{}
2226+ err := bson.Unmarshal([]byte(wrapInDoc(item.data)), obj)
2227+ c.Assert(err, IsNil)
2228+
2229+ if item.data == "" {
2230+ // Nothing to unmarshal. Should be untouched.
2231+ c.Assert(obj.Field, IsNil)
2232+ } else {
2233+ expected := item.obj.(bson.M)["_"]
2234+
2235+ if m, ok := expected.(bson.M); ok {
2236+ // Setter works with a bson.D slice rather than bson.M.
2237+ slice := make(bson.D, 0, len(m))
2238+ for key, value := range m {
2239+ slice = append(slice, bson.DocElem{key, value})
2240+ }
2241+ expected = slice
2242+ }
2243+
2244+ c.Assert(obj.Field, NotNil,
2245+ Bug("Pointer not initialized (%#v)", expected))
2246+ c.Assert(obj.Field.received, Equals, expected)
2247+ }
2248+ }
2249+}
2250+
2251+func (s *S) TestUnmarshalWholeDocumentWithSetter(c *C) {
2252+ obj := &typeWithSetter{}
2253+ err := bson.Unmarshal([]byte(sampleItems[0].data), obj)
2254+ c.Assert(err, IsNil)
2255+ c.Assert(obj.received, Equals, bson.D{{"hello", "world"}})
2256+}
2257+
2258+func (s *S) TestUnmarshalWithFalseSetterIgnoresValue(c *C) {
2259+ setterResult["2"] = false
2260+ setterResult["4"] = false
2261+ defer func() {
2262+ setterResult["2"] = false, false
2263+ setterResult["4"] = false, false
2264+ }()
2265+
2266+ m := map[string]*typeWithSetter{}
2267+ data := wrapInDoc("\x02abc\x00\x02\x00\x00\x001\x00" +
2268+ "\x02def\x00\x02\x00\x00\x002\x00" +
2269+ "\x02ghi\x00\x02\x00\x00\x003\x00" +
2270+ "\x02jkl\x00\x02\x00\x00\x004\x00")
2271+ err := bson.Unmarshal([]byte(data), m)
2272+ c.Assert(err, IsNil)
2273+ c.Assert(m["abc"], NotNil)
2274+ c.Assert(m["def"], IsNil)
2275+ c.Assert(m["ghi"], NotNil)
2276+ c.Assert(m["jkl"], IsNil)
2277+
2278+ c.Assert(m["abc"].received, Equals, "1")
2279+ c.Assert(m["ghi"].received, Equals, "3")
2280+}
2281+
2282+func (s *S) TestDMap(c *C) {
2283+ d := bson.D{{"a", 1}, {"b", 2}}
2284+ c.Assert(d.Map(), Equals, bson.M{"a": 1, "b": 2})
2285+}
2286+
2287+
2288+// --------------------------------------------------------------------------
2289+// Getter test cases.
2290+
2291+type typeWithGetter struct {
2292+ result interface{}
2293+}
2294+
2295+func (t *typeWithGetter) GetBSON() interface{} {
2296+ return t.result
2297+}
2298+
2299+type docWithGetterField struct {
2300+ Field *typeWithGetter "_"
2301+}
2302+
2303+func (s *S) TestMarshalAllItemsWithGetter(c *C) {
2304+ for i, item := range allItems {
2305+ if item.data == "" {
2306+ continue
2307+ }
2308+ obj := &docWithGetterField{}
2309+ obj.Field = &typeWithGetter{item.obj.(bson.M)["_"]}
2310+ data, err := bson.Marshal(obj)
2311+ c.Assert(err, IsNil)
2312+ c.Assert(string(data), Equals, wrapInDoc(item.data),
2313+ Bug("Failed on item #%d", i))
2314+ }
2315+}
2316+
2317+func (s *S) TestMarshalWholeDocumentWithGetter(c *C) {
2318+ obj := &typeWithGetter{sampleItems[0].obj}
2319+ data, err := bson.Marshal(obj)
2320+ c.Assert(err, IsNil)
2321+ c.Assert(string(data), Equals, sampleItems[0].data)
2322+}
2323+
2324+type intGetter int64
2325+
2326+func (t intGetter) GetBSON() interface{} {
2327+ return int64(t)
2328+}
2329+
2330+type typeWithIntGetter struct {
2331+ V intGetter "/s"
2332+}
2333+
2334+func (s *S) TestMarshalShortWithGetter(c *C) {
2335+ obj := typeWithIntGetter{42}
2336+ data, err := bson.Marshal(obj)
2337+ c.Assert(err, IsNil)
2338+ m := bson.M{}
2339+ err = bson.Unmarshal(data, m)
2340+ c.Assert(m["v"], Equals, 42)
2341+}
2342+
2343+// --------------------------------------------------------------------------
2344+// Cross-type conversion tests.
2345+
2346+type crossTypeItem struct {
2347+ obj1 interface{}
2348+ obj2 interface{}
2349+}
2350+
2351+type condStr struct {
2352+ V string "/c"
2353+}
2354+type condBool struct {
2355+ V bool "/c"
2356+}
2357+type condInt struct {
2358+ V int "/c"
2359+}
2360+type condUInt struct {
2361+ V uint "/c"
2362+}
2363+type condIface struct {
2364+ V interface{} "/c"
2365+}
2366+type condPtr struct {
2367+ V *bool "/c"
2368+}
2369+type condSlice struct {
2370+ V []string "/c"
2371+}
2372+type condMap struct {
2373+ V map[string]int "/c"
2374+}
2375+type namedCondStr struct {
2376+ V string "myv/c"
2377+}
2378+
2379+type shortInt struct {
2380+ V int64 "/s"
2381+}
2382+type shortUint struct {
2383+ V uint64 "/s"
2384+}
2385+type shortIface struct {
2386+ V interface{} "/s"
2387+}
2388+type shortPtr struct {
2389+ V *int64 "/s"
2390+}
2391+
2392+type slashedName struct {
2393+ V string "a/b/"
2394+}
2395+
2396+var truevar = true
2397+var falsevar = false
2398+
2399+var int64var = int64(42)
2400+var int64ptr = &int64var
2401+var intvar = int(42)
2402+var intptr = &intvar
2403+
2404+// That's a pretty fun test. It will dump the first item, generate a zero
2405+// value equivalent to the second one, load the dumped data onto it, and then
2406+// verify that the resulting value is deep-equal to the untouched second value.
2407+// Then, it will do the same in the *opposite* direction!
2408+var twoWayCrossItems = []crossTypeItem{
2409+ // int<=>int
2410+ {&struct{ I int }{42}, &struct{ I int8 }{42}},
2411+ {&struct{ I int }{42}, &struct{ I int32 }{42}},
2412+ {&struct{ I int }{42}, &struct{ I int64 }{42}},
2413+ {&struct{ I int8 }{42}, &struct{ I int32 }{42}},
2414+ {&struct{ I int8 }{42}, &struct{ I int64 }{42}},
2415+ {&struct{ I int32 }{42}, &struct{ I int64 }{42}},
2416+
2417+ // uint<=>uint
2418+ {&struct{ I uint }{42}, &struct{ I uint8 }{42}},
2419+ {&struct{ I uint }{42}, &struct{ I uint32 }{42}},
2420+ {&struct{ I uint }{42}, &struct{ I uint64 }{42}},
2421+ {&struct{ I uint8 }{42}, &struct{ I uint32 }{42}},
2422+ {&struct{ I uint8 }{42}, &struct{ I uint64 }{42}},
2423+ {&struct{ I uint32 }{42}, &struct{ I uint64 }{42}},
2424+
2425+ // float32<=>float64
2426+ {&struct{ I float32 }{42}, &struct{ I float64 }{42}},
2427+
2428+ // int<=>uint
2429+ {&struct{ I uint }{42}, &struct{ I int }{42}},
2430+ {&struct{ I uint }{42}, &struct{ I int8 }{42}},
2431+ {&struct{ I uint }{42}, &struct{ I int32 }{42}},
2432+ {&struct{ I uint }{42}, &struct{ I int64 }{42}},
2433+ {&struct{ I uint8 }{42}, &struct{ I int }{42}},
2434+ {&struct{ I uint8 }{42}, &struct{ I int8 }{42}},
2435+ {&struct{ I uint8 }{42}, &struct{ I int32 }{42}},
2436+ {&struct{ I uint8 }{42}, &struct{ I int64 }{42}},
2437+ {&struct{ I uint32 }{42}, &struct{ I int }{42}},
2438+ {&struct{ I uint32 }{42}, &struct{ I int8 }{42}},
2439+ {&struct{ I uint32 }{42}, &struct{ I int32 }{42}},
2440+ {&struct{ I uint32 }{42}, &struct{ I int64 }{42}},
2441+ {&struct{ I uint64 }{42}, &struct{ I int }{42}},
2442+ {&struct{ I uint64 }{42}, &struct{ I int8 }{42}},
2443+ {&struct{ I uint64 }{42}, &struct{ I int32 }{42}},
2444+ {&struct{ I uint64 }{42}, &struct{ I int64 }{42}},
2445+
2446+ // int <=> timestamp. Note the NS <=> MS conversion.
2447+ {&struct{ I bson.Timestamp }{42e6}, &struct{ I int64 }{42}},
2448+ {&struct{ I bson.Timestamp }{42e6}, &struct{ I int32 }{42}},
2449+ {&struct{ I bson.Timestamp }{42e6}, &struct{ I int }{42}},
2450+
2451+ // int <=> float
2452+ {&struct{ I int }{42}, &struct{ I float64 }{42}},
2453+
2454+ // int <=> bool
2455+ {&struct{ I int }{1}, &struct{ I bool }{true}},
2456+ {&struct{ I int }{0}, &struct{ I bool }{false}},
2457+
2458+ // uint <=> float64
2459+ {&struct{ I uint }{42}, &struct{ I float64 }{42}},
2460+
2461+ // uint <=> bool
2462+ {&struct{ I uint }{1}, &struct{ I bool }{true}},
2463+ {&struct{ I uint }{0}, &struct{ I bool }{false}},
2464+
2465+ // float64 <=> bool
2466+ {&struct{ I float64 }{1}, &struct{ I bool }{true}},
2467+ {&struct{ I float64 }{0}, &struct{ I bool }{false}},
2468+
2469+ // string <=> string and string <=> []byte
2470+ {&struct{ S []byte }{[]byte("abc")}, &struct{ S string }{"abc"}},
2471+ {&struct{ S []byte }{[]byte("def")}, &struct{ S bson.Symbol }{"def"}},
2472+ {&struct{ S string }{"ghi"}, &struct{ S bson.Symbol }{"ghi"}},
2473+
2474+ // map <=> struct
2475+ {&struct {
2476+ A struct {
2477+ B, C int
2478+ }
2479+ }{struct{ B, C int }{1, 2}},
2480+ map[string]map[string]int{"a": map[string]int{"b": 1, "c": 2}}},
2481+
2482+ {&struct{ A bson.Symbol }{"abc"}, map[string]string{"a": "abc"}},
2483+ {&struct{ A bson.Symbol }{"abc"}, map[string][]byte{"a": []byte("abc")}},
2484+ {&struct{ A []byte }{[]byte("abc")}, map[string]string{"a": "abc"}},
2485+ {&struct{ A uint }{42}, map[string]int{"a": 42}},
2486+ {&struct{ A uint }{42}, map[string]float64{"a": 42}},
2487+ {&struct{ A uint }{1}, map[string]bool{"a": true}},
2488+ {&struct{ A int }{42}, map[string]uint{"a": 42}},
2489+ {&struct{ A int }{42}, map[string]float64{"a": 42}},
2490+ {&struct{ A int }{1}, map[string]bool{"a": true}},
2491+ {&struct{ A float64 }{42}, map[string]float32{"a": 42}},
2492+ {&struct{ A float64 }{42}, map[string]int{"a": 42}},
2493+ {&struct{ A float64 }{42}, map[string]uint{"a": 42}},
2494+ {&struct{ A float64 }{1}, map[string]bool{"a": true}},
2495+ {&struct{ A bool }{true}, map[string]int{"a": 1}},
2496+ {&struct{ A bool }{true}, map[string]uint{"a": 1}},
2497+ {&struct{ A bool }{true}, map[string]float64{"a": 1}},
2498+ {&struct{ A **byte }{&byteptr}, map[string]byte{"a": 8}},
2499+
2500+ // Slices
2501+ {&struct{ S []int }{[]int{1, 2, 3}}, map[string][]int{"s": []int{1, 2, 3}}},
2502+ {&struct{ S *[]int }{&[]int{1, 2, 3}}, map[string][]int{"s": []int{1, 2, 3}}},
2503+
2504+ // Conditionals
2505+ {&condBool{true}, map[string]bool{"v": true}},
2506+ {&condBool{}, map[string]bool{}},
2507+ {&condInt{1}, map[string]int{"v": 1}},
2508+ {&condInt{}, map[string]int{}},
2509+ {&condUInt{1}, map[string]uint{"v": 1}},
2510+ {&condUInt{}, map[string]uint{}},
2511+ {&condStr{"yo"}, map[string]string{"v": "yo"}},
2512+ {&condStr{}, map[string]string{}},
2513+ {&condSlice{[]string{"yo"}}, map[string][]string{"v": []string{"yo"}}},
2514+ {&condSlice{}, map[string][]string{}},
2515+ {&condMap{map[string]int{"k": 1}}, bson.M{"v": bson.M{"k": 1}}},
2516+ {&condMap{map[string]int{}}, map[string][]string{}},
2517+ {&condMap{}, map[string][]string{}},
2518+ {&condIface{"yo"}, map[string]string{"v": "yo"}},
2519+ {&condIface{""}, map[string]string{"v": ""}},
2520+ {&condIface{}, map[string]string{}},
2521+ {&condPtr{&truevar}, map[string]bool{"v": true}},
2522+ {&condPtr{&falsevar}, map[string]bool{"v": false}},
2523+ {&condPtr{}, map[string]string{}},
2524+
2525+ {&namedCondStr{"yo"}, map[string]string{"myv": "yo"}},
2526+ {&namedCondStr{}, map[string]string{}},
2527+
2528+ {&shortInt{1}, map[string]interface{}{"v": 1}},
2529+ {&shortInt{1 << 30}, map[string]interface{}{"v": 1 << 30}},
2530+ {&shortInt{1 << 31}, map[string]interface{}{"v": int64(1 << 31)}},
2531+ {&shortUint{1 << 30}, map[string]interface{}{"v": 1 << 30}},
2532+ {&shortUint{1 << 31}, map[string]interface{}{"v": int64(1 << 31)}},
2533+ {&shortIface{int64(1) << 31}, map[string]interface{}{"v": int64(1 << 31)}},
2534+ {&shortPtr{int64ptr}, map[string]interface{}{"v": intvar}},
2535+
2536+ {&slashedName{"yo"}, map[string]string{"a/b": "yo"}},
2537+}
2538+
2539+// Same thing, but only one way (obj1 => obj2).
2540+var oneWayCrossItems = []crossTypeItem{
2541+ // map <=> struct
2542+ {map[string]interface{}{"a": 1, "b": "2", "c": 3},
2543+ map[string]int{"a": 1, "c": 3}},
2544+
2545+ // Can't decode int into struct.
2546+ {bson.M{"a": bson.M{"b": 2}}, &struct{ A bool }{}},
2547+
2548+ // Would get decoded into a int32 too in the opposite direction.
2549+ {&shortIface{int64(1) << 30}, map[string]interface{}{"v": 1 << 30}},
2550+}
2551+
2552+func testCrossPair(c *C, dump interface{}, load interface{}, bug interface{}) {
2553+ //c.Logf("")
2554+ zero := makeZeroDoc(load)
2555+ data, err := bson.Marshal(dump)
2556+ c.Assert(err, IsNil, bug)
2557+ c.Logf("Data: %#v", string(data))
2558+ err = bson.Unmarshal(data, zero)
2559+ c.Assert(err, IsNil, bug)
2560+ c.Assert(zero, Equals, load, bug)
2561+}
2562+
2563+func (s *S) TestTwoWayCrossPairs(c *C) {
2564+ for i, item := range twoWayCrossItems {
2565+ testCrossPair(c, item.obj1, item.obj2, Bug("#%d obj1 => obj2", i))
2566+ testCrossPair(c, item.obj2, item.obj1, Bug("#%d obj1 <= obj2", i))
2567+ }
2568+}
2569+
2570+func (s *S) TestOneWayCrossPairs(c *C) {
2571+ for i, item := range oneWayCrossItems {
2572+ testCrossPair(c, item.obj1, item.obj2, Bug("#%d obj1 => obj2", i))
2573+ }
2574+}
2575+
2576+// --------------------------------------------------------------------------
2577+// ObjectId hex representation test.
2578+
2579+func (s *S) TestObjectIdHex(c *C) {
2580+ id := bson.ObjectIdHex("4d88e15b60f486e428412dc9")
2581+ str := "ObjectIdHex(\"4d88e15b60f486e428412dc9\")"
2582+ c.Assert(str, Equals, id.String())
2583+}
2584+
2585+// --------------------------------------------------------------------------
2586+// ObjectId parts extraction tests.
2587+
2588+type objectIdParts struct {
2589+ id bson.ObjectId
2590+ timestamp int32
2591+ machine []byte
2592+ pid uint16
2593+ counter int32
2594+}
2595+
2596+var objectIds = []objectIdParts{
2597+ objectIdParts{
2598+ bson.ObjectIdHex("4d88e15b60f486e428412dc9"),
2599+ 1300816219,
2600+ []byte{0x60, 0xf4, 0x86},
2601+ 0xe428,
2602+ 4271561,
2603+ },
2604+ objectIdParts{
2605+ bson.ObjectIdHex("000000000000000000000000"),
2606+ 0,
2607+ []byte{0x00, 0x00, 0x00},
2608+ 0x0000,
2609+ 0,
2610+ },
2611+ objectIdParts{
2612+ bson.ObjectIdHex("00000000aabbccddee000001"),
2613+ 0,
2614+ []byte{0xaa, 0xbb, 0xcc},
2615+ 0xddee,
2616+ 1,
2617+ },
2618+}
2619+
2620+func (s *S) TestObjectIdPartsExtraction(c *C) {
2621+ for i, v := range objectIds {
2622+ c.Assert(v.id.Timestamp(), Equals, v.timestamp, Bug("#%d Wrong timestamp value", i))
2623+ c.Assert(v.id.Machine(), Equals, v.machine, Bug("#%d Wrong machine id value", i))
2624+ c.Assert(v.id.Pid(), Equals, v.pid, Bug("#%d Wrong pid value", i))
2625+ c.Assert(v.id.Counter(), Equals, v.counter, Bug("#%d Wrong counter value", i))
2626+ }
2627+}
2628+
2629+func (s *S) TestNow(c *C) {
2630+ before := time.Nanoseconds()
2631+ time.Sleep(1e6)
2632+ now := bson.Now()
2633+ time.Sleep(1e6)
2634+ after := time.Nanoseconds()
2635+ c.Assert(reflect.TypeOf(now), Equals, reflect.TypeOf(bson.Timestamp(00)))
2636+ c.Assert(int64(now) > before && int64(now) < after, Equals, true, Bug("now=%d, before=%d, after=%d", now, before, after))
2637+}
2638+
2639+// --------------------------------------------------------------------------
2640+// ObjectId generation tests.
2641+
2642+func (s *S) TestNewObjectId(c *C) {
2643+ // Generate 10 ids
2644+ ids := make([]bson.ObjectId, 10)
2645+ for i := 0; i < 10; i++ {
2646+ ids[i] = bson.NewObjectId()
2647+ }
2648+ for i := 1; i < 10; i++ {
2649+ prevId := ids[i-1]
2650+ id := ids[i]
2651+ // Test for uniqueness among all other 9 generated ids
2652+ for j, tid := range ids {
2653+ if j != i {
2654+ c.Assert(id, Not(Equals), tid, Bug("Generated ObjectId is not unique"))
2655+ }
2656+ }
2657+ // Check that timestamp was incremented and is within 30 seconds of the previous one
2658+ td := id.Timestamp() - prevId.Timestamp()
2659+ c.Assert((td >= 0 && td <= 30), Equals, true, Bug("Wrong timestamp in generated ObjectId"))
2660+ // Check that machine ids are the same
2661+ c.Assert(id.Machine(), Equals, prevId.Machine())
2662+ // Check that pids are the same
2663+ c.Assert(id.Pid(), Equals, prevId.Pid())
2664+ // Test for proper increment
2665+ delta := int(id.Counter() - prevId.Counter())
2666+ c.Assert(delta, Equals, 1, Bug("Wrong increment in generated ObjectId"))
2667+ }
2668+}
2669+
2670+func (s *S) TestNewObjectIdSeconds(c *C) {
2671+ sec := int32(time.Seconds())
2672+ id := bson.NewObjectIdSeconds(sec)
2673+ c.Assert(id.Timestamp(), Equals, sec)
2674+ c.Assert(id.Machine(), Equals, []byte{0x00, 0x00, 0x00})
2675+ c.Assert(int(id.Pid()), Equals, 0)
2676+ c.Assert(int(id.Counter()), Equals, 0)
2677+}

Subscribers

People subscribed via source and target branches

to all changes: