Commits

Daniel Smith committed 5a79496

Initial commit

Comments (0)

Files changed (9)

+Copyright (c) 2000 Michael Stephens
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// Copyright (c) 2009 The Go Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+include $(GOROOT)/src/Make.inc
+
+TARG=mongo
+GOFILES=\
+	bson.go\
+	bson_struct.go\
+	mongo.go\
+
+include $(GOROOT)/src/Make.pkg
+Example usage:
+
+import "mongo"
+
+doc, _ := mongo.Marshal(map[string]string{"_id": "doc1", "title": "A Mongo document", "content": "Testing, 1. 2. 3."});
+conn, _ := mongo.Connect("127.0.0.1", 27017);
+collection := conn.GetDB("test").GetCollection("test_collection");
+collection.Insert(doc);
+
+query, _ := mongo.Marshal(map[string]string{"_id": "doc1"});
+got, _ := collection.FindOne(query);
+mongo.Equal(doc, got);  // true!
+
+collection.Drop();
+// Based on the Go json package.
+// Original Copyright 2009 The Go Authors. All rights reserved.
+// Modifications Copyright 2009 Michael Stephens.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE and LICENSE.GO files.
+
+package mongo
+
+import (
+	"os";
+	"io";
+	"io/ioutil";
+	"fmt";
+	"math";
+	"time";
+	"bytes";
+	"strconv";
+	"encoding/binary";
+	"encoding/base64"
+	"container/vector";
+)
+
+const (
+	EOOKind	= iota;
+	NumberKind;
+	StringKind;
+	ObjectKind;
+	ArrayKind;
+	BinaryKind;
+	UndefinedKind;	// deprecated
+	OIDKind;
+	BooleanKind;
+	DateKind;
+	NullKind;
+	RegexKind;
+	RefKind;	// deprecated
+	CodeKind;
+	SymbolKind;
+	CodeWithScope;
+	IntKind;
+	TimestampKind;
+	LongKind;
+	MinKeyKind;
+	MaxKeyKind;
+)
+
+type BSON interface {
+	Kind() int;
+	Number() float64;
+	String() string;
+	OID() OID;
+	Bool() bool;
+	Date() *time.Time;
+	Regex() (string, string);
+	Int() int32;
+	Long() int64;
+	Get(s string) BSON;
+	Elem(i int) BSON;
+	Len() int;
+
+	Bytes() []byte;
+	
+	//return the value as an interface {}
+	Interface() interface {}
+	
+	DebugPrint() string
+	
+	//to allow marshalling a struct and then tacking on an ID.
+	AddField(name string, value interface {}) os.Error
+}
+
+type OID []byte
+
+var oidEncoding = base64.NewEncoding("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-")
+
+func (oid OID) String() string {
+	if oid == nil {
+		return ""
+	}
+	b := [(12 + 2) / 3 * 4]byte{}[:]
+	oidEncoding.Encode(b, []byte(oid))
+	return string(b)
+}
+
+func NewOID(src string) (OID, os.Error) {
+	if src == "" {
+		return nil, nil
+	}
+	b := [12]byte{}[:]
+	n, err := oidEncoding.Decode(b, []byte(src))
+	if err != nil {
+		return nil, err
+	}
+	if n != 12 {
+		return nil, os.NewError("Incorrect number of bytes for OID")
+	}
+	return OID(b), nil
+}
+
+func (lhs OID) Less(rhs OID) bool {
+	return bytes.Compare([]byte(lhs), []byte(rhs)) < 0
+}
+
+type _Null struct{}
+
+var Null BSON = &_Null{}
+
+func (*_Null) Kind() int		{ return NullKind }
+func (*_Null) Number() float64		{ return 0 }
+func (*_Null) String() string		{ return "null" }
+func (*_Null) OID() OID		{ return nil }
+func (*_Null) Bool() bool		{ return false }
+func (*_Null) Date() *time.Time		{ return nil }
+func (*_Null) Regex() (string, string)	{ return "", "" }
+func (*_Null) Int() int32		{ return 0 }
+func (*_Null) Long() int64		{ return 0 }
+func (*_Null) Get(string) BSON		{ return Null }
+func (*_Null) Elem(int) BSON		{ return Null }
+func (*_Null) Len() int			{ return 0 }
+func (*_Null) Bytes() []byte		{ return []byte{0} }
+func (*_Null) Interface() interface {}		{ return nil }
+func (*_Null) DebugPrint() string {return "NULL"}
+func (*_Null) AddField(name string, value interface {}) os.Error {return os.NewError("Only allowed on structs")}
+
+type _Number struct {
+	value	float64;
+	_Null;
+}
+
+func (n *_Number) Kind() int		{ return NumberKind }
+func (n *_Number) Number() float64	{ return n.value }
+func (n *_Number) Bytes() []byte {
+	bits := math.Float64bits(n.value);
+	b := []byte{0, 0, 0, 0, 0, 0, 0, 0};
+	binary.LittleEndian.PutUint64(b, bits);
+	return b;
+}
+func (obj *_Number) Interface() interface {}		{ return obj.value }
+func (n *_Number) DebugPrint() string {return fmt.Sprintf("%vf", n.value)}
+
+type _String struct {
+	value	string;
+	_Null;
+}
+
+func (s *_String) Kind() int		{ return StringKind }
+func (s *_String) String() string	{ return s.value }
+func (s *_String) Bytes() []byte {
+	b := []byte{0, 0, 0, 0};
+	l := len(s.value) + 1;
+	binary.LittleEndian.PutUint32(b, uint32(l));
+
+	buf := bytes.NewBuffer(b);
+	buf.WriteString(s.value);
+	buf.WriteByte(0);
+
+	return buf.Bytes();
+}
+func (obj *_String) Interface() interface {}		{ return obj.value }
+func (s *_String) DebugPrint() string {return fmt.Sprintf(`"%s"`, s.value)}
+
+type _Object struct {
+	value	map[string]BSON;
+	_Null;
+}
+
+func (o *_Object) Kind() int	{ return ObjectKind }
+func (o *_Object) Get(s string) BSON {
+	if o.value == nil {
+		return Null
+	}
+
+	b, ok := o.value[s];
+	if !ok {
+		return Null
+	}
+
+	return b;
+}
+func (o *_Object) Len() int	{ return len(o.value) }
+func (o *_Object) Bytes() []byte {
+	buf := bytes.NewBuffer([]byte{});
+	for k, v := range o.value {
+		buf.WriteByte(byte(v.Kind()));
+		buf.WriteString(k);
+		buf.WriteByte(0);
+		buf.Write(v.Bytes());
+	}
+	buf.WriteByte(0);
+
+	l := buf.Len() + 4;
+	b := []byte{0, 0, 0, 0};
+	binary.LittleEndian.PutUint32(b, uint32(l));
+	return bytes.Add(b, buf.Bytes());
+}
+func (o *_Object) DebugPrint() (str string) {
+	str = "{"
+	comma := ""
+	for k, v := range o.value {
+		str += fmt.Sprintf(`%s"%s" : %s`, comma, k, v.DebugPrint())
+		comma = ", "
+	}
+	str += "}"
+	return
+}
+func (o *_Object) AddField(name string, value interface {}) os.Error {
+	switch v := value.(type) {
+		case string: o.value[name] = &_String{v, _Null{}}
+		case uint64: o.value[name] = &_Long{int64(v), _Null{}}
+		default: return os.NewError("Unhandled Type")
+	}
+	return nil
+}
+
+var EmptyObject BSON = &_Object{map[string]BSON{}, _Null{}}
+
+type _Array struct {
+	value	*vector.Vector;
+	_Null;
+}
+
+func (a *_Array) Kind() int	{ return ArrayKind }
+func (a *_Array) Elem(i int) BSON {
+	if a.value == nil {
+		return Null
+	}
+
+	if a.Len() < i {
+		return Null
+	}
+
+	return a.value.At(i).(BSON);
+}
+func (a *_Array) Len() int	{ return a.value.Len() }
+func (a *_Array) Bytes() []byte {
+	buf := bytes.NewBuffer([]byte{});
+
+	for i := 0; i < a.value.Len(); i++ {
+		v := a.value.At(i).(BSON);
+		buf.WriteByte(byte(v.Kind()));
+		buf.WriteString(strconv.Itoa(i));
+		buf.WriteByte(0);
+		buf.Write(v.Bytes());
+	}
+	buf.WriteByte(0);
+
+	l := buf.Len() + 4;
+	b := []byte{0, 0, 0, 0};
+	binary.LittleEndian.PutUint32(b, uint32(l));
+	return bytes.Add(b, buf.Bytes());
+}
+func (a *_Array) DebugPrint() (str string) {
+	str = "["
+	for i := 0; i < a.value.Len(); i++ {
+		str += a.value.At(i).(BSON).DebugPrint()
+		if i < a.value.Len() - 1 {
+			str += ", "
+		}
+	}
+	str += "]"
+	return
+}
+
+type _OID struct {
+	value	[]byte;
+	_Null;
+}
+
+func (o *_OID) Kind() int	{ return OIDKind }
+func (o *_OID) OID() OID	{ return OID(o.value) }
+func (o *_OID) Bytes() []byte	{ return o.value }
+func (o *_OID) Interface() interface {}		{ return OID(o.value) }
+func (o *_OID) DebugPrint() string {return fmt.Sprintf("%v", o.value)}
+
+func OIDConstruct(b BSON) OID {
+	var o OID
+	copy(o[0:12], b.(*_OID).value)
+	return o
+}
+
+type _Boolean struct {
+	value	bool;
+	_Null;
+}
+
+func (b *_Boolean) Kind() int	{ return BooleanKind }
+func (b *_Boolean) Bool() bool	{ return b.value }
+func (b *_Boolean) Bytes() []byte {
+	if b.value {
+		return []byte{1}
+	}
+	return []byte{0};
+}
+func (obj *_Boolean) Interface() interface {}		{return obj.value }
+func (b *_Boolean) DebugPrint() string {
+	if b.value {
+		return "true"
+	}
+	return "false"
+}
+
+type _Date struct {
+	value	*time.Time;
+	_Null;
+}
+
+func (d *_Date) Kind() int		{ return DateKind }
+func (d *_Date) Date() *time.Time	{ return d.value }
+func (d *_Date) Bytes() []byte {
+	b := []byte{0, 0, 0, 0, 0, 0, 0, 0};
+	seconds := int64(0)
+	if d.value != nil {
+		seconds = d.value.Seconds()
+	}
+	mtime := seconds * 1000;
+	binary.LittleEndian.PutUint64(b, uint64(mtime));
+	return b;
+}
+func (obj *_Date) Interface() interface {}		{ return obj.value }
+func (d *_Date) DebugPrint() string {return fmt.Sprintf("%s", d.value)}
+
+type _Regex struct {
+	regex, options	string;
+	_Null;
+}
+
+func (r *_Regex) Kind() int			{ return RegexKind }
+func (r *_Regex) Regex() (string, string)	{ return r.regex, r.options }
+func (r *_Regex) Bytes() []byte {
+	buf := bytes.NewBufferString(r.regex);
+	buf.WriteByte(0);
+	buf.WriteString(r.options);
+	buf.WriteByte(0);
+	return buf.Bytes();
+}
+func (r *_Regex) DebugPrint() string {return "Regex(" + r.regex + "," + r.options + ")"}
+
+type _Int struct {
+	value	int32;
+	_Null;
+}
+
+func (i *_Int) Kind() int	{ return IntKind }
+func (i *_Int) Int() int32	{ return i.value }
+func (i *_Int) Bytes() []byte {
+	b := []byte{0, 0, 0, 0};
+	binary.LittleEndian.PutUint32(b, uint32(i.value));
+	return b;
+}
+func (obj *_Int) Interface() interface {}		{ return obj.value }
+func (i *_Int) DebugPrint() string {return fmt.Sprintf("%vi", i.value)}
+
+type _Long struct {
+	value	int64;
+	_Null;
+}
+
+func (l *_Long) Kind() int	{ return LongKind }
+func (l *_Long) Long() int64	{ return l.value }
+func (l *_Long) Bytes() []byte {
+	b := []byte{0, 0, 0, 0, 0, 0, 0, 0};
+	binary.LittleEndian.PutUint64(b, uint64(l.value));
+	return b;
+}
+func (obj *_Long) Interface() interface {}		{ return obj.value }
+func (l *_Long) DebugPrint() string {return fmt.Sprintf("%vl", l.value)}
+
+func Equal(a, b BSON) bool {
+	switch {
+	case a == nil && b == nil:
+		return true
+	case a == nil || b == nil:
+		return false
+	case a.Kind() != b.Kind():
+		return false
+	}
+
+	switch a.Kind() {
+	case NumberKind:
+		return a.Number() == b.Number()
+	case StringKind:
+		return a.String() == b.String()
+	case ObjectKind:
+		obj := a.(*_Object).value;
+		if len(obj) != len(b.(*_Object).value) {
+			return false
+		}
+		for k, v := range obj {
+			if !Equal(v, b.Get(k)) {
+				return false
+			}
+		}
+		return true;
+	case ArrayKind:
+		if a.Len() != b.Len() {
+			return false
+		}
+		for i := 0; i < a.Len(); i++ {
+			if !Equal(a.Elem(i), b.Elem(i)) {
+				return false
+			}
+		}
+		return true;
+	case OIDKind:
+		return bytes.Equal([]byte(a.OID()), []byte(b.OID()))
+	case BooleanKind:
+		return a.Bool() == b.Bool()
+	case DateKind:
+		return a.Date() == b.Date()
+	case RegexKind:
+		ar, ao := a.Regex();
+		br, bo := b.Regex();
+		return ar == br && ao == bo;
+	case IntKind:
+		return a.Int() == b.Int()
+	case LongKind:
+		return a.Long() == b.Long()
+	}
+	return true;
+
+}
+
+type Builder interface {
+	// Set value
+	Int64(i int64);
+	Int32(i int32);
+	Float64(f float64);
+	String(s string);
+	Bool(b bool);
+	Date(d *time.Time);
+	OID(o []byte);
+	Regex(regex, options string);
+	Null();
+	Object();
+	Array();
+
+	// Create sub-Builders
+	Key(s string) Builder;
+	Elem(i int) Builder;
+
+	// Flush changes to parent Builder if necessary.
+	Flush();
+}
+
+type _BSONBuilder struct {
+	ptr	*BSON;
+
+	arr	*vector.Vector;
+	elem	int;
+
+	obj	map[string]BSON;
+	key	string;
+}
+
+func (bb *_BSONBuilder) Put(b BSON) {
+	switch {
+	case bb.ptr != nil:
+		*bb.ptr = b
+	case bb.arr != nil:
+		bb.arr.Set(bb.elem, b)
+	case bb.obj != nil:
+		bb.obj[bb.key] = b
+	}
+}
+
+func (bb *_BSONBuilder) Get() BSON {
+	switch {
+	case bb.ptr != nil:
+		return *bb.ptr
+	case bb.arr != nil:
+		return bb.arr.At(bb.elem).(BSON)
+	case bb.obj != nil:
+		return bb.obj[bb.key]
+	}
+	return nil;
+}
+
+func (bb *_BSONBuilder) Float64(f float64)	{ bb.Put(&_Number{f, _Null{}}) }
+func (bb *_BSONBuilder) String(s string)	{ bb.Put(&_String{s, _Null{}}) }
+func (bb *_BSONBuilder) Object()		{ bb.Put(&_Object{make(map[string]BSON), _Null{}}) }
+func (bb *_BSONBuilder) Array()			{ bb.Put(&_Array{new(vector.Vector), _Null{}}) }
+func (bb *_BSONBuilder) Bool(b bool)		{ bb.Put(&_Boolean{b, _Null{}}) }
+func (bb *_BSONBuilder) Date(t *time.Time) {
+	if t == nil {
+		t = &time.Time{}
+	}
+	bb.Put(&_Date{t, _Null{}})
+}
+func (bb *_BSONBuilder) Null()			{ bb.Put(Null) }
+func (bb *_BSONBuilder) Regex(regex, options string) {
+	bb.Put(&_Regex{regex, options, _Null{}})
+}
+func (bb *_BSONBuilder) Int32(i int32)	{ bb.Put(&_Int{i, _Null{}}) }
+func (bb *_BSONBuilder) Int64(i int64)	{ bb.Put(&_Long{i, _Null{}}) }
+func (bb *_BSONBuilder) OID(o []byte)	{ bb.Put(&_OID{o, _Null{}}) }
+
+func (bb *_BSONBuilder) Key(key string) Builder {
+	bb2 := new(_BSONBuilder);
+
+	switch obj := bb.Get().(type) {
+	case *_Object:
+		bb2.obj = obj.value;
+		bb2.key = key;
+		bb2.obj[key] = Null;
+	case *_Array:
+		bb2.arr = obj.value;
+		elem, _ := strconv.Atoi(key);
+		bb2.elem = elem;
+		for elem >= bb2.arr.Len() {
+			bb2.arr.Push(Null)
+		}
+	}
+	return bb2;
+}
+
+func (bb *_BSONBuilder) Elem(i int) Builder {
+	bb2 := new(_BSONBuilder);
+	bb2.arr = bb.Get().(*_Array).value;
+	bb2.elem = i;
+	for i >= bb2.arr.Len() {
+		bb2.arr.Push(Null)
+	}
+	return bb2;
+}
+
+func (bb *_BSONBuilder) Flush()	{}
+
+func BytesToBSON(b []byte) (BSON, os.Error) {
+	var bson BSON;
+	bb := new(_BSONBuilder);
+	bb.ptr = &bson;
+	bb.Object();
+	err := Parse(bytes.NewBuffer(b[4:len(b)]), bb);
+	return bson, err;
+}
+
+func readCString(buf *bytes.Buffer) string {
+	out := bytes.NewBuffer([]byte{});
+	var c byte;
+	for c, _ = buf.ReadByte(); c != 0; c, _ = buf.ReadByte() {
+		out.WriteByte(c)
+	}
+
+	return out.String();
+}
+
+func Parse(buf *bytes.Buffer, builder Builder) (err os.Error) {
+	kind, _ := buf.ReadByte();
+	err = nil;
+
+	for kind != EOOKind {
+		name := readCString(buf);
+		b2 := builder.Key(name);
+
+		switch kind {
+		case NumberKind:
+			lr := io.LimitReader(buf, 8);
+			bits, _ := ioutil.ReadAll(lr);
+			ui64 := binary.LittleEndian.Uint64(bits);
+			fl64 := math.Float64frombits(ui64);
+			b2.Float64(fl64);
+		case StringKind:
+			bits, _ := ioutil.ReadAll(io.LimitReader(buf, 4));
+			l := binary.LittleEndian.Uint32(bits);
+			s, _ := ioutil.ReadAll(io.LimitReader(buf, int64(l-1)));
+			buf.ReadByte();
+			b2.String(string(s));
+		case ObjectKind:
+			b2.Object();
+			ioutil.ReadAll(io.LimitReader(buf, 4));
+			err = Parse(buf, b2);
+		case ArrayKind:
+			b2.Array();
+			ioutil.ReadAll(io.LimitReader(buf, 4));
+			err = Parse(buf, b2);
+		case OIDKind:
+			oid, _ := ioutil.ReadAll(io.LimitReader(buf, 12));
+			b2.OID(oid);
+		case BooleanKind:
+			b, _ := buf.ReadByte();
+			if b == 1 {
+				b2.Bool(true)
+			} else {
+				b2.Bool(false)
+			}
+		case DateKind:
+			bits, _ := ioutil.ReadAll(io.LimitReader(buf, 8));
+			ui64 := binary.LittleEndian.Uint64(bits);
+			b2.Date(time.SecondsToUTC(int64(ui64) / 1000));
+		case RegexKind:
+			regex := readCString(buf);
+			options := readCString(buf);
+			b2.Regex(regex, options);
+		case IntKind:
+			bits, _ := ioutil.ReadAll(io.LimitReader(buf, 4));
+			ui32 := binary.LittleEndian.Uint32(bits);
+			b2.Int32(int32(ui32));
+		case LongKind:
+			bits, _ := ioutil.ReadAll(io.LimitReader(buf, 8));
+			ui64 := binary.LittleEndian.Uint64(bits);
+			b2.Int64(int64(ui64));
+		default:
+			err = os.NewError(fmt.Sprintf("don't know how to handle kind %v yet", kind))
+		}
+
+		kind, _ = buf.ReadByte();
+	}
+	
+	if b, ok := builder.(*structBuilder); b != nil && ok {
+		if b.map_ != nil {
+			b.map_.SetElem(b.key, b.val)
+		}
+	}
+
+	return;
+}
+// Based on the Go json package.
+// Original Copyright 2009 The Go Authors. All rights reserved.
+// Modifications Copyright 2009 Michael Stephens.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE and LICENSE.GO files.
+
+package mongo
+
+import (
+	"reflect";
+	//"strings";
+	"fmt";
+	"os";
+	"bytes";
+	"time";
+	"container/vector";
+	"strconv"
+)
+
+type structBuilder struct {
+	val	reflect.Value;
+
+	// if map_ != nil, write val to map_[key] on each change
+	map_	*reflect.MapValue;
+	key	reflect.Value;
+}
+
+var nobuilder *structBuilder
+
+func isfloat(v reflect.Value) bool {
+	switch v.(type) {
+	case *reflect.FloatValue:
+		return true
+	}
+	return false;
+}
+
+func setfloat(v reflect.Value, f float64) {
+	switch v := v.(type) {
+	case *reflect.FloatValue:
+		v.Set(f)
+	}
+}
+
+func setint(v reflect.Value, i int64) {
+	switch v := v.(type) {
+	case *reflect.IntValue:
+		v.Set(i)
+	case *reflect.UintValue:
+		v.Set(uint64(i))
+	}
+}
+
+// If updating b.val is not enough to update the original,
+// copy a changed b.val out to the original.
+func (b *structBuilder) Flush() {
+	if b == nil {
+		return
+	}
+	if b.map_ != nil {
+		b.map_.SetElem(b.key, b.val)
+	}
+}
+
+func (b *structBuilder) Int64(i int64) {
+	if b == nil {
+		return
+	}
+	v := b.val;
+	if isfloat(v) {
+		setfloat(v, float64(i))
+	} else {
+		setint(v, i)
+	}
+}
+
+func (b *structBuilder) Date(t *time.Time) {
+	if b == nil {
+		return
+	}
+	if v, ok := b.val.(*reflect.PtrValue); ok {
+		v.PointTo(reflect.Indirect(reflect.NewValue(t)))
+	}
+}
+
+func (b *structBuilder) Int32(i int32) {
+	if b == nil {
+		return
+	}
+	v := b.val;
+	if isfloat(v) {
+		setfloat(v, float64(i))
+	} else {
+		setint(v, int64(i))
+	}
+}
+
+func (b *structBuilder) Float64(f float64) {
+	if b == nil {
+		return
+	}
+	v := b.val;
+	if isfloat(v) {
+		setfloat(v, f)
+	} else {
+		setint(v, int64(f))
+	}
+}
+
+func (b *structBuilder) Null()	{}
+
+func (b *structBuilder) String(s string) {
+	if b == nil {
+		return
+	}
+	if v, ok := b.val.(*reflect.StringValue); ok {
+		v.Set(s)
+	}
+}
+
+func (b *structBuilder) Regex(regex, options string) {
+	// Ignore options for now...
+	if b == nil {
+		return
+	}
+	if v, ok := b.val.(*reflect.StringValue); ok {
+		v.Set(regex)
+	}
+}
+
+func (b *structBuilder) Bool(tf bool) {
+	if b == nil {
+		return
+	}
+	if v, ok := b.val.(*reflect.BoolValue); ok {
+		v.Set(tf)
+	}
+}
+
+func (b *structBuilder) OID(oid []byte) {
+	if b == nil {
+		return
+	}
+	if v, ok := b.val.(*reflect.SliceValue); ok {
+		if v.Cap() < 12 {
+			nv := reflect.MakeSlice(v.Type().(*reflect.SliceType), 12, 12);
+			v.Set(nv);
+		}
+		for i := 0; i < 12; i++ {
+			v.Elem(i).(*reflect.UintValue).Set(uint64(oid[i]))
+		}
+	}
+}
+
+func (b *structBuilder) Array() {
+	if b == nil {
+		return
+	}
+	if v, ok := b.val.(*reflect.SliceValue); ok {
+		if v.IsNil() {
+			v.Set(reflect.MakeSlice(v.Type().(*reflect.SliceType), 0, 8))
+		}
+	}
+}
+
+func (b *structBuilder) Elem(i int) Builder {
+	if b == nil || i < 0 {
+		return nobuilder
+	}
+	switch v := b.val.(type) {
+	case *reflect.ArrayValue:
+		if i < v.Len() {
+			return &structBuilder{val: v.Elem(i)}
+		}
+	case *reflect.SliceValue:
+		if i > v.Cap() {
+			n := v.Cap();
+			if n < 8 {
+				n = 8
+			}
+			for n <= i {
+				n *= 2
+			}
+			nv := reflect.MakeSlice(v.Type().(*reflect.SliceType), v.Len(), n);
+			reflect.ArrayCopy(nv, v);
+			v.Set(nv);
+		}
+		if v.Len() <= i && i < v.Cap() {
+			v.SetLen(i + 1)
+		}
+		if i < v.Len() {
+			return &structBuilder{val: v.Elem(i)}
+		}
+	}
+	return nobuilder;
+}
+
+func (b *structBuilder) Object() {
+	if b == nil {
+		return
+	}
+	if v, ok := b.val.(*reflect.PtrValue); ok && v.IsNil() {
+		if v.IsNil() {
+			v.PointTo(reflect.MakeZero(v.Type().(*reflect.PtrType).Elem()));
+			b.Flush();
+		}
+		b.map_ = nil;
+		b.val = v.Elem();
+	}
+	if v, ok := b.val.(*reflect.MapValue); ok && v.IsNil() {
+		v.Set(reflect.MakeMap(v.Type().(*reflect.MapType)))
+	}
+}
+
+func (b *structBuilder) Key(k string) Builder {
+	if b == nil {
+		return nobuilder
+	}
+	switch v := reflect.Indirect(b.val).(type) {
+	case *reflect.StructValue:
+		t := v.Type().(*reflect.StructType);
+		// Case-insensitive field lookup.
+		//k = strings.ToLower(k);
+		for i := 0; i < t.NumField(); i++ {
+			//if strings.ToLower(t.Field(i).Name) == k {
+			if t.Field(i).Name == k {
+				return &structBuilder{val: v.Field(i)}
+			}
+		}
+	case *reflect.MapValue:
+		t := v.Type().(*reflect.MapType);
+		if t.Key() != reflect.Typeof(k) {
+			break
+		}
+		key := reflect.NewValue(k);
+		elem := v.Elem(key);
+		if elem == nil {
+			v.SetElem(key, reflect.MakeZero(t.Elem()));
+			elem = v.Elem(key);
+		}
+		return &structBuilder{val: elem, map_: v, key: key};
+	case *reflect.SliceValue:
+		index, err := strconv.Atoi(k)
+		if err != nil {
+			return nobuilder
+		}
+		if index < v.Len() {
+			return &structBuilder{val: v.Elem(index)}
+		}
+		if index < v.Cap() {
+			v.SetLen(index + 1)
+			return &structBuilder{val: v.Elem(index)}
+		}
+		newCap := v.Cap() * 2
+		if index >= newCap {
+			newCap = index * 2 + 1
+		}
+		temp := reflect.MakeSlice(v.Type().(*reflect.SliceType), index + 1, newCap)
+		reflect.ArrayCopy(temp, v)
+		v.Set(temp)
+		return &structBuilder{val: v.Elem(index)}
+	}
+	
+	return nobuilder;
+}
+
+func Unmarshal(b []byte, val interface{}) (err os.Error) {
+	sb := &structBuilder{val: reflect.NewValue(val)};
+	err = Parse(bytes.NewBuffer(b[4:len(b)]), sb);
+	return;
+}
+
+func Marshal(val interface{}) (BSON, os.Error) {
+	if val == nil {
+		return Null, nil
+	}
+
+	switch v := val.(type) {
+	case float64:
+		return &_Number{v, _Null{}}, nil
+	case float:
+		return &_Number{float64(v), _Null{}}, nil
+	case float32:
+		return &_Number{float64(v), _Null{}}, nil
+	case string:
+		return &_String{v, _Null{}}, nil
+	case bool:
+		return &_Boolean{v, _Null{}}, nil
+	case int32:
+		return &_Int{v, _Null{}}, nil
+	case int64:
+		return &_Long{v, _Null{}}, nil
+	case uint64:
+		return &_Long{int64(v), _Null{}}, nil
+	case int:
+		return &_Long{int64(v), _Null{}}, nil
+	case byte:
+		return &_Int{int32(v), _Null{}}, nil
+	case *time.Time:
+		return &_Date{v, _Null{}}, nil
+	case OID:
+		return &_OID{[]byte(v), _Null{}}, nil
+	/*default:
+		x := reflect.NewValue(val)
+		fmt.Printf("don't know how to marshal %v\n", x.Type())*/
+	}
+
+	var value reflect.Value;
+	switch nv := reflect.NewValue(val).(type) {
+	case *reflect.PtrValue:
+		value = nv.Elem()
+	default:
+		value = nv
+	}
+
+	switch fv := value.(type) {
+	case *reflect.StructValue:
+		o := &_Object{map[string]BSON{}, _Null{}};
+		t := fv.Type().(*reflect.StructType);
+		for i := 0; i < t.NumField(); i++ {
+			if t.Field(i).Tag == "nomarshal" {
+				continue
+			}
+			//key := strings.ToLower(t.Field(i).Name);
+			key := t.Field(i).Name;
+			el, err := Marshal(fv.Field(i).Interface());
+			if err != nil {
+				return nil, err
+			}
+			o.value[key] = el;
+		}
+		return o, nil;
+	case *reflect.MapValue:
+		o := &_Object{map[string]BSON{}, _Null{}};
+		mt := fv.Type().(*reflect.MapType);
+		if mt.Key() != reflect.Typeof("") {
+			return nil, os.NewError("can't marshall maps with non-string key types")
+		}
+
+		keys := fv.Keys();
+		for _, k := range keys {
+			sk := k.(*reflect.StringValue).Get();
+			el, err := Marshal(fv.Elem(k).Interface());
+			if err != nil {
+				return nil, err
+			}
+			o.value[sk] = el;
+		}
+		return o, nil;
+	case *reflect.SliceValue:
+		a := &_Array{new(vector.Vector), _Null{}};
+		for i := 0; i < fv.Len(); i++ {
+			el, err := Marshal(fv.Elem(i).Interface());
+			if err != nil {
+				return nil, err
+			}
+			a.value.Push(el);
+		}
+		return a, nil;
+	default:
+		return nil, os.NewError(fmt.Sprintf("don't know how to marshal %v\n", value.Type()))
+	}
+
+	return nil, nil;
+}
+// Copyright 2009 Michael Stephens.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mongo_test
+
+import (
+	"testing";
+	"mongo";
+	"fmt";
+	"time";
+	"bytes"
+)
+
+func assertTrue(tf bool, msg string, t *testing.T) {
+	if !tf {
+		t.Error(msg)
+	}
+}
+
+type EmptyStruct struct{}
+
+type OtherStruct struct {
+	F, V string;
+}
+
+type ExampleStruct struct {
+	First	int32;
+	Second	float64;
+	Third	string;
+	Fourth	EmptyStruct;
+	Fifth	OtherStruct;
+}
+
+func TestMarshalArrayInMap(t *testing.T) {
+	as := map[string][]byte{"1": []byte{1, 2, 3, 4, 5, 6}, "2": []byte{7, 8, 9, 10, 11, 12}}
+	b1, _ := mongo.Marshal(as)
+	
+	var as2 = map[string][]byte{}
+	mongo.Unmarshal(b1.Bytes(), &as2)
+	
+	b2, _ := mongo.Marshal(as2)
+	fmt.Print(as, as2)
+	
+	assertTrue(mongo.Equal(b1, b2), "map array field unmarshal->marshal", t);
+}
+
+//var b []byte = []byte{92, 0, 0, 0, 1, 115, 101, 99, 111, 110, 100, 0, 0, 0, 0, 0, 0, 0, 0, 64, 3, 102, 105, 102, 116, 104, 0, 23, 0, 0, 0, 2, 118, 0, 2, 0, 0, 0, 101, 0, 2, 102, 0, 2, 0, 0, 0, 105, 0, 0, 3, 102, 111, 117, 114, 116, 104, 0, 5, 0, 0, 0, 0, 2, 116, 104, 105, 114, 100, 0, 6, 0, 0, 0, 116, 104, 114, 101, 101, 0, 16, 102, 105, 114, 115, 116, 0, 1, 0, 0, 0, 0}
+
+var b []byte = []byte{92, 0, 0, 0, 16, 70, 105, 114, 115, 116, 0, 1, 0, 0, 0, 3, 70, 105, 102, 116, 104, 0, 23, 0, 0, 0, 2, 70, 0, 2, 0, 0, 0, 105, 0, 2, 86, 0, 2, 0, 0, 0, 101, 0, 0, 1, 83, 101, 99, 111, 110, 100, 0, 0, 0, 0, 0, 0, 0, 0, 6, 4, 2, 84, 104, 105, 114, 100, 0, 6, 0, 0, 0, 116, 104, 114, 101, 101, 0, 3, 70, 111, 117, 114, 116, 104, 0, 5, 0, 0, 0, 0, 0}
+
+func TestSerializeAndDeserialize(t *testing.T) {
+	obj, err := mongo.BytesToBSON(b);
+	assertTrue(err == nil, fmt.Sprintf("failed parsing %v", b), t);
+	obj2, _ := mongo.BytesToBSON(obj.Bytes());
+	assertTrue(mongo.Equal(obj, obj2), fmt.Sprintf("obj != obj2 for %v", b), t);
+
+	fmt.Println(obj.Get("First").Int())
+	fmt.Println(obj.Get("Second").Number())
+	fmt.Println(obj.Get("Third").String())
+	fmt.Println(obj.Get("Fifth").Get("F").String())
+	fmt.Println(obj.Get("Fifth").Get("V").String())
+	fmt.Print(obj)
+	
+	assertTrue(obj.Get("First").Int() == 1, "obj['First'] != 1", t);
+	assertTrue(obj.Get("Second").Number() == 2, "obj['Second'] != 2.0", t);
+	assertTrue(obj.Get("Third").String() == "three", "obj['Third'] != 'three'", t);
+	assertTrue(obj.Get("Fifth").Get("F").String() == "i", "obj['Fifth']['F'] != 'i'", t);
+	assertTrue(obj.Get("Fifth").Get("V").String() == "e", "obj['Fifth']['V'] != 'e'", t);
+}
+
+func TestUnmarshal(t *testing.T) {
+	var es ExampleStruct;
+	mongo.Unmarshal(b, &es)
+	fmt.Println(es)
+	assertTrue(es.First == 1, "unmarshal int", t);
+	assertTrue(es.Second == 2, "unmarshal float64", t);
+	assertTrue(es.Third == "three", "unmarshal string", t);
+	assertTrue(es.Fifth.F == "i" && es.Fifth.V == "e", "unmarshal struct", t);
+}
+
+type ExampleStruct2 struct {
+	Date *time.Time;
+}
+
+func TestMarshal(t *testing.T) {
+	var es1 ExampleStruct;
+	mongo.Unmarshal(b, &es1);
+	bs1, _ := mongo.Marshal(&es1);
+	bs2, _ := mongo.BytesToBSON(b);
+	fmt.Println(bs1.Bytes())
+	fmt.Println(bs2.Bytes())
+	assertTrue(mongo.Equal(bs1, bs2), "unmarshal->marshal", t);
+
+	m := map[string]string{"f": "i", "v": "e"};
+	bs3, _ := mongo.Marshal(&m);
+	assertTrue(mongo.Equal(bs3, bs2.Get("Fifth")), "marshal map", t);
+
+	arr, _ := mongo.Marshal([]int{1, 2, 3});
+	assertTrue(arr.Elem(0).Long() == 1, "array marshal (0)", t);
+	assertTrue(arr.Elem(1).Long() == 2, "array marshal (1)", t);
+	assertTrue(arr.Elem(2).Long() == 3, "array marshal (2)", t);
+
+	d := time.UTC();
+	es2 := &ExampleStruct2{d};
+	bs2, err := mongo.Marshal(es2);
+	if err != nil {fmt.Println(err)}
+	t2 := bs2.Get("Date").Date()
+	assertTrue(t2 != nil && t2.Seconds() == d.Seconds(), "date marshal", t);
+	es2 = new(ExampleStruct2);
+	mongo.Unmarshal(bs2.Bytes(), es2);
+	assertTrue(es2.Date.Seconds() == d.Seconds(), "date unmarshal", t);
+}
+
+type ArrayStruct struct {
+	Str string
+	Ary []int
+}
+
+
+func TestMarshalArray(t *testing.T) {
+	as := ArrayStruct{"a string", []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}}
+	b1, _ := mongo.Marshal(as)
+	
+	var as2 ArrayStruct
+	mongo.Unmarshal(b1.Bytes(), &as2)
+	
+	b2, _ := mongo.Marshal(as2)
+	
+	assertTrue(mongo.Equal(b1, b2), "array field unmarshal->marshal", t);
+}
+
+func TestOID(t *testing.T) {
+	b := []byte{1,2,3,4,5,6,7,8,9,10,11,12}
+	oid := mongo.OID(b)
+	str := oid.String()
+	oid2, err := mongo.NewOID(str)
+	
+	assertTrue(err == nil, fmt.Sprintf("conversion error %s", err), t)
+	assertTrue(bytes.Equal(b, []byte(oid2)), fmt.Sprintf("oid->string-oid didn't work. %v:%s", b, []byte(oid2)), t)
+}
+
+// Copyright 2009 Michael Stephens.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mongo
+
+import (
+	"os";
+	"io";
+	"io/ioutil";
+	"net";
+	"fmt";
+	"rand";
+	"bytes";
+	"encoding/binary";
+	"container/vector";
+	"runtime"
+)
+
+var last_req int32
+
+const (
+	_OP_REPLY		= 1;
+	_OP_MSG			= 1000;
+	_OP_UPDATE		= 2001;
+	_OP_INSERT		= 2002;
+	_OP_GET_BY_OID		= 2003;
+	_OP_QUERY		= 2004;
+	_OP_GET_MORE		= 2005;
+	_OP_DELETE		= 2006;
+	_OP_KILL_CURSORS	= 2007;
+)
+
+type message interface {
+	Bytes() []byte;
+	RequestID() int32;
+	OpCode() int32;
+}
+
+type connRequest struct {
+	toWrite message
+	readReply bool
+	response chan<- connResponse
+}
+type connResponse struct {
+	reply *replyMsg
+	err os.Error
+}
+
+type Connection struct {
+	host	string;
+	port	int;
+	conn	*net.TCPConn;
+	quit	chan bool
+	reqChan chan connRequest
+}
+
+func (conn *Connection) dispatch() {
+	done := false
+	for !done {
+		func () {
+			defer func () {
+				if x := recover(); x != nil {
+					fmt.Println("mongo thread crash:", x)
+					i := 0
+					for {
+						pc, file, line, ok := runtime.Caller(i)
+						if !ok {
+							break
+						}
+						fmt.Printf("%16.16x: %s(%d)\n", pc, file, line)
+						i++
+					}
+				}
+			}()
+			for {
+				select {
+					case req := <- conn.reqChan:
+						err := conn._writeMessage(req.toWrite)
+						if err != nil {
+							req.response <- connResponse{nil, err}
+							continue
+						}
+						if req.readReply {
+							rep, err := conn._readReply()
+							if err != nil {
+								req.response <- connResponse{nil, err}
+								continue
+							}
+							if rep.responseTo != req.toWrite.RequestID() {
+								req.response <- connResponse{nil, os.NewError("wrong responseTo code")}
+								continue
+							}
+							req.response <- connResponse{rep, err}
+							continue
+						}
+						req.response <- connResponse{nil, nil}
+					case <- conn.quit:
+						done = true
+						return
+				}
+			}
+		}()
+	}
+}
+
+func (conn *Connection) send(msg message) os.Error {
+	wait := make(chan connResponse)
+	conn.reqChan <- connRequest{msg, false, wait}
+	response := <- wait
+	return response.err
+}
+
+func (conn *Connection) request(msg message) (*replyMsg, os.Error) {
+	wait := make(chan connResponse)
+	conn.reqChan <- connRequest{msg, true, wait}
+	response := <- wait
+	return response.reply, response.err
+}
+
+func Connect(host string, port int) (*Connection, os.Error) {
+	laddr, _ := net.ResolveTCPAddr("localhost");
+	addr, _ := net.ResolveTCPAddr(fmt.Sprintf("%s:%d", host, port));
+	conn, err := net.DialTCP("tcp", laddr, addr);
+
+	if err != nil {
+		return nil, err
+	}
+
+	c := &Connection{host, port, conn, make(chan bool), make(chan connRequest)};
+	go c.dispatch()
+	return c, nil
+}
+
+func (conn *Connection) Close() {
+	conn.quit <- false
+	conn.conn.Close()
+}
+
+func header(length, reqID, respTo, opCode int32) []byte {
+	b := make([]byte, 16);
+	binary.LittleEndian.PutUint32(b[0:4], uint32(length));
+	binary.LittleEndian.PutUint32(b[4:8], uint32(reqID));
+	binary.LittleEndian.PutUint32(b[8:12], uint32(respTo));
+	binary.LittleEndian.PutUint32(b[12:16], uint32(opCode));
+	return b;
+}
+
+func (c *Connection) _writeMessage(m message) (err os.Error) {
+	defer func () {
+		if x := recover(); x != nil {
+			err = os.NewError(fmt.Sprintf("%v", x))
+		}
+	}()
+	
+	body := m.Bytes();
+	hb := header(int32(len(body)+16), m.RequestID(), 0, m.OpCode());
+	msg := bytes.Add(hb, body);
+
+	_, err = c.conn.Write(msg);
+
+	last_req = m.RequestID();
+	return err;
+}
+
+func (c *Connection) _readReply() (reply *replyMsg, err os.Error) {
+	defer func () {
+		if x := recover(); x != nil {
+			err = os.NewError(fmt.Sprintf("%v", x))
+		}
+	}()
+	
+	size_bits, _ := ioutil.ReadAll(io.LimitReader(c.conn, 4));
+	size := binary.LittleEndian.Uint32(size_bits);
+	rest, _ := ioutil.ReadAll(io.LimitReader(c.conn, int64(size)-4));
+	reply = parseReply(rest);
+	return reply, nil;
+}
+
+type Database struct {
+	conn	*Connection;
+	name	string;
+}
+
+func (c *Connection) GetDB(name string) *Database {
+	return &Database{c, name}
+}
+
+func (db *Database) Drop() os.Error {
+	cmd, err := Marshal(map[string]int{"dropDatabase": 1});
+	if err != nil {
+		return err
+	}
+
+	_, err = db.Command(cmd);
+	return err;
+}
+
+func (db *Database) Repair(preserveClonedFilesOnFailure, backupOriginalFiles bool) os.Error {
+	cmd := &_Object{map[string]BSON{"repairDatabase": &_Number{1, _Null{}}, "preserveClonedFilesOnFailure": &_Boolean{preserveClonedFilesOnFailure, _Null{}}, "backupOriginalFiles": &_Boolean{backupOriginalFiles, _Null{}}}, _Null{}};
+	_, err := db.Command(cmd);
+	return err;
+}
+
+type Collection struct {
+	db	*Database;
+	name	string;
+}
+
+func (db *Database) GetCollection(name string) *Collection {
+	return &Collection{db, name}
+}
+
+type Cursor struct {
+	collection	*Collection;
+	id		int64;
+	pos		int;
+	NumberReturned int
+	docs		*vector.Vector;
+}
+
+func (c *Cursor) HasMore() bool {
+	if c.pos < c.docs.Len() {
+		return true
+	}
+
+	err := c.GetMore();
+	if err != nil {
+		return false
+	}
+
+	return c.pos < c.docs.Len();
+}
+
+func (c *Cursor) GetNext() (BSON, os.Error) {
+	if c.HasMore() {
+		doc := c.docs.At(c.pos).(BSON);
+		c.pos = c.pos + 1;
+		return doc, nil;
+	}
+	return nil, os.NewError("cursor failure");
+}
+
+func (c *Cursor) GetMore() os.Error {
+	if c.id == 0 {
+		return os.NewError("no cursorID")
+	}
+
+	gm := &getMoreMsg{c.collection.fullName(), 0, c.id, rand.Int31()};
+	conn := c.collection.db.conn;
+	
+	reply, err := conn.request(gm)
+	if err != nil {
+		return err
+	}
+
+	c.pos = 0;
+	c.docs = reply.docs;
+
+	return nil;
+}
+
+func (c *Cursor) Close() os.Error {
+	if c.id == 0 {
+		// not open on server
+		return nil
+	}
+
+	req_id := rand.Int31();
+	km := &killMsg{1, []int64{c.id}, req_id};
+	conn := c.collection.db.conn;
+	return conn.send(km);
+}
+
+func (c *Collection) fullName() string	{ return c.db.name + "." + c.name }
+
+type indexDesc struct {
+	Name	string;
+	Ns	string;
+	Key	map[string]int;
+}
+
+func (c *Collection) EnsureIndex(name string, index map[string]int) os.Error {
+	coll := c.db.GetCollection("system.indexes");
+	id := &indexDesc{name, c.fullName(), index};
+	desc, err := Marshal(id);
+	if err != nil {
+		return err
+	}
+	return coll.Insert(desc);
+}
+
+func (c *Collection) DropIndexes() os.Error	{ return c.DropIndex("*") }
+
+func (c *Collection) DropIndex(name string) os.Error {
+	cmdm := map[string]string{"deleteIndexes": c.fullName(), "index": name};
+	cmd, err := Marshal(cmdm);
+	if err != nil {
+		return err
+	}
+
+	_, err = c.db.Command(cmd);
+	return err;
+}
+
+func (c *Collection) Drop() os.Error {
+	cmdm := map[string]string{"drop": c.name};
+	cmd, err := Marshal(cmdm);
+	if err != nil {
+		return err
+	}
+
+	_, err = c.db.Command(cmd);
+	return err;
+}
+
+func (c *Collection) Insert(doc BSON) os.Error {
+	im := &insertMsg{c.fullName(), doc, rand.Int31()};
+	return c.db.conn.send(im);
+}
+
+func (c *Collection) Remove(selector BSON) os.Error {
+	dm := &deleteMsg{c.fullName(), selector, rand.Int31()};
+	return c.db.conn.send(dm);
+}
+
+func (coll *Collection) Query(query BSON, skip, limit int) (*Cursor, os.Error) {
+	req_id := rand.Int31();
+	conn := coll.db.conn;
+	qm := &queryMsg{0, coll.fullName(), int32(skip), int32(limit), query, req_id};
+
+	reply, err := conn.request(qm)
+	if err != nil {
+		return nil, err
+	}
+
+	return &Cursor{coll, reply.cursorID, 0, int(reply.numberReturned), reply.docs}, nil;
+}
+
+func (coll *Collection) FindAll(query BSON) (*Cursor, os.Error) {
+	return coll.Query(query, 0, 0)
+}
+
+func (coll *Collection) FindOne(query BSON) (BSON, os.Error) {
+	cursor, err := coll.Query(query, 0, 1);
+	if err != nil {
+		return nil, err
+	}
+	return cursor.GetNext();
+}
+
+func (coll *Collection) Count(query BSON) (int64, os.Error) {
+	cmd := &_Object{map[string]BSON{"count": &_String{coll.name, _Null{}}, "query": query}, _Null{}};
+	reply, err := coll.db.Command(cmd);
+	if err != nil {
+		return -1, err
+	}
+
+	return int64(reply.Get("n").Number()), nil;
+}
+
+func (coll *Collection) update(um *updateMsg) os.Error {
+	um.requestID = rand.Int31();
+	conn := coll.db.conn;
+	return conn.send(um);
+}
+
+func (coll *Collection) Update(selector, document BSON) os.Error {
+	return coll.update(&updateMsg{coll.fullName(), 0, selector, document, 0})
+}
+
+func (coll *Collection) Upsert(selector, document BSON) os.Error {
+	return coll.update(&updateMsg{coll.fullName(), 1, selector, document, 0})
+}
+
+func (coll *Collection) UpdateAll(selector, document BSON) os.Error {
+	return coll.update(&updateMsg{coll.fullName(), 2, selector, document, 0})
+}
+
+func (coll *Collection) UpsertAll(selector, document BSON) os.Error {
+	return coll.update(&updateMsg{coll.fullName(), 3, selector, document, 0})
+}
+
+func (db *Database) Command(cmd BSON) (BSON, os.Error) {
+	coll := db.GetCollection("$cmd");
+	return coll.FindOne(cmd);
+}
+
+type queryMsg struct {
+	opts			int32;
+	fullCollectionName	string;
+	numberToSkip		int32;
+	numberToReturn		int32;
+	query			BSON;
+	requestID		int32;
+}
+
+func (q *queryMsg) OpCode() int32	{ return _OP_QUERY }
+func (q *queryMsg) RequestID() int32	{ return q.requestID }
+func (q *queryMsg) Bytes() []byte {
+	b := make([]byte, 4);
+	binary.LittleEndian.PutUint32(b, uint32(q.opts));
+
+	buf := bytes.NewBuffer(b);
+	buf.WriteString(q.fullCollectionName);
+	buf.WriteByte(0);
+
+	binary.LittleEndian.PutUint32(b, uint32(q.numberToSkip));
+	buf.Write(b);
+
+	binary.LittleEndian.PutUint32(b, uint32(q.numberToReturn));
+	buf.Write(b);
+
+	buf.Write(q.query.Bytes());
+	return buf.Bytes();
+}
+
+type insertMsg struct {
+	fullCollectionName	string;
+	doc			BSON;
+	requestID		int32;
+}
+
+func (i *insertMsg) OpCode() int32	{ return _OP_INSERT }
+func (i *insertMsg) RequestID() int32	{ return i.requestID }
+func (i *insertMsg) Bytes() []byte {
+	buf := bytes.NewBuffer(make([]byte, 4));
+	buf.WriteString(i.fullCollectionName);
+	buf.WriteByte(0);
+	buf.Write(i.doc.Bytes());
+	return buf.Bytes();
+}
+
+type deleteMsg struct {
+	fullCollectionName	string;
+	selector		BSON;
+	requestID		int32;
+}
+
+func (d *deleteMsg) OpCode() int32	{ return _OP_DELETE }
+func (d *deleteMsg) RequestID() int32	{ return d.requestID }
+func (d *deleteMsg) Bytes() []byte {
+	zero := make([]byte, 4);
+	buf := bytes.NewBuffer(zero);
+	buf.WriteString(d.fullCollectionName);
+	buf.WriteByte(0);
+	buf.Write(zero);
+	buf.Write(d.selector.Bytes());
+	return buf.Bytes();
+
+}
+
+type getMoreMsg struct {
+	fullCollectionName	string;
+	numberToReturn		int32;
+	cursorID		int64;
+	requestID		int32;
+}
+
+func (g *getMoreMsg) OpCode() int32	{ return _OP_GET_MORE }
+func (g *getMoreMsg) RequestID() int32	{ return g.requestID }
+func (g *getMoreMsg) Bytes() []byte {
+	buf := bytes.NewBuffer(make([]byte, 4));
+	buf.WriteString(g.fullCollectionName);
+	buf.WriteByte(0);
+
+	b := make([]byte, 4);
+	binary.LittleEndian.PutUint32(b, uint32(g.numberToReturn));
+	buf.Write(b);
+
+	b = make([]byte, 8);
+	binary.LittleEndian.PutUint64(b, uint64(g.cursorID));
+	buf.Write(b);
+
+	return buf.Bytes();
+}
+
+func (db *Database) GetCollectionNames() *vector.StringVector {
+	return new(vector.StringVector)
+}
+
+type replyMsg struct {
+	responseTo	int32;
+	responseFlag	int32;
+	cursorID	int64;
+	startingFrom	int32;
+	numberReturned	int32;
+	docs		*vector.Vector;
+}
+
+func parseReply(b []byte) *replyMsg {
+	r := new(replyMsg);
+	r.responseTo = int32(binary.LittleEndian.Uint32(b[4:8]));
+	r.responseFlag = int32(binary.LittleEndian.Uint32(b[12:16]));
+	r.cursorID = int64(binary.LittleEndian.Uint64(b[16:24]));
+	r.startingFrom = int32(binary.LittleEndian.Uint32(b[24:28]));
+	r.numberReturned = int32(binary.LittleEndian.Uint32(b[28:32]));
+	r.docs = new(vector.Vector)
+
+	if r.numberReturned > 0 {
+		buf := bytes.NewBuffer(b[36:len(b)]);
+		for i := 0; int32(i) < r.numberReturned; i++ {
+			var bson BSON;
+			bb := new(_BSONBuilder);
+			bb.ptr = &bson;
+			bb.Object();
+			Parse(buf, bb);
+			r.docs.Push(bson);
+			ioutil.ReadAll(io.LimitReader(buf, 4));
+		}
+	}
+
+	return r;
+}
+
+type updateMsg struct {
+	fullCollectionName	string;
+	flags			int32;
+	selector, document	BSON;
+	requestID		int32;
+}
+
+func (u *updateMsg) OpCode() int32	{ return _OP_UPDATE }
+func (u *updateMsg) RequestID() int32	{ return u.requestID }
+func (u *updateMsg) Bytes() []byte {
+	buf := bytes.NewBuffer(make([]byte, 4));
+	buf.WriteString(u.fullCollectionName);
+	buf.WriteByte(0);
+
+	b := make([]byte, 4);
+	binary.LittleEndian.PutUint32(b, uint32(u.flags));
+	buf.Write(b);
+
+	buf.Write(u.selector.Bytes());
+	buf.Write(u.document.Bytes());
+
+	return buf.Bytes();
+}
+
+type killMsg struct {
+	numberOfCursorIDs	int32;
+	cursorIDs		[]int64;
+	requestID		int32;
+}
+
+func (k *killMsg) OpCode() int32	{ return _OP_KILL_CURSORS }
+func (k *killMsg) RequestID() int32	{ return k.requestID }
+func (k *killMsg) Bytes() []byte {
+	buf := bytes.NewBuffer(make([]byte, 4));
+
+	b := make([]byte, 4);
+	binary.LittleEndian.PutUint32(b, uint32(k.numberOfCursorIDs));
+	buf.Write(b);
+
+	b = make([]byte, 8);
+	for _, id := range k.cursorIDs {
+		binary.LittleEndian.PutUint64(b, uint64(id));
+		buf.Write(b);
+	}
+
+	return buf.Bytes();
+}
+// Copyright 2009 Michael Stephens.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mongo_test
+
+import (
+	"mongo";
+	"testing";
+	"fmt";
+	"time";
+)
+
+type KeyStruct struct {
+	First int32;
+}
+
+type IndexCmd struct {
+	Name, Ns	string;
+	Key		*KeyStruct;
+}
+
+func TestStuff(t *testing.T) {
+	obj, err := mongo.BytesToBSON([]byte{92, 0, 0, 0, 1, 115, 101, 99, 111, 110, 100, 0, 0, 0, 0, 0, 0, 0, 0, 64, 3, 102, 105, 102, 116, 104, 0, 23, 0, 0, 0, 2, 118, 0, 2, 0, 0, 0, 101, 0, 2, 102, 0, 2, 0, 0, 0, 105, 0, 0, 3, 102, 111, 117, 114, 116, 104, 0, 5, 0, 0, 0, 0, 2, 116, 104, 105, 114, 100, 0, 6, 0, 0, 0, 116, 104, 114, 101, 101, 0, 16, 102, 105, 114, 115, 116, 0, 1, 0, 0, 0, 0});
+	assertTrue(err == nil, "failed parsing BSON obj", t);
+
+	conn, err := mongo.Connect("127.0.0.1", 27017);
+	assertTrue(err == nil && conn != nil, fmt.Sprintf("failed connecting to mongo: %v", err), t);
+
+	db := conn.GetDB("go_driver_tests");
+	coll := db.GetCollection("coll");
+	coll.Drop();
+
+	coll.Insert(obj);
+
+	q, _ := mongo.Marshal(map[string]string{});
+	ret, err := coll.FindAll(q);
+	assertTrue(err == nil && ret != nil, "query succeeded", t);
+
+	doc, _ := ret.GetNext();
+	assertTrue(doc.Kind() == mongo.ObjectKind, "query returned document", t);
+	assertTrue(doc.Get("first").Int() == 1, "returned doc has proper 'first' element", t);
+	assertTrue(doc.Get("second").Number() == 2, "returned doc has proper 'second' element", t);
+	assertTrue(doc.Get("third").String() == "three", "returned doc has proper 'third' element", t);
+	assertTrue(doc.Get("fourth").Kind() == mongo.ObjectKind, "returned doc has proper 'fourth' element", t);
+	assertTrue(doc.Get("fifth").Get("f").String() == "i" && doc.Get("fifth").Get("v").String() == "e", "returned doc has proper 'fifth' element", t);
+
+	count, err := coll.Count(q);
+	assertTrue(count == 1, "count", t);
+
+	newDoc, _ := mongo.Marshal(map[string]string{"first": "one", "second": "two", "third": "three"});
+	coll.Update(q, newDoc);
+	doc, _ = coll.FindOne(q);
+	assertTrue(doc.Get("first").String() == "one", "update", t);
+
+	rem, _ := mongo.Marshal(map[string]string{"third": "three"});
+	coll.Remove(rem);
+	doc, err = coll.FindOne(rem);
+	assertTrue(err != nil, "remove", t);
+
+	coll.Drop();
+
+	statusCmd, _ := mongo.Marshal(map[string]float64{"serverStatus": 1});
+	status, _ := db.Command(statusCmd);
+	assertTrue(status.Get("uptime").Number() != 0, "valid serverStatus", t);
+
+	db.Drop();
+}
+
+func TestOtherStuff(t *testing.T) {
+	doc, _ := mongo.Marshal(map[string]string{"_id": "doc1", "title": "A Mongo document", "content": "Testing, 1. 2. 3."});
+	conn, _ := mongo.Connect("127.0.0.1", 27017);
+	collection := conn.GetDB("test").GetCollection("test_collection");
+	collection.Insert(doc);
+
+	query, _ := mongo.Marshal(map[string]string{"_id": "doc1"});
+	got, _ := collection.FindOne(query);
+	assertTrue(mongo.Equal(doc, got), "equal", t);
+
+}
+
+const (
+	PER_TRIAL	= 1000;
+	BATCH_SIZE	= 100;
+)
+
+func timeIt(s string, f func(*mongo.Collection, *testing.T), coll *mongo.Collection, t *testing.T) {
+	start := time.Nanoseconds();
+	f(coll, t);
+	end := time.Nanoseconds();
+	diff := end - start;
+	ops := (PER_TRIAL / float64(diff)) * 1000000000.0;
+	secs := float64(diff) / 1000000000.0;
+	t.Logf("%v: %v secs, %v OPS", s, secs, ops);
+}
+
+func TestBenchmark(t *testing.T) {
+	conn, err := mongo.Connect("127.0.0.1", 27017);
+	if err != nil {
+		t.Error("failed connecting")
+	}
+
+	db := conn.GetDB("perf_test");
+	db.Drop();
+	db.GetCollection("creation").Insert(mongo.EmptyObject);
+	db.GetCollection("creation").Count(mongo.EmptyObject);
+
+	timeIt("single.small Insert", singleInsertSmall, db.GetCollection("single.small"), t);
+	timeIt("single.medium Insert", singleInsertMedium, db.GetCollection("single.medium"), t);
+	timeIt("single.large Insert", singleInsertLarge, db.GetCollection("single.large"), t);
+	timeIt("single.small FindOne", findOneSmall, db.GetCollection("single.small"), t);
+	timeIt("single.medium FindOne", findOneMedium, db.GetCollection("single.medium"), t);
+	timeIt("single.large FindOne", findOne, db.GetCollection("single.large"), t);
+
+	t.Log("---");
+	db.GetCollection("single.small.indexed").EnsureIndex("my_index1", map[string]int{"x": 1});
+	timeIt("single.small.indexed Insert", singleInsertSmall, db.GetCollection("single.small.indexed"), t);
+
+	db.GetCollection("single.medium.indexed").EnsureIndex("my_index2", map[string]int{"x": 1});
+	timeIt("single.medium.indexed Insert", singleInsertMedium, db.GetCollection("single.medium.indexed"), t);
+
+	db.GetCollection("single.large.indexed").EnsureIndex("my_index3", map[string]int{"x": 1});
+	timeIt("single.large.indexed Insert", singleInsertLarge, db.GetCollection("single.large.indexed"), t);
+
+	timeIt("single.small.indexed FindOne", findOneSmall, db.GetCollection("single.small.indexed"), t);
+	timeIt("single.medium.indexed FindOne", findOneMedium, db.GetCollection("single.medium.indexed"), t);
+	timeIt("single.large.indexed FindOne", findOne, db.GetCollection("single.large.indexed"), t);
+}
+
+type smallStruct struct {
+	X int;
+}
+
+func singleInsertSmall(coll *mongo.Collection, t *testing.T) {
+	ss := &smallStruct{0};
+	for i := 0; i < PER_TRIAL; i++ {
+		ss.X = i;
+		obj, err := mongo.Marshal(ss);
+		if err != nil {
+			t.Errorf("singleInsertSmall Marshal: %v\n", err)
+		}
+
+		err = coll.Insert(obj);
+		if err != nil {
+			t.Errorf("singleInsertSmall Insert: %v\n", err)
+		}
+	}
+}
+
+func findOneSmall(coll *mongo.Collection, t *testing.T) {
+	ss := &smallStruct{PER_TRIAL / 2};
+	obj, err := mongo.Marshal(ss);
+	if err != nil {
+		t.Errorf("findOneSmall Marshal: %v\n", err)
+	}
+
+	for i := 0; i < PER_TRIAL; i++ {
+		_, err = coll.FindOne(obj);
+		if err != nil {
+			t.Errorf("findOneSmall FindOne: %v\n", err)
+		}
+	}
+}
+
+type mediumStruct struct {
+	Integer	int;
+	Number	float64;
+	Boolean	bool;
+	Array	[]string;
+	X	int;
+}
+
+func singleInsertMedium(coll *mongo.Collection, t *testing.T) {
+	ms := &mediumStruct{5, 5.05, false, []string{"test", "benchmark"}, 0};
+	for i := 0; i < PER_TRIAL; i++ {
+		ms.X = i;
+		obj, err := mongo.Marshal(ms);
+		if err != nil {
+			t.Errorf("singleInsertMedium Marshal: %v\n", err)
+		}
+
+		err = coll.Insert(obj);
+		if err != nil {
+			t.Errorf("singleInsertMedium Insert: %v\n", err)
+		}
+	}
+}
+
+func findOneMedium(coll *mongo.Collection, t *testing.T) {
+	ss := &smallStruct{PER_TRIAL / 2};
+	obj, err := mongo.Marshal(ss);
+	if err != nil {
+		t.Errorf("findOneMedium Marshal: %v\n", err)
+	}
+
+	for i := 0; i < PER_TRIAL; i++ {
+		_, err = coll.FindOne(obj);
+		if err != nil {
+			t.Errorf("findOneMedium FindOne: %v\n", err)
+		}
+	}
+}
+
+func findOne(coll *mongo.Collection, t *testing.T) {
+	ss := &smallStruct{PER_TRIAL / 2};
+	obj, err := mongo.Marshal(ss);
+	if err != nil {
+		t.Errorf("findOne Marshal: %v\n", err)
+	}
+
+	for i := 0; i < PER_TRIAL; i++ {
+		_, err = coll.FindOne(obj);
+		if err != nil {
+			t.Errorf("findOne FindOne: %v\n", err)
+		}
+	}
+}
+
+type largeStruct struct {
+	Base_url		string;
+	Total_word_count	int;
+	Access_time		*time.Time;
+	Meta_tags		map[string]string;
+	Page_structure		map[string]int;
+	Harvested_words		[]string;
+	X			int;
+}
+
+func singleInsertLarge(coll *mongo.Collection, t *testing.T) {
+	base_words := []string{"10gen", "web", "open", "source", "application", "paas",
+		"platform-as-a-service", "technology", "helps",
+		"developers", "focus", "building", "mongodb", "mongo",
+	};
+
+	words := make([]string, 280);
+	for i := 0; i < 20; i++ {
+		for k, word := range base_words {
+			words[i+k] = word
+		}
+	}
+
+	ls := &largeStruct{"http://www.example.com/test-me",
+		6743, time.UTC(),
+		map[string]string{"description": "i am a long description string",
+			"author": "Holly Man",
+			"dynamically_created_meta_tag": "who know\n what",
+		},
+		map[string]int{"counted_tags": 3450,
+			"no_of_js_attached": 10,
+			"no_of_images": 6,
+		},
+		words, 0,
+	};
+
+	for i := 0; i < PER_TRIAL; i++ {
+		ls.X = i;
+		obj, err := mongo.Marshal(ls);
+		if err != nil {
+			t.Errorf("singleInsertLarge Marshal: %v", err)
+		}
+
+		err = coll.Insert(obj);
+		if err != nil {
+			t.Errorf("singleInsertLarge Insert: %v", err)
+		}
+	}
+}