summaryrefslogtreecommitdiff
path: root/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson')
-rw-r--r--src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bson.go22
-rw-r--r--src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bson_1_8.go28
-rw-r--r--src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/default_value_decoders.go75
-rw-r--r--src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/default_value_encoders.go88
-rw-r--r--src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/map_codec.go203
-rw-r--r--src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/string_codec.go81
-rw-r--r--src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/struct_codec.go211
-rw-r--r--src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/time_codec.go98
-rw-r--r--src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/map_codec_options.go38
-rw-r--r--src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/string_codec_options.go41
-rw-r--r--src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/struct_codec_options.go70
-rw-r--r--src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/time_codec_options.go38
-rw-r--r--src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_wrappers.go18
-rw-r--r--src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_writer.go5
-rw-r--r--src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/value_writer.go37
-rw-r--r--src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/writer.go6
-rw-r--r--src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/decoder.go18
-rw-r--r--src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/doc.go106
-rw-r--r--src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/marshal.go89
-rw-r--r--src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/mgocompat/registry.go59
-rw-r--r--src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/primitive/decimal.go379
-rw-r--r--src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/primitive/primitive.go58
22 files changed, 1454 insertions, 314 deletions
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bson.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bson.go
index 37bf9811f31..ae1a87faa7b 100644
--- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bson.go
+++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bson.go
@@ -22,39 +22,29 @@ type Zeroer interface {
IsZero() bool
}
-// D represents a BSON Document. This type can be used to represent BSON in a concise and readable
-// manner. It should generally be used when serializing to BSON. For deserializing, the Raw or
-// Document types should be used.
+// D is an ordered representation of a BSON document. This type should be used when the order of the elements matters,
+// such as MongoDB command documents. If the order of the elements does not matter, an M should be used instead.
//
// Example usage:
//
// bson.D{{"foo", "bar"}, {"hello", "world"}, {"pi", 3.14159}}
-//
-// This type should be used in situations where order matters, such as MongoDB commands. If the
-// order is not important, a map is more comfortable and concise.
type D = primitive.D
// E represents a BSON element for a D. It is usually used inside a D.
type E = primitive.E
-// M is an unordered, concise representation of a BSON Document. It should generally be used to
-// serialize BSON when the order of the elements of a BSON document do not matter. If the element
-// order matters, use a D instead.
+// M is an unordered representation of a BSON document. This type should be used when the order of the elements does not
+// matter. This type is handled as a regular map[string]interface{} when encoding and decoding. Elements will be
+// serialized in an undefined, random order. If the order of the elements matters, a D should be used instead.
//
// Example usage:
//
// bson.M{"foo": "bar", "hello": "world", "pi": 3.14159}
-//
-// This type is handled in the encoders as a regular map[string]interface{}. The elements will be
-// serialized in an undefined, random order, and the order will be different each time.
type M = primitive.M
-// An A represents a BSON array. This type can be used to represent a BSON array in a concise and
-// readable manner. It should generally be used when serializing to BSON. For deserializing, the
-// RawArray or Array types should be used.
+// An A is an ordered representation of a BSON array.
//
// Example usage:
//
// bson.A{"bar", "world", 3.14159, bson.D{{"qux", 12345}}}
-//
type A = primitive.A
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bson_1_8.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bson_1_8.go
index caf5f50a716..bbe7792848f 100644
--- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bson_1_8.go
+++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bson_1_8.go
@@ -21,16 +21,12 @@ type Zeroer interface {
IsZero() bool
}
-// D represents a BSON Document. This type can be used to represent BSON in a concise and readable
-// manner. It should generally be used when serializing to BSON. For deserializing, the Raw or
-// Document types should be used.
+// D is an ordered representation of a BSON document. This type should be used when the order of the elements matters,
+// such as MongoDB command documents. If the order of the elements does not matter, an M should be used instead.
//
// Example usage:
//
-// primitive.D{{"foo", "bar"}, {"hello", "world"}, {"pi", 3.14159}}
-//
-// This type should be used in situations where order matters, such as MongoDB commands. If the
-// order is not important, a map is more comfortable and concise.
+// bson.D{{"foo", "bar"}, {"hello", "world"}, {"pi", 3.14159}}
type D []E
// Map creates a map from the elements of the D.
@@ -48,26 +44,20 @@ type E struct {
Value interface{}
}
-// M is an unordered, concise representation of a BSON Document. It should generally be used to
-// serialize BSON when the order of the elements of a BSON document do not matter. If the element
-// order matters, use a D instead.
+// M is an unordered representation of a BSON document. This type should be used when the order of the elements does not
+// matter. This type is handled as a regular map[string]interface{} when encoding and decoding. Elements will be
+// serialized in an undefined, random order. If the order of the elements matters, a D should be used instead.
//
// Example usage:
//
-// primitive.M{"foo": "bar", "hello": "world", "pi": 3.14159}
-//
-// This type is handled in the encoders as a regular map[string]interface{}. The elements will be
-// serialized in an undefined, random order, and the order will be different each time.
+// bson.M{"foo": "bar", "hello": "world", "pi": 3.14159}
type M map[string]interface{}
-// An A represents a BSON array. This type can be used to represent a BSON array in a concise and
-// readable manner. It should generally be used when serializing to BSON. For deserializing, the
-// RawArray or Array types should be used.
+// An A is an ordered representation of a BSON array.
//
// Example usage:
//
-// primitive.A{"bar", "world", 3.14159, primitive.D{{"qux", 12345}}}
-//
+// bson.A{"bar", "world", 3.14159, bson.D{{"qux", 12345}}}
type A []interface{}
func formatDouble(f float64) string {
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/default_value_decoders.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/default_value_decoders.go
index 65cd1c0a55c..7f5bfbd1589 100644
--- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/default_value_decoders.go
+++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/default_value_decoders.go
@@ -52,7 +52,7 @@ func (dvd DefaultValueDecoders) RegisterDefaultDecoders(rb *RegistryBuilder) {
RegisterDecoder(tJavaScript, ValueDecoderFunc(dvd.JavaScriptDecodeValue)).
RegisterDecoder(tSymbol, ValueDecoderFunc(dvd.SymbolDecodeValue)).
RegisterDecoder(tByteSlice, ValueDecoderFunc(dvd.ByteSliceDecodeValue)).
- RegisterDecoder(tTime, ValueDecoderFunc(dvd.TimeDecodeValue)).
+ RegisterDecoder(tTime, defaultTimeCodec).
RegisterDecoder(tEmpty, ValueDecoderFunc(dvd.EmptyInterfaceDecodeValue)).
RegisterDecoder(tOID, ValueDecoderFunc(dvd.ObjectIDDecodeValue)).
RegisterDecoder(tDecimal, ValueDecoderFunc(dvd.Decimal128DecodeValue)).
@@ -76,10 +76,10 @@ func (dvd DefaultValueDecoders) RegisterDefaultDecoders(rb *RegistryBuilder) {
RegisterDefaultDecoder(reflect.Float32, ValueDecoderFunc(dvd.FloatDecodeValue)).
RegisterDefaultDecoder(reflect.Float64, ValueDecoderFunc(dvd.FloatDecodeValue)).
RegisterDefaultDecoder(reflect.Array, ValueDecoderFunc(dvd.ArrayDecodeValue)).
- RegisterDefaultDecoder(reflect.Map, ValueDecoderFunc(dvd.MapDecodeValue)).
+ RegisterDefaultDecoder(reflect.Map, defaultMapCodec).
RegisterDefaultDecoder(reflect.Slice, ValueDecoderFunc(dvd.SliceDecodeValue)).
- RegisterDefaultDecoder(reflect.String, ValueDecoderFunc(dvd.StringDecodeValue)).
- RegisterDefaultDecoder(reflect.Struct, &StructCodec{cache: make(map[reflect.Type]*structDescription), parser: DefaultStructTagParser}).
+ RegisterDefaultDecoder(reflect.String, defaultStringCodec).
+ RegisterDefaultDecoder(reflect.Struct, defaultStructCodec).
RegisterDefaultDecoder(reflect.Ptr, NewPointerCodec()).
RegisterTypeMapEntry(bsontype.Double, tFloat64).
RegisterTypeMapEntry(bsontype.String, tString).
@@ -105,19 +105,44 @@ func (dvd DefaultValueDecoders) RegisterDefaultDecoders(rb *RegistryBuilder) {
// BooleanDecodeValue is the ValueDecoderFunc for bool types.
func (dvd DefaultValueDecoders) BooleanDecodeValue(dctx DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
- if vr.Type() != bsontype.Boolean {
- return fmt.Errorf("cannot decode %v into a boolean", vr.Type())
- }
if !val.IsValid() || !val.CanSet() || val.Kind() != reflect.Bool {
return ValueDecoderError{Name: "BooleanDecodeValue", Kinds: []reflect.Kind{reflect.Bool}, Received: val}
}
- b, err := vr.ReadBoolean()
+ var b bool
+ var err error
+ switch vr.Type() {
+ case bsontype.Int32:
+ i32, err := vr.ReadInt32()
+ if err != nil {
+ return err
+ }
+ b = (i32 != 0)
+ case bsontype.Int64:
+ i64, err := vr.ReadInt64()
+ if err != nil {
+ return err
+ }
+ b = (i64 != 0)
+ case bsontype.Double:
+ f64, err := vr.ReadDouble()
+ if err != nil {
+ return err
+ }
+ b = (f64 != 0)
+ case bsontype.Boolean:
+ b, err = vr.ReadBoolean()
+ if err != nil {
+ return err
+ }
+ default:
+ return fmt.Errorf("cannot decode %v into a boolean", vr.Type())
+ }
val.SetBool(b)
- return err
+ return nil
}
-// IntDecodeValue is the ValueDecoderFunc for bool types.
+// IntDecodeValue is the ValueDecoderFunc for int types.
func (dvd DefaultValueDecoders) IntDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
var i64 int64
var err error
@@ -145,6 +170,14 @@ func (dvd DefaultValueDecoders) IntDecodeValue(dc DecodeContext, vr bsonrw.Value
return fmt.Errorf("%g overflows int64", f64)
}
i64 = int64(f64)
+ case bsontype.Boolean:
+ b, err := vr.ReadBoolean()
+ if err != nil {
+ return err
+ }
+ if b {
+ i64 = 1
+ }
default:
return fmt.Errorf("cannot decode %v into an integer type", vr.Type())
}
@@ -215,6 +248,14 @@ func (dvd DefaultValueDecoders) UintDecodeValue(dc DecodeContext, vr bsonrw.Valu
return fmt.Errorf("%g overflows int64", f64)
}
i64 = int64(f64)
+ case bsontype.Boolean:
+ b, err := vr.ReadBoolean()
+ if err != nil {
+ return err
+ }
+ if b {
+ i64 = 1
+ }
default:
return fmt.Errorf("cannot decode %v into an integer type", vr.Type())
}
@@ -282,6 +323,14 @@ func (dvd DefaultValueDecoders) FloatDecodeValue(ec DecodeContext, vr bsonrw.Val
if err != nil {
return err
}
+ case bsontype.Boolean:
+ b, err := vr.ReadBoolean()
+ if err != nil {
+ return err
+ }
+ if b {
+ f = 1
+ }
default:
return fmt.Errorf("cannot decode %v into a float32 or float64 type", vr.Type())
}
@@ -329,7 +378,7 @@ func (dvd DefaultValueDecoders) StringDecodeValue(dctx DecodeContext, vr bsonrw.
// JavaScriptDecodeValue is the ValueDecoderFunc for the primitive.JavaScript type.
func (DefaultValueDecoders) JavaScriptDecodeValue(dctx DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Type() != tJavaScript {
- return ValueDecoderError{Name: "BinaryDecodeValue", Types: []reflect.Type{tJavaScript}, Received: val}
+ return ValueDecoderError{Name: "JavaScriptDecodeValue", Types: []reflect.Type{tJavaScript}, Received: val}
}
if vr.Type() != bsontype.JavaScript {
@@ -348,7 +397,7 @@ func (DefaultValueDecoders) JavaScriptDecodeValue(dctx DecodeContext, vr bsonrw.
// SymbolDecodeValue is the ValueDecoderFunc for the primitive.Symbol type.
func (DefaultValueDecoders) SymbolDecodeValue(dctx DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Type() != tSymbol {
- return ValueDecoderError{Name: "BinaryDecodeValue", Types: []reflect.Type{tSymbol}, Received: val}
+ return ValueDecoderError{Name: "SymbolDecodeValue", Types: []reflect.Type{tSymbol}, Received: val}
}
if vr.Type() != bsontype.Symbol {
@@ -555,7 +604,7 @@ func (dvd DefaultValueDecoders) JSONNumberDecodeValue(dc DecodeContext, vr bsonr
if err != nil {
return err
}
- val.Set(reflect.ValueOf(json.Number(strconv.FormatFloat(f64, 'g', -1, 64))))
+ val.Set(reflect.ValueOf(json.Number(strconv.FormatFloat(f64, 'f', -1, 64))))
case bsontype.Int32:
i32, err := vr.ReadInt32()
if err != nil {
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/default_value_encoders.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/default_value_encoders.go
index 39ebfc7ecd3..03afc0e0bc2 100644
--- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/default_value_encoders.go
+++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/default_value_encoders.go
@@ -26,6 +26,8 @@ var defaultValueEncoders DefaultValueEncoders
var bvwPool = bsonrw.NewBSONValueWriterPool()
+var errInvalidValue = errors.New("cannot encode invalid element")
+
var sliceWriterPool = sync.Pool{
New: func() interface{} {
sw := make(bsonrw.SliceWriter, 0, 0)
@@ -66,7 +68,7 @@ func (dve DefaultValueEncoders) RegisterDefaultEncoders(rb *RegistryBuilder) {
}
rb.
RegisterEncoder(tByteSlice, ValueEncoderFunc(dve.ByteSliceEncodeValue)).
- RegisterEncoder(tTime, ValueEncoderFunc(dve.TimeEncodeValue)).
+ RegisterEncoder(tTime, defaultTimeCodec).
RegisterEncoder(tEmpty, ValueEncoderFunc(dve.EmptyInterfaceEncodeValue)).
RegisterEncoder(tOID, ValueEncoderFunc(dve.ObjectIDEncodeValue)).
RegisterEncoder(tDecimal, ValueEncoderFunc(dve.Decimal128EncodeValue)).
@@ -102,10 +104,10 @@ func (dve DefaultValueEncoders) RegisterDefaultEncoders(rb *RegistryBuilder) {
RegisterDefaultEncoder(reflect.Float32, ValueEncoderFunc(dve.FloatEncodeValue)).
RegisterDefaultEncoder(reflect.Float64, ValueEncoderFunc(dve.FloatEncodeValue)).
RegisterDefaultEncoder(reflect.Array, ValueEncoderFunc(dve.ArrayEncodeValue)).
- RegisterDefaultEncoder(reflect.Map, ValueEncoderFunc(dve.MapEncodeValue)).
+ RegisterDefaultEncoder(reflect.Map, defaultMapCodec).
RegisterDefaultEncoder(reflect.Slice, ValueEncoderFunc(dve.SliceEncodeValue)).
- RegisterDefaultEncoder(reflect.String, ValueEncoderFunc(dve.StringEncodeValue)).
- RegisterDefaultEncoder(reflect.Struct, &StructCodec{cache: make(map[reflect.Type]*structDescription), parser: DefaultStructTagParser}).
+ RegisterDefaultEncoder(reflect.String, defaultStringCodec).
+ RegisterDefaultEncoder(reflect.Struct, defaultStructCodec).
RegisterDefaultEncoder(reflect.Ptr, NewPointerCodec())
}
@@ -289,8 +291,9 @@ func (dve DefaultValueEncoders) MapEncodeValue(ec EncodeContext, vw bsonrw.Value
// struct codec.
func (dve DefaultValueEncoders) mapEncodeValue(ec EncodeContext, dw bsonrw.DocumentWriter, val reflect.Value, collisionFn func(string) bool) error {
- encoder, err := ec.LookupEncoder(val.Type().Elem())
- if err != nil {
+ elemType := val.Type().Elem()
+ encoder, err := ec.LookupEncoder(elemType)
+ if err != nil && elemType.Kind() != reflect.Interface {
return err
}
@@ -299,19 +302,33 @@ func (dve DefaultValueEncoders) mapEncodeValue(ec EncodeContext, dw bsonrw.Docum
if collisionFn != nil && collisionFn(key.String()) {
return fmt.Errorf("Key %s of inlined map conflicts with a struct field name", key)
}
+
+ currEncoder, currVal, lookupErr := dve.lookupElementEncoder(ec, encoder, val.MapIndex(key))
+ if lookupErr != nil && lookupErr != errInvalidValue {
+ return lookupErr
+ }
+
vw, err := dw.WriteDocumentElement(key.String())
if err != nil {
return err
}
- if enc, ok := encoder.(ValueEncoder); ok {
- err = enc.EncodeValue(ec, vw, val.MapIndex(key))
+ if lookupErr == errInvalidValue {
+ err = vw.WriteNull()
if err != nil {
return err
}
continue
}
- err = encoder.EncodeValue(ec, vw, val.MapIndex(key))
+
+ if enc, ok := currEncoder.(ValueEncoder); ok {
+ err = enc.EncodeValue(ec, vw, currVal)
+ if err != nil {
+ return err
+ }
+ continue
+ }
+ err = encoder.EncodeValue(ec, vw, currVal)
if err != nil {
return err
}
@@ -349,18 +366,32 @@ func (dve DefaultValueEncoders) ArrayEncodeValue(ec EncodeContext, vw bsonrw.Val
return err
}
- encoder, err := ec.LookupEncoder(val.Type().Elem())
- if err != nil {
+ elemType := val.Type().Elem()
+ encoder, err := ec.LookupEncoder(elemType)
+ if err != nil && elemType.Kind() != reflect.Interface {
return err
}
for idx := 0; idx < val.Len(); idx++ {
+ currEncoder, currVal, lookupErr := dve.lookupElementEncoder(ec, encoder, val.Index(idx))
+ if lookupErr != nil && lookupErr != errInvalidValue {
+ return lookupErr
+ }
+
vw, err := aw.WriteArrayElement()
if err != nil {
return err
}
- err = encoder.EncodeValue(ec, vw, val.Index(idx))
+ if lookupErr == errInvalidValue {
+ err = vw.WriteNull()
+ if err != nil {
+ return err
+ }
+ continue
+ }
+
+ err = currEncoder.EncodeValue(ec, vw, currVal)
if err != nil {
return err
}
@@ -402,18 +433,32 @@ func (dve DefaultValueEncoders) SliceEncodeValue(ec EncodeContext, vw bsonrw.Val
return err
}
- encoder, err := ec.LookupEncoder(val.Type().Elem())
- if err != nil {
+ elemType := val.Type().Elem()
+ encoder, err := ec.LookupEncoder(elemType)
+ if err != nil && elemType.Kind() != reflect.Interface {
return err
}
for idx := 0; idx < val.Len(); idx++ {
+ currEncoder, currVal, lookupErr := dve.lookupElementEncoder(ec, encoder, val.Index(idx))
+ if lookupErr != nil && lookupErr != errInvalidValue {
+ return lookupErr
+ }
+
vw, err := aw.WriteArrayElement()
if err != nil {
return err
}
- err = encoder.EncodeValue(ec, vw, val.Index(idx))
+ if lookupErr == errInvalidValue {
+ err = vw.WriteNull()
+ if err != nil {
+ return err
+ }
+ continue
+ }
+
+ err = currEncoder.EncodeValue(ec, vw, currVal)
if err != nil {
return err
}
@@ -421,6 +466,19 @@ func (dve DefaultValueEncoders) SliceEncodeValue(ec EncodeContext, vw bsonrw.Val
return aw.WriteArrayEnd()
}
+func (dve DefaultValueEncoders) lookupElementEncoder(ec EncodeContext, origEncoder ValueEncoder, currVal reflect.Value) (ValueEncoder, reflect.Value, error) {
+ if origEncoder != nil || (currVal.Kind() != reflect.Interface) {
+ return origEncoder, currVal, nil
+ }
+ currVal = currVal.Elem()
+ if !currVal.IsValid() {
+ return nil, currVal, errInvalidValue
+ }
+ currEncoder, err := ec.LookupEncoder(currVal.Type())
+
+ return currEncoder, currVal, err
+}
+
// EmptyInterfaceEncodeValue is the ValueEncoderFunc for interface{}.
func (dve DefaultValueEncoders) EmptyInterfaceEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Type() != tEmpty {
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/map_codec.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/map_codec.go
new file mode 100644
index 00000000000..0015024ee42
--- /dev/null
+++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/map_codec.go
@@ -0,0 +1,203 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package bsoncodec
+
+import (
+ "fmt"
+ "reflect"
+ "strconv"
+
+ "go.mongodb.org/mongo-driver/bson/bsonoptions"
+ "go.mongodb.org/mongo-driver/bson/bsonrw"
+ "go.mongodb.org/mongo-driver/bson/bsontype"
+)
+
+var defaultMapCodec = NewMapCodec()
+
+// MapCodec is the Codec used for map values.
+type MapCodec struct {
+ DecodeZerosMap bool
+}
+
+var _ ValueCodec = &MapCodec{}
+
+// NewMapCodec returns a MapCodec with options opts.
+func NewMapCodec(opts ...*bsonoptions.MapCodecOptions) *MapCodec {
+ mapOpt := bsonoptions.MergeMapCodecOptions(opts...)
+
+ codec := MapCodec{}
+ if mapOpt.DecodeZerosMap != nil {
+ codec.DecodeZerosMap = *mapOpt.DecodeZerosMap
+ }
+ return &codec
+}
+
+// EncodeValue is the ValueEncoder for map[*]* types.
+func (mc *MapCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
+ if !val.IsValid() || val.Kind() != reflect.Map {
+ return ValueEncoderError{Name: "MapEncodeValue", Kinds: []reflect.Kind{reflect.Map}, Received: val}
+ }
+
+ if val.IsNil() {
+ // If we have a nil map but we can't WriteNull, that means we're probably trying to encode
+ // to a TopLevel document. We can't currently tell if this is what actually happened, but if
+ // there's a deeper underlying problem, the error will also be returned from WriteDocument,
+ // so just continue. The operations on a map reflection value are valid, so we can call
+ // MapKeys within mapEncodeValue without a problem.
+ err := vw.WriteNull()
+ if err == nil {
+ return nil
+ }
+ }
+
+ dw, err := vw.WriteDocument()
+ if err != nil {
+ return err
+ }
+
+ return mc.mapEncodeValue(ec, dw, val, nil)
+}
+
+// mapEncodeValue handles encoding of the values of a map. The collisionFn returns
+// true if the provided key exists, this is mainly used for inline maps in the
+// struct codec.
+func (mc *MapCodec) mapEncodeValue(ec EncodeContext, dw bsonrw.DocumentWriter, val reflect.Value, collisionFn func(string) bool) error {
+
+ elemType := val.Type().Elem()
+ encoder, err := ec.LookupEncoder(elemType)
+ if err != nil && elemType.Kind() != reflect.Interface {
+ return err
+ }
+
+ keys := val.MapKeys()
+ for _, key := range keys {
+ keyStr := fmt.Sprint(key)
+ if collisionFn != nil && collisionFn(keyStr) {
+ return fmt.Errorf("Key %s of inlined map conflicts with a struct field name", key)
+ }
+
+ currEncoder, currVal, lookupErr := defaultValueEncoders.lookupElementEncoder(ec, encoder, val.MapIndex(key))
+ if lookupErr != nil && lookupErr != errInvalidValue {
+ return lookupErr
+ }
+
+ vw, err := dw.WriteDocumentElement(keyStr)
+ if err != nil {
+ return err
+ }
+
+ if lookupErr == errInvalidValue {
+ err = vw.WriteNull()
+ if err != nil {
+ return err
+ }
+ continue
+ }
+
+ if enc, ok := currEncoder.(ValueEncoder); ok {
+ err = enc.EncodeValue(ec, vw, currVal)
+ if err != nil {
+ return err
+ }
+ continue
+ }
+ err = encoder.EncodeValue(ec, vw, currVal)
+ if err != nil {
+ return err
+ }
+ }
+
+ return dw.WriteDocumentEnd()
+}
+
+// DecodeValue is the ValueDecoder for map[string/decimal]* types.
+func (mc *MapCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
+ if (!val.CanSet() && val.IsNil()) || val.Kind() != reflect.Map {
+ return ValueDecoderError{Name: "MapDecodeValue", Kinds: []reflect.Kind{reflect.Map}, Received: val}
+ }
+
+ switch vr.Type() {
+ case bsontype.Type(0), bsontype.EmbeddedDocument:
+ case bsontype.Null:
+ val.Set(reflect.Zero(val.Type()))
+ return vr.ReadNull()
+ default:
+ return fmt.Errorf("cannot decode %v into a %s", vr.Type(), val.Type())
+ }
+
+ dr, err := vr.ReadDocument()
+ if err != nil {
+ return err
+ }
+
+ if val.IsNil() {
+ val.Set(reflect.MakeMap(val.Type()))
+ }
+
+ if val.Len() > 0 && mc.DecodeZerosMap {
+ clearMap(val)
+ }
+
+ eType := val.Type().Elem()
+ decoder, err := dc.LookupDecoder(eType)
+ if err != nil {
+ return err
+ }
+
+ if eType == tEmpty {
+ dc.Ancestor = val.Type()
+ }
+
+ keyType := val.Type().Key()
+ keyKind := keyType.Kind()
+
+ for {
+ key, vr, err := dr.ReadElement()
+ if err == bsonrw.ErrEOD {
+ break
+ }
+ if err != nil {
+ return err
+ }
+
+ elem := reflect.New(eType).Elem()
+
+ err = decoder.DecodeValue(dc, vr, elem)
+ if err != nil {
+ return err
+ }
+
+ k := reflect.ValueOf(key)
+ if keyType != tString {
+ switch keyKind {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+ reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
+ reflect.Float32, reflect.Float64:
+ parsed, err := strconv.ParseFloat(k.String(), 64)
+ if err != nil {
+ return fmt.Errorf("Map key is defined to be a decimal type (%v) but got error %v", keyKind, err)
+ }
+ k = reflect.ValueOf(parsed)
+ case reflect.String: // if keyType wraps string
+ default:
+ return fmt.Errorf("BSON map must have string or decimal keys. Got:%v", val)
+ }
+
+ k = k.Convert(keyType)
+ }
+
+ val.SetMapIndex(k, elem)
+ }
+ return nil
+}
+
+func clearMap(m reflect.Value) {
+ var none reflect.Value
+ for _, k := range m.MapKeys() {
+ m.SetMapIndex(k, none)
+ }
+}
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/string_codec.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/string_codec.go
new file mode 100644
index 00000000000..f24f2e9a7bb
--- /dev/null
+++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/string_codec.go
@@ -0,0 +1,81 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package bsoncodec
+
+import (
+ "fmt"
+ "reflect"
+
+ "go.mongodb.org/mongo-driver/bson/bsonoptions"
+ "go.mongodb.org/mongo-driver/bson/bsonrw"
+ "go.mongodb.org/mongo-driver/bson/bsontype"
+)
+
+var defaultStringCodec = NewStringCodec()
+
+// StringCodec is the Codec used for struct values.
+type StringCodec struct {
+ DecodeObjectIDAsHex bool
+}
+
+var _ ValueCodec = &StringCodec{}
+
+// NewStringCodec returns a StringCodec with options opts.
+func NewStringCodec(opts ...*bsonoptions.StringCodecOptions) *StringCodec {
+ stringOpt := bsonoptions.MergeStringCodecOptions(opts...)
+ return &StringCodec{*stringOpt.DecodeObjectIDAsHex}
+}
+
+// EncodeValue is the ValueEncoder for string types.
+func (sc *StringCodec) EncodeValue(ectx EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
+ if val.Kind() != reflect.String {
+ return ValueEncoderError{
+ Name: "StringEncodeValue",
+ Kinds: []reflect.Kind{reflect.String},
+ Received: val,
+ }
+ }
+
+ return vw.WriteString(val.String())
+}
+
+// DecodeValue is the ValueDecoder for string types.
+func (sc *StringCodec) DecodeValue(dctx DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
+ if !val.CanSet() || val.Kind() != reflect.String {
+ return ValueDecoderError{Name: "StringDecodeValue", Kinds: []reflect.Kind{reflect.String}, Received: val}
+ }
+ var str string
+ var err error
+ switch vr.Type() {
+ case bsontype.String:
+ str, err = vr.ReadString()
+ if err != nil {
+ return err
+ }
+ case bsontype.ObjectID:
+ oid, err := vr.ReadObjectID()
+ if err != nil {
+ return err
+ }
+ if sc.DecodeObjectIDAsHex {
+ str = oid.Hex()
+ } else {
+ byteArray := [12]byte(oid)
+ str = string(byteArray[:])
+ }
+ case bsontype.Symbol:
+ str, err = vr.ReadSymbol()
+ if err != nil {
+ return err
+ }
+ default:
+ return fmt.Errorf("cannot decode %v into a string type", vr.Type())
+ }
+
+ val.SetString(str)
+ return nil
+}
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/struct_codec.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/struct_codec.go
index 56eeff94b17..7853b0c59ce 100644
--- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/struct_codec.go
+++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/struct_codec.go
@@ -12,7 +12,9 @@ import (
"reflect"
"strings"
"sync"
+ "time"
+ "go.mongodb.org/mongo-driver/bson/bsonoptions"
"go.mongodb.org/mongo-driver/bson/bsonrw"
"go.mongodb.org/mongo-driver/bson/bsontype"
)
@@ -31,24 +33,45 @@ type Zeroer interface {
// StructCodec is the Codec used for struct values.
type StructCodec struct {
- cache map[reflect.Type]*structDescription
- l sync.RWMutex
- parser StructTagParser
+ cache map[reflect.Type]*structDescription
+ l sync.RWMutex
+ parser StructTagParser
+ DecodeZeroStruct bool
+ DecodeDeepZeroInline bool
+ EncodeOmitDefaultStruct bool
+ AllowUnexportedFields bool
}
var _ ValueEncoder = &StructCodec{}
var _ ValueDecoder = &StructCodec{}
// NewStructCodec returns a StructCodec that uses p for struct tag parsing.
-func NewStructCodec(p StructTagParser) (*StructCodec, error) {
+func NewStructCodec(p StructTagParser, opts ...*bsonoptions.StructCodecOptions) (*StructCodec, error) {
if p == nil {
return nil, errors.New("a StructTagParser must be provided to NewStructCodec")
}
- return &StructCodec{
+ structOpt := bsonoptions.MergeStructCodecOptions(opts...)
+
+ codec := &StructCodec{
cache: make(map[reflect.Type]*structDescription),
parser: p,
- }, nil
+ }
+
+ if structOpt.DecodeZeroStruct != nil {
+ codec.DecodeZeroStruct = *structOpt.DecodeZeroStruct
+ }
+ if structOpt.DecodeDeepZeroInline != nil {
+ codec.DecodeDeepZeroInline = *structOpt.DecodeDeepZeroInline
+ }
+ if structOpt.EncodeOmitDefaultStruct != nil {
+ codec.EncodeOmitDefaultStruct = *structOpt.EncodeOmitDefaultStruct
+ }
+ if structOpt.AllowUnexportedFields != nil {
+ codec.AllowUnexportedFields = *structOpt.AllowUnexportedFields
+ }
+
+ return codec, nil
}
// EncodeValue handles encoding generic struct types.
@@ -71,7 +94,31 @@ func (sc *StructCodec) EncodeValue(r EncodeContext, vw bsonrw.ValueWriter, val r
if desc.inline == nil {
rv = val.Field(desc.idx)
} else {
- rv = val.FieldByIndex(desc.inline)
+ rv, err = fieldByIndexErr(val, desc.inline)
+ if err != nil {
+ continue
+ }
+ }
+
+ desc.encoder, rv, err = defaultValueEncoders.lookupElementEncoder(r, desc.encoder, rv)
+
+ if err != nil && err != errInvalidValue {
+ return err
+ }
+
+ if err == errInvalidValue {
+ if desc.omitEmpty {
+ continue
+ }
+ vw2, err := dw.WriteDocumentElement(desc.name)
+ if err != nil {
+ return err
+ }
+ err = vw2.WriteNull()
+ if err != nil {
+ return err
+ }
+ continue
}
if desc.encoder == nil {
@@ -80,12 +127,17 @@ func (sc *StructCodec) EncodeValue(r EncodeContext, vw bsonrw.ValueWriter, val r
encoder := desc.encoder
- iszero := sc.isZero
- if iz, ok := encoder.(CodecZeroer); ok {
- iszero = iz.IsTypeZero
+ var isZero bool
+ rvInterface := rv.Interface()
+ if cz, ok := encoder.(CodecZeroer); ok {
+ isZero = cz.IsTypeZero(rvInterface)
+ } else if rv.Kind() == reflect.Interface {
+ // sc.isZero will not treat an interface rv as an interface, so we need to check for the zero interface separately.
+ isZero = rv.IsNil()
+ } else {
+ isZero = sc.isZero(rvInterface)
}
-
- if desc.omitEmpty && iszero(rv.Interface()) {
+ if desc.omitEmpty && isZero {
continue
}
@@ -108,7 +160,7 @@ func (sc *StructCodec) EncodeValue(r EncodeContext, vw bsonrw.ValueWriter, val r
return exists
}
- return defaultValueEncoders.mapEncodeValue(r, dw, rv, collisionFn)
+ return defaultMapCodec.mapEncodeValue(r, dw, rv, collisionFn)
}
return dw.WriteDocumentEnd()
@@ -133,13 +185,17 @@ func (sc *StructCodec) DecodeValue(r DecodeContext, vr bsonrw.ValueReader, val r
return err
}
+ if sc.DecodeZeroStruct {
+ val.Set(reflect.Zero(val.Type()))
+ }
+ if sc.DecodeDeepZeroInline && sd.inline {
+ val.Set(deepZero(val.Type()))
+ }
+
var decoder ValueDecoder
var inlineMap reflect.Value
if sd.inlineMap >= 0 {
inlineMap = val.Field(sd.inlineMap)
- if inlineMap.IsNil() {
- inlineMap.Set(reflect.MakeMap(inlineMap.Type()))
- }
decoder, err = r.LookupDecoder(inlineMap.Type().Elem())
if err != nil {
return err
@@ -179,6 +235,10 @@ func (sc *StructCodec) DecodeValue(r DecodeContext, vr bsonrw.ValueReader, val r
continue
}
+ if inlineMap.IsNil() {
+ inlineMap.Set(reflect.MakeMap(inlineMap.Type()))
+ }
+
elem := reflect.New(inlineMap.Type().Elem()).Elem()
err = decoder.DecodeValue(r, vr, elem)
if err != nil {
@@ -192,7 +252,10 @@ func (sc *StructCodec) DecodeValue(r DecodeContext, vr bsonrw.ValueReader, val r
if fd.inline == nil {
field = val.Field(fd.idx)
} else {
- field = val.FieldByIndex(fd.inline)
+ field, err = getInlineField(val, fd.inline)
+ if err != nil {
+ return err
+ }
}
if !field.CanSet() { // Being settable is a super set of being addressable.
@@ -249,6 +312,23 @@ func (sc *StructCodec) isZero(i interface{}) bool {
return v.Float() == 0
case reflect.Interface, reflect.Ptr:
return v.IsNil()
+ case reflect.Struct:
+ if sc.EncodeOmitDefaultStruct {
+ vt := v.Type()
+ if vt == tTime {
+ return v.Interface().(time.Time).IsZero()
+ }
+ for i := 0; i < v.NumField(); i++ {
+ if vt.Field(i).PkgPath != "" && !vt.Field(i).Anonymous {
+ continue // Private field
+ }
+ fld := v.Field(i)
+ if !sc.isZero(fld.Interface()) {
+ return false
+ }
+ }
+ return true
+ }
}
return false
@@ -258,6 +338,7 @@ type structDescription struct {
fm map[string]fieldDescription
fl []fieldDescription
inlineMap int
+ inline bool
}
type fieldDescription struct {
@@ -290,16 +371,17 @@ func (sc *StructCodec) describeStruct(r *Registry, t reflect.Type) (*structDescr
for i := 0; i < numFields; i++ {
sf := t.Field(i)
- if sf.PkgPath != "" {
- // unexported, ignore
+ if sf.PkgPath != "" && (!sc.AllowUnexportedFields || !sf.Anonymous) {
+ // field is private or unexported fields aren't allowed, ignore
continue
}
- encoder, err := r.LookupEncoder(sf.Type)
+ sfType := sf.Type
+ encoder, err := r.LookupEncoder(sfType)
if err != nil {
encoder = nil
}
- decoder, err := r.LookupDecoder(sf.Type)
+ decoder, err := r.LookupDecoder(sfType)
if err != nil {
decoder = nil
}
@@ -319,17 +401,24 @@ func (sc *StructCodec) describeStruct(r *Registry, t reflect.Type) (*structDescr
description.truncate = stags.Truncate
if stags.Inline {
- switch sf.Type.Kind() {
+ sd.inline = true
+ switch sfType.Kind() {
case reflect.Map:
if sd.inlineMap >= 0 {
return nil, errors.New("(struct " + t.String() + ") multiple inline maps")
}
- if sf.Type.Key() != tString {
+ if sfType.Key() != tString {
return nil, errors.New("(struct " + t.String() + ") inline map must have a string keys")
}
sd.inlineMap = description.idx
+ case reflect.Ptr:
+ sfType = sfType.Elem()
+ if sfType.Kind() != reflect.Struct {
+ return nil, fmt.Errorf("(struct %s) inline fields must be a struct, a struct pointer, or a map", t.String())
+ }
+ fallthrough
case reflect.Struct:
- inlinesf, err := sc.describeStruct(r, sf.Type)
+ inlinesf, err := sc.describeStruct(r, sfType)
if err != nil {
return nil, err
}
@@ -346,7 +435,7 @@ func (sc *StructCodec) describeStruct(r *Registry, t reflect.Type) (*structDescr
sd.fl = append(sd.fl, fd)
}
default:
- return nil, fmt.Errorf("(struct %s) inline fields must be either a struct or a map", t.String())
+ return nil, fmt.Errorf("(struct %s) inline fields must be a struct, a struct pointer, or a map", t.String())
}
continue
}
@@ -365,3 +454,75 @@ func (sc *StructCodec) describeStruct(r *Registry, t reflect.Type) (*structDescr
return sd, nil
}
+
+func fieldByIndexErr(v reflect.Value, index []int) (result reflect.Value, err error) {
+ defer func() {
+ if recovered := recover(); recovered != nil {
+ switch r := recovered.(type) {
+ case string:
+ err = fmt.Errorf("%s", r)
+ case error:
+ err = r
+ }
+ }
+ }()
+
+ result = v.FieldByIndex(index)
+ return
+}
+
+func getInlineField(val reflect.Value, index []int) (reflect.Value, error) {
+ field, err := fieldByIndexErr(val, index)
+ if err == nil {
+ return field, nil
+ }
+
+ // if parent of this element doesn't exist, fix its parent
+ inlineParent := index[:len(index)-1]
+ var fParent reflect.Value
+ if fParent, err = fieldByIndexErr(val, inlineParent); err != nil {
+ fParent, err = getInlineField(val, inlineParent)
+ if err != nil {
+ return fParent, err
+ }
+ }
+ fParent.Set(reflect.New(fParent.Type().Elem()))
+
+ return fieldByIndexErr(val, index)
+}
+
+// DeepZero returns recursive zero object
+func deepZero(st reflect.Type) (result reflect.Value) {
+ result = reflect.Indirect(reflect.New(st))
+
+ if result.Kind() == reflect.Struct {
+ for i := 0; i < result.NumField(); i++ {
+ if f := result.Field(i); f.Kind() == reflect.Ptr {
+ if f.CanInterface() {
+ if ft := reflect.TypeOf(f.Interface()); ft.Elem().Kind() == reflect.Struct {
+ result.Field(i).Set(recursivePointerTo(deepZero(ft.Elem())))
+ }
+ }
+ }
+ }
+ }
+
+ return
+}
+
+// recursivePointerTo calls reflect.New(v.Type) but recursively for its fields inside
+func recursivePointerTo(v reflect.Value) reflect.Value {
+ v = reflect.Indirect(v)
+ result := reflect.New(v.Type())
+ if v.Kind() == reflect.Struct {
+ for i := 0; i < v.NumField(); i++ {
+ if f := v.Field(i); f.Kind() == reflect.Ptr {
+ if f.Elem().Kind() == reflect.Struct {
+ result.Elem().Field(i).Set(recursivePointerTo(f))
+ }
+ }
+ }
+ }
+
+ return result
+}
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/time_codec.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/time_codec.go
new file mode 100644
index 00000000000..fb80c7558bf
--- /dev/null
+++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/time_codec.go
@@ -0,0 +1,98 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package bsoncodec
+
+import (
+ "fmt"
+ "reflect"
+ "time"
+
+ "go.mongodb.org/mongo-driver/bson/bsonoptions"
+ "go.mongodb.org/mongo-driver/bson/bsonrw"
+ "go.mongodb.org/mongo-driver/bson/bsontype"
+)
+
+const (
+ timeFormatString = "2006-01-02T15:04:05.999Z07:00"
+)
+
+var defaultTimeCodec = NewTimeCodec()
+
+// TimeCodec is the Codec used for time.Time values.
+type TimeCodec struct {
+ UseLocalTimeZone bool
+}
+
+var _ ValueCodec = &TimeCodec{}
+
+// NewTimeCodec returns a TimeCodec with options opts.
+func NewTimeCodec(opts ...*bsonoptions.TimeCodecOptions) *TimeCodec {
+ timeOpt := bsonoptions.MergeTimeCodecOptions(opts...)
+
+ codec := TimeCodec{}
+ if timeOpt.UseLocalTimeZone != nil {
+ codec.UseLocalTimeZone = *timeOpt.UseLocalTimeZone
+ }
+ return &codec
+}
+
+// DecodeValue is the ValueDecoderFunc for time.Time.
+func (tc *TimeCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
+ if !val.CanSet() || val.Type() != tTime {
+ return ValueDecoderError{Name: "TimeDecodeValue", Types: []reflect.Type{tTime}, Received: val}
+ }
+
+ var timeVal time.Time
+ valueType := vr.Type()
+ switch valueType {
+ case bsontype.DateTime:
+ dt, err := vr.ReadDateTime()
+ if err != nil {
+ return err
+ }
+ timeVal = time.Unix(dt/1000, dt%1000*1000000)
+ case bsontype.String:
+ // assume strings are in the isoTimeFormat
+ timeStr, err := vr.ReadString()
+ if err != nil {
+ return err
+ }
+ timeVal, err = time.Parse(timeFormatString, timeStr)
+ if err != nil {
+ return err
+ }
+ case bsontype.Int64:
+ i64, err := vr.ReadInt64()
+ if err != nil {
+ return err
+ }
+ timeVal = time.Unix(i64/1000, i64%1000*1000000)
+ case bsontype.Timestamp:
+ t, _, err := vr.ReadTimestamp()
+ if err != nil {
+ return err
+ }
+ timeVal = time.Unix(int64(t), 0)
+ default:
+ return fmt.Errorf("cannot decode %v into a time.Time", valueType)
+ }
+
+ if !tc.UseLocalTimeZone {
+ timeVal = timeVal.UTC()
+ }
+ val.Set(reflect.ValueOf(timeVal))
+ return nil
+}
+
+// EncodeValue is the ValueEncoderFunc for time.TIme.
+func (tc *TimeCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
+ if !val.IsValid() || val.Type() != tTime {
+ return ValueEncoderError{Name: "TimeEncodeValue", Types: []reflect.Type{tTime}, Received: val}
+ }
+ tt := val.Interface().(time.Time)
+ return vw.WriteDateTime(tt.Unix()*1000 + int64(tt.Nanosecond()/1e6))
+}
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/map_codec_options.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/map_codec_options.go
new file mode 100644
index 00000000000..981ba787825
--- /dev/null
+++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/map_codec_options.go
@@ -0,0 +1,38 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package bsonoptions
+
+// MapCodecOptions represents all possible options for map encoding and decoding.
+type MapCodecOptions struct {
+ DecodeZerosMap *bool // Specifies if the map should be zeroed before decoding into it. Defaults to false.
+}
+
+// MapCodec creates a new *MapCodecOptions
+func MapCodec() *MapCodecOptions {
+ return &MapCodecOptions{}
+}
+
+// SetDecodeZerosMap specifies if the map should be zeroed before decoding into it. Defaults to false.
+func (t *MapCodecOptions) SetDecodeZerosMap(b bool) *MapCodecOptions {
+ t.DecodeZerosMap = &b
+ return t
+}
+
+// MergeMapCodecOptions combines the given *MapCodecOptions into a single *MapCodecOptions in a last one wins fashion.
+func MergeMapCodecOptions(opts ...*MapCodecOptions) *MapCodecOptions {
+ s := MapCodec()
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+ if opt.DecodeZerosMap != nil {
+ s.DecodeZerosMap = opt.DecodeZerosMap
+ }
+ }
+
+ return s
+}
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/string_codec_options.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/string_codec_options.go
new file mode 100644
index 00000000000..65964f4207d
--- /dev/null
+++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/string_codec_options.go
@@ -0,0 +1,41 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package bsonoptions
+
+var defaultDecodeOIDAsHex = true
+
+// StringCodecOptions represents all possible options for string encoding and decoding.
+type StringCodecOptions struct {
+ DecodeObjectIDAsHex *bool // Specifies if we should decode ObjectID as the hex value. Defaults to true.
+}
+
+// StringCodec creates a new *StringCodecOptions
+func StringCodec() *StringCodecOptions {
+ return &StringCodecOptions{}
+}
+
+// SetDecodeObjectIDAsHex specifies if object IDs should be decoded as their hex representation. If false, a string made
+// from the raw object ID bytes will be used. Defaults to true.
+func (t *StringCodecOptions) SetDecodeObjectIDAsHex(b bool) *StringCodecOptions {
+ t.DecodeObjectIDAsHex = &b
+ return t
+}
+
+// MergeStringCodecOptions combines the given *StringCodecOptions into a single *StringCodecOptions in a last one wins fashion.
+func MergeStringCodecOptions(opts ...*StringCodecOptions) *StringCodecOptions {
+ s := &StringCodecOptions{&defaultDecodeOIDAsHex}
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+ if opt.DecodeObjectIDAsHex != nil {
+ s.DecodeObjectIDAsHex = opt.DecodeObjectIDAsHex
+ }
+ }
+
+ return s
+}
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/struct_codec_options.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/struct_codec_options.go
new file mode 100644
index 00000000000..ad32c7c3824
--- /dev/null
+++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/struct_codec_options.go
@@ -0,0 +1,70 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package bsonoptions
+
+// StructCodecOptions represents all possible options for struct encoding and decoding.
+type StructCodecOptions struct {
+ DecodeZeroStruct *bool // Specifies if structs should be zeroed before decoding into them. Defaults to false.
+ DecodeDeepZeroInline *bool // Specifies if structs should be recursively zeroed when a inline value is decoded. Defaults to false.
+ EncodeOmitDefaultStruct *bool // Specifies if default structs should be considered empty by omitempty. Defaults to false.
+ AllowUnexportedFields *bool // Specifies if unexported fields should be marshaled/unmarshaled. Defaults to false.
+}
+
+// StructCodec creates a new *StructCodecOptions
+func StructCodec() *StructCodecOptions {
+ return &StructCodecOptions{}
+}
+
+// SetDecodeZeroStruct specifies if structs should be zeroed before decoding into them. Defaults to false.
+func (t *StructCodecOptions) SetDecodeZeroStruct(b bool) *StructCodecOptions {
+ t.DecodeZeroStruct = &b
+ return t
+}
+
+// SetDecodeDeepZeroInline specifies if structs should be zeroed before decoding into them. Defaults to false.
+func (t *StructCodecOptions) SetDecodeDeepZeroInline(b bool) *StructCodecOptions {
+ t.DecodeDeepZeroInline = &b
+ return t
+}
+
+// SetEncodeOmitDefaultStruct specifies if default structs should be considered empty by omitempty. A default struct has all
+// its values set to their default value. Defaults to false.
+func (t *StructCodecOptions) SetEncodeOmitDefaultStruct(b bool) *StructCodecOptions {
+ t.EncodeOmitDefaultStruct = &b
+ return t
+}
+
+// SetAllowUnexportedFields specifies if unexported fields should be marshaled/unmarshaled. Defaults to false.
+func (t *StructCodecOptions) SetAllowUnexportedFields(b bool) *StructCodecOptions {
+ t.AllowUnexportedFields = &b
+ return t
+}
+
+// MergeStructCodecOptions combines the given *StructCodecOptions into a single *StructCodecOptions in a last one wins fashion.
+func MergeStructCodecOptions(opts ...*StructCodecOptions) *StructCodecOptions {
+ s := StructCodec()
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+
+ if opt.DecodeZeroStruct != nil {
+ s.DecodeZeroStruct = opt.DecodeZeroStruct
+ }
+ if opt.DecodeDeepZeroInline != nil {
+ s.DecodeDeepZeroInline = opt.DecodeDeepZeroInline
+ }
+ if opt.EncodeOmitDefaultStruct != nil {
+ s.EncodeOmitDefaultStruct = opt.EncodeOmitDefaultStruct
+ }
+ if opt.AllowUnexportedFields != nil {
+ s.AllowUnexportedFields = opt.AllowUnexportedFields
+ }
+ }
+
+ return s
+}
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/time_codec_options.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/time_codec_options.go
new file mode 100644
index 00000000000..13496d12179
--- /dev/null
+++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/time_codec_options.go
@@ -0,0 +1,38 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package bsonoptions
+
+// TimeCodecOptions represents all possible options for time.Time encoding and decoding.
+type TimeCodecOptions struct {
+ UseLocalTimeZone *bool // Specifies if we should decode into the local time zone. Defaults to false.
+}
+
+// TimeCodec creates a new *TimeCodecOptions
+func TimeCodec() *TimeCodecOptions {
+ return &TimeCodecOptions{}
+}
+
+// SetUseLocalTimeZone specifies if we should decode into the local time zone. Defaults to false.
+func (t *TimeCodecOptions) SetUseLocalTimeZone(b bool) *TimeCodecOptions {
+ t.UseLocalTimeZone = &b
+ return t
+}
+
+// MergeTimeCodecOptions combines the given *TimeCodecOptions into a single *TimeCodecOptions in a last one wins fashion.
+func MergeTimeCodecOptions(opts ...*TimeCodecOptions) *TimeCodecOptions {
+ t := TimeCodec()
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+ if opt.UseLocalTimeZone != nil {
+ t.UseLocalTimeZone = opt.UseLocalTimeZone
+ }
+ }
+
+ return t
+}
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_wrappers.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_wrappers.go
index e6ca0e038a9..7ee09431139 100644
--- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_wrappers.go
+++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_wrappers.go
@@ -180,7 +180,13 @@ func (ejv *extJSONValue) parseDBPointer() (ns string, oid primitive.ObjectID, er
return ns, oid, nil
}
-const rfc3339Milli = "2006-01-02T15:04:05.999Z07:00"
+const (
+ rfc3339Milli = "2006-01-02T15:04:05.999Z07:00"
+)
+
+var (
+ timeFormats = []string{rfc3339Milli, "2006-01-02T15:04:05.999Z0700"}
+)
func (ejv *extJSONValue) parseDateTime() (int64, error) {
switch ejv.t {
@@ -198,7 +204,15 @@ func (ejv *extJSONValue) parseDateTime() (int64, error) {
}
func parseDatetimeString(data string) (int64, error) {
- t, err := time.Parse(rfc3339Milli, data)
+ var t time.Time
+ var err error
+ // try acceptable time formats until one matches
+ for _, format := range timeFormats {
+ t, err = time.Parse(format, data)
+ if err == nil {
+ break
+ }
+ }
if err != nil {
return 0, fmt.Errorf("invalid $date value string: %s", data)
}
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_writer.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_writer.go
index b34b937379d..605e41a138c 100644
--- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_writer.go
+++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_writer.go
@@ -536,7 +536,10 @@ func (ejvw *extJSONValueWriter) WriteUndefined() error {
func (ejvw *extJSONValueWriter) WriteDocumentElement(key string) (ValueWriter, error) {
switch ejvw.stack[ejvw.frame].mode {
case mDocument, mTopLevel, mCodeWithScope:
- ejvw.buf = append(ejvw.buf, []byte(fmt.Sprintf(`"%s":`, key))...)
+ var buf bytes.Buffer
+ writeStringWithEscapes(key, &buf, ejvw.escapeHTML)
+
+ ejvw.buf = append(ejvw.buf, []byte(fmt.Sprintf(`%s:`, buf.String()))...)
ejvw.push(mElement)
default:
return nil, ejvw.invalidTransitionErr(mElement, "WriteDocumentElement", []mode{mDocument, mTopLevel, mCodeWithScope})
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/value_writer.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/value_writer.go
index caa6fae3aa2..37171983663 100644
--- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/value_writer.go
+++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/value_writer.go
@@ -56,6 +56,13 @@ func (bvwp *BSONValueWriterPool) Get(w io.Writer) ValueWriter {
return vw
}
+// GetAtModeElement retrieves a ValueWriterFlusher from the pool and resets it to use w as the destination.
+func (bvwp *BSONValueWriterPool) GetAtModeElement(w io.Writer) ValueWriterFlusher {
+ vw := bvwp.Get(w).(*valueWriter)
+ vw.push(mElement)
+ return vw
+}
+
// Put inserts a ValueWriter into the pool. If the ValueWriter is not a BSON ValueWriter, nothing
// happens and ok will be false.
func (bvwp *BSONValueWriterPool) Put(vw ValueWriter) (ok bool) {
@@ -512,17 +519,8 @@ func (vw *valueWriter) WriteDocumentEnd() error {
}
if vw.stack[vw.frame].mode == mTopLevel {
- if vw.w != nil {
- if sw, ok := vw.w.(*SliceWriter); ok {
- *sw = vw.buf
- } else {
- _, err = vw.w.Write(vw.buf)
- if err != nil {
- return err
- }
- // reset buffer
- vw.buf = vw.buf[:0]
- }
+ if err = vw.Flush(); err != nil {
+ return err
}
}
@@ -537,6 +535,23 @@ func (vw *valueWriter) WriteDocumentEnd() error {
return nil
}
+func (vw *valueWriter) Flush() error {
+ if vw.w == nil {
+ return nil
+ }
+
+ if sw, ok := vw.w.(*SliceWriter); ok {
+ *sw = vw.buf
+ return nil
+ }
+ if _, err := vw.w.Write(vw.buf); err != nil {
+ return err
+ }
+ // reset buffer
+ vw.buf = vw.buf[:0]
+ return nil
+}
+
func (vw *valueWriter) WriteArrayElement() (ValueWriter, error) {
if vw.stack[vw.frame].mode != mArray {
return nil, vw.invalidTransitionError(mValue, "WriteArrayElement", []mode{mArray})
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/writer.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/writer.go
index 128b79bdfa0..7644df12909 100644
--- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/writer.go
+++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/writer.go
@@ -55,6 +55,12 @@ type ValueWriter interface {
WriteUndefined() error
}
+// ValueWriterFlusher is a superset of ValueWriter that exposes functionality to flush to the underlying buffer.
+type ValueWriterFlusher interface {
+ ValueWriter
+ Flush() error
+}
+
// BytesWriter is the interface used to write BSON bytes to a ValueWriter.
// This interface is meant to be a superset of ValueWriter, so that types that
// implement ValueWriter may also implement this interface.
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/decoder.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/decoder.go
index 550541e941a..7f6b7694f9c 100644
--- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/decoder.go
+++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/decoder.go
@@ -78,13 +78,19 @@ func (d *Decoder) Decode(val interface{}) error {
}
rval := reflect.ValueOf(val)
- if rval.Kind() != reflect.Ptr {
- return fmt.Errorf("argument to Decode must be a pointer to a type, but got %v", rval)
- }
- if rval.IsNil() {
- return ErrDecodeToNil
+ switch rval.Kind() {
+ case reflect.Ptr:
+ if rval.IsNil() {
+ return ErrDecodeToNil
+ }
+ rval = rval.Elem()
+ case reflect.Map:
+ if rval.IsNil() {
+ return ErrDecodeToNil
+ }
+ default:
+ return fmt.Errorf("argument to Decode must be a pointer or a map, but got %v", rval)
}
- rval = rval.Elem()
decoder, err := d.dc.LookupDecoder(rval.Type())
if err != nil {
return err
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/doc.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/doc.go
index b3f6c52ffb7..ee15315d103 100644
--- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/doc.go
+++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/doc.go
@@ -4,8 +4,10 @@
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
-// Package bson is a library for reading, writing, and manipulating BSON. The
-// library has two families of types for representing BSON.
+// Package bson is a library for reading, writing, and manipulating BSON. BSON is a binary serialization format used to
+// store documents and make remote procedure calls in MongoDB. The BSON specification is located at https://bsonspec.org.
+//
+// Raw BSON
//
// The Raw family of types is used to validate and retrieve elements from a slice of bytes. This
// type is most useful when you want do lookups on BSON bytes without unmarshaling it into another
@@ -19,24 +21,96 @@
// i32, ok := val.Int32OK()
// // do something with i32...
//
-// The D family of types is used to build concise representations of BSON using native Go types.
-// These types do not support automatic lookup.
+// Native Go Types
+//
+// The D and M types defined in this package can be used to build representations of BSON using native Go types. D is a
+// slice and M is a map. For more information about the use cases for these types, see the documentation on the type
+// definitions.
//
// Example:
// bson.D{{"foo", "bar"}, {"hello", "world"}, {"pi", 3.14159}}
+// bson.M{"foo": "bar", "hello": "world", "pi": 3.14159}
//
+// When decoding BSON to a D or M, the following type mappings apply when unmarshalling:
//
-// Marshaling and Unmarshaling are handled with the Marshal and Unmarshal family of functions. If
-// you need to write or read BSON from a non-slice source, an Encoder or Decoder can be used with a
-// bsonrw.ValueWriter or bsonrw.ValueReader.
+// 1. BSON int32 unmarshals to an int32.
+// 2. BSON int64 unmarshals to an int64.
+// 3. BSON double unmarshals to a float64.
+// 4. BSON string unmarshals to a string.
+// 5. BSON boolean unmarshals to a bool.
+// 6. BSON embedded document unmarshals to the parent type (i.e. D for a D, M for an M).
+// 7. BSON array unmarshals to a bson.A.
+// 8. BSON ObjectId unmarshals to a primitive.ObjectID.
+// 9. BSON datetime unmarshals to a primitive.Datetime.
+// 10. BSON binary unmarshals to a primitive.Binary.
+// 11. BSON regular expression unmarshals to a primitive.Regex.
+// 12. BSON JavaScript unmarshals to a primitive.JavaScript.
+// 13. BSON code with scope unmarshals to a primitive.CodeWithScope.
+// 14. BSON timestamp unmarshals to an primitive.Timestamp.
+// 15. BSON 128-bit decimal unmarshals to an primitive.Decimal128.
+// 16. BSON min key unmarshals to an primitive.MinKey.
+// 17. BSON max key unmarshals to an primitive.MaxKey.
+// 18. BSON undefined unmarshals to a primitive.Undefined.
+// 19. BSON null unmarshals to a primitive.Null.
+// 20. BSON DBPointer unmarshals to a primitive.DBPointer.
+// 21. BSON symbol unmarshals to a primitive.Symbol.
//
-// Example:
-// b, err := bson.Marshal(bson.D{{"foo", "bar"}})
-// if err != nil { return err }
-// var fooer struct {
-// Foo string
-// }
-// err = bson.Unmarshal(b, &fooer)
-// if err != nil { return err }
-// // do something with fooer...
+// The above mappings also apply when marshalling a D or M to BSON. Some other useful marshalling mappings are:
+//
+// 1. time.Time marshals to a BSON datetime.
+// 2. int8, int16, and int32 marshal to a BSON int32.
+// 3. int marshals to a BSON int32 if the value is between math.MinInt32 and math.MaxInt32, inclusive, and a BSON int64
+// otherwise.
+// 4. int64 marshals to BSON int64.
+// 5. uint8 and uint16 marshal to a BSON int32.
+// 6. uint, uint32, and uint64 marshal to a BSON int32 if the value is between math.MinInt32 and math.MaxInt32,
+// inclusive, and BSON int64 otherwise.
+//
+// Structs
+//
+// Structs can be marshalled/unmarshalled to/from BSON. When transforming structs to/from BSON, the following rules
+// apply:
+//
+// 1. Only exported fields in structs will be marshalled or unmarshalled.
+//
+// 2. When marshalling a struct, each field will be lowercased to generate the key for the corresponding BSON element.
+// For example, a struct field named "Foo" will generate key "foo". This can be overriden via a struct tag (e.g.
+// `bson:"fooField"` to generate key "fooField" instead).
+//
+// 3. An embedded struct field is marshalled as a subdocument. The key will be the lowercased name of the field's type.
+//
+// 4. A pointer field is marshalled as the underlying type if the pointer is non-nil. If the pointer is nil, it is
+// marshalled as a BSON null value.
+//
+// 5. When unmarshalling, a field of type interface{} will follow the D/M type mappings listed above. BSON documents
+// unmarshalled into an interface{} field will be unmarshalled as a D.
+//
+// The following struct tags can be used to configure behavior:
+//
+// 1. omitempty: If the omitempty struct tag is specified on a field, the field will not be marshalled if it is set to
+// the zero value. By default, a struct field is only considered empty if the field's type implements the Zeroer
+// interface and the IsZero method returns true. Struct fields of types that do not implement Zeroer are always
+// marshalled as embedded documents.
+//
+// 2. minsize: If the minsize struct tag is specified on a field of type int64, uint, uint32, or uint64 and the value of
+// the field can fit in a signed int32, the field will be serialized as a BSON int32 rather than a BSON int64. For other
+// types, this tag is ignored.
+//
+// 3. truncate: If the truncate struct tag is specified on a field with a non-float numeric type, BSON doubles unmarshalled
+// into that field will be trucated at the decimal point. For example, if 3.14 is unmarshalled into a field of type int,
+// it will be unmarshalled as 3. If this tag is not specified, the decoder will throw an error if the value cannot be
+// decoded without losing precision. For float64 or non-numeric types, this tag is ignored.
+//
+// 4. inline: If the inline struct tag is specified for a struct or map field, the field will be "flattened" when
+// marshalling and "un-flattened" when unmarshalling. This means that all of the fields in that struct/map will be
+// pulled up one level and will become top-level fields rather than being fields in a nested document. For example, if a
+// map field named "Map" with value map[string]interface{}{"foo": "bar"} is inlined, the resulting document will be
+// {"foo": "bar"} instead of {"map": {"foo": "bar"}}. There can only be one inlined map field in a struct. If there are
+// duplicated fields in the resulting document when an inlined field is marshalled, an error will be returned. This tag
+// can be used with fields that are pointers to structs. If an inlined pointer field is nil, it will not be marshalled.
+// For fields that are not maps or structs, this tag is ignored.
+//
+// Marshalling and Unmarshalling
+//
+// Manually marshalling and unmarshalling can be done with the Marshal and Unmarshal family of functions.
package bson
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/marshal.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/marshal.go
index 9a4e28d4b90..381822af53e 100644
--- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/marshal.go
+++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/marshal.go
@@ -32,7 +32,8 @@ type ValueMarshaler interface {
MarshalBSONValue() (bsontype.Type, []byte, error)
}
-// Marshal returns the BSON encoding of val.
+// Marshal returns the BSON encoding of val as a BSON document. If val is not a type that can be transformed into a
+// document, MarshalValue should be used instead.
//
// Marshal will use the default registry created by NewRegistry to recursively
// marshal val into a []byte. Marshal will inspect struct tags and alter the
@@ -41,34 +42,37 @@ func Marshal(val interface{}) ([]byte, error) {
return MarshalWithRegistry(DefaultRegistry, val)
}
-// MarshalAppend will append the BSON encoding of val to dst. If dst is not
-// large enough to hold the BSON encoding of val, dst will be grown.
+// MarshalAppend will encode val as a BSON document and append the bytes to dst. If dst is not large enough to hold the
+// bytes, it will be grown. If val is not a type that can be transformed into a document, MarshalValueAppend should be
+// used instead.
func MarshalAppend(dst []byte, val interface{}) ([]byte, error) {
return MarshalAppendWithRegistry(DefaultRegistry, dst, val)
}
-// MarshalWithRegistry returns the BSON encoding of val using Registry r.
+// MarshalWithRegistry returns the BSON encoding of val as a BSON document. If val is not a type that can be transformed
+// into a document, MarshalValueWithRegistry should be used instead.
func MarshalWithRegistry(r *bsoncodec.Registry, val interface{}) ([]byte, error) {
dst := make([]byte, 0, 256) // TODO: make the default cap a constant
return MarshalAppendWithRegistry(r, dst, val)
}
-// MarshalWithContext returns the BSON encoding of val using EncodeContext ec.
+// MarshalWithContext returns the BSON encoding of val as a BSON document using EncodeContext ec. If val is not a type
+// that can be transformed into a document, MarshalValueWithContext should be used instead.
func MarshalWithContext(ec bsoncodec.EncodeContext, val interface{}) ([]byte, error) {
dst := make([]byte, 0, 256) // TODO: make the default cap a constant
return MarshalAppendWithContext(ec, dst, val)
}
-// MarshalAppendWithRegistry will append the BSON encoding of val to dst using
-// Registry r. If dst is not large enough to hold the BSON encoding of val, dst
-// will be grown.
+// MarshalAppendWithRegistry will encode val as a BSON document using Registry r and append the bytes to dst. If dst is
+// not large enough to hold the bytes, it will be grown. If val is not a type that can be transformed into a document,
+// MarshalValueAppendWithRegistry should be used instead.
func MarshalAppendWithRegistry(r *bsoncodec.Registry, dst []byte, val interface{}) ([]byte, error) {
return MarshalAppendWithContext(bsoncodec.EncodeContext{Registry: r}, dst, val)
}
-// MarshalAppendWithContext will append the BSON encoding of val to dst using
-// EncodeContext ec. If dst is not large enough to hold the BSON encoding of val, dst
-// will be grown.
+// MarshalAppendWithContext will encode val as a BSON document using Registry r and EncodeContext ec and append the
+// bytes to dst. If dst is not large enough to hold the bytes, it will be grown. If val is not a type that can be
+// transformed into a document, MarshalValueAppendWithContext should be used instead.
func MarshalAppendWithContext(ec bsoncodec.EncodeContext, dst []byte, val interface{}) ([]byte, error) {
sw := new(bsonrw.SliceWriter)
*sw = dst
@@ -95,6 +99,69 @@ func MarshalAppendWithContext(ec bsoncodec.EncodeContext, dst []byte, val interf
return *sw, nil
}
+// MarshalValue returns the BSON encoding of val.
+//
+// MarshalValue will use bson.DefaultRegistry to transform val into a BSON value. If val is a struct, this function will
+// inspect struct tags and alter the marshalling process accordingly.
+func MarshalValue(val interface{}) (bsontype.Type, []byte, error) {
+ return MarshalValueWithRegistry(DefaultRegistry, val)
+}
+
+// MarshalValueAppend will append the BSON encoding of val to dst. If dst is not large enough to hold the BSON encoding
+// of val, dst will be grown.
+func MarshalValueAppend(dst []byte, val interface{}) (bsontype.Type, []byte, error) {
+ return MarshalValueAppendWithRegistry(DefaultRegistry, dst, val)
+}
+
+// MarshalValueWithRegistry returns the BSON encoding of val using Registry r.
+func MarshalValueWithRegistry(r *bsoncodec.Registry, val interface{}) (bsontype.Type, []byte, error) {
+ dst := make([]byte, 0, defaultDstCap)
+ return MarshalValueAppendWithRegistry(r, dst, val)
+}
+
+// MarshalValueWithContext returns the BSON encoding of val using EncodeContext ec.
+func MarshalValueWithContext(ec bsoncodec.EncodeContext, val interface{}) (bsontype.Type, []byte, error) {
+ dst := make([]byte, 0, defaultDstCap)
+ return MarshalValueAppendWithContext(ec, dst, val)
+}
+
+// MarshalValueAppendWithRegistry will append the BSON encoding of val to dst using Registry r. If dst is not large
+// enough to hold the BSON encoding of val, dst will be grown.
+func MarshalValueAppendWithRegistry(r *bsoncodec.Registry, dst []byte, val interface{}) (bsontype.Type, []byte, error) {
+ return MarshalValueAppendWithContext(bsoncodec.EncodeContext{Registry: r}, dst, val)
+}
+
+// MarshalValueAppendWithContext will append the BSON encoding of val to dst using EncodeContext ec. If dst is not large
+// enough to hold the BSON encoding of val, dst will be grown.
+func MarshalValueAppendWithContext(ec bsoncodec.EncodeContext, dst []byte, val interface{}) (bsontype.Type, []byte, error) {
+ // get a ValueWriter configured to write to dst
+ sw := new(bsonrw.SliceWriter)
+ *sw = dst
+ vwFlusher := bvwPool.GetAtModeElement(sw)
+
+ // get an Encoder and encode the value
+ enc := encPool.Get().(*Encoder)
+ defer encPool.Put(enc)
+ if err := enc.Reset(vwFlusher); err != nil {
+ return 0, nil, err
+ }
+ if err := enc.SetContext(ec); err != nil {
+ return 0, nil, err
+ }
+ if err := enc.Encode(val); err != nil {
+ return 0, nil, err
+ }
+
+ // flush the bytes written because we cannot guarantee that a full document has been written
+ // after the flush, *sw will be in the format
+ // [value type, 0 (null byte to indicate end of empty element name), value bytes..]
+ if err := vwFlusher.Flush(); err != nil {
+ return 0, nil, err
+ }
+ buffer := *sw
+ return bsontype.Type(buffer[0]), buffer[2:], nil
+}
+
// MarshalExtJSON returns the extended JSON encoding of val.
func MarshalExtJSON(val interface{}, canonical, escapeHTML bool) ([]byte, error) {
return MarshalExtJSONWithRegistry(DefaultRegistry, val, canonical, escapeHTML)
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/mgocompat/registry.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/mgocompat/registry.go
new file mode 100644
index 00000000000..eeaa4fb92b8
--- /dev/null
+++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/mgocompat/registry.go
@@ -0,0 +1,59 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package mgocompat
+
+import (
+ "reflect"
+ "time"
+
+ "go.mongodb.org/mongo-driver/bson"
+ "go.mongodb.org/mongo-driver/bson/bsoncodec"
+ "go.mongodb.org/mongo-driver/bson/bsonoptions"
+ "go.mongodb.org/mongo-driver/bson/bsontype"
+)
+
+var (
+ tInt = reflect.TypeOf(int(0))
+ tUint = reflect.TypeOf(uint(0))
+ tTime = reflect.TypeOf(time.Time{})
+ tM = reflect.TypeOf(bson.M{})
+ tInterfaceSlice = reflect.TypeOf([]interface{}{})
+ tByteSlice = reflect.TypeOf([]byte{})
+)
+
+// mgoRegistry is the default bsoncodec.Registry. It contains the default codecs and the
+// primitive codecs.
+var mgoRegistry = newRegistryBuilder().Build()
+
+// newRegistryBuilder creates a new RegistryBuilder configured with the default encoders and
+// deocders from the bsoncodec.DefaultValueEncoders and bsoncodec.DefaultValueDecoders types and the
+// PrimitiveCodecs type in this package.
+func newRegistryBuilder() *bsoncodec.RegistryBuilder {
+ rb := bsoncodec.NewRegistryBuilder()
+ bsoncodec.DefaultValueEncoders{}.RegisterDefaultEncoders(rb)
+ bsoncodec.DefaultValueDecoders{}.RegisterDefaultDecoders(rb)
+ bson.PrimitiveCodecs{}.RegisterPrimitiveCodecs(rb)
+
+ structcodec, _ := bsoncodec.NewStructCodec(bsoncodec.DefaultStructTagParser,
+ bsonoptions.StructCodec().
+ SetDecodeZeroStruct(true).
+ SetDecodeDeepZeroInline(true).
+ SetEncodeOmitDefaultStruct(true).
+ SetAllowUnexportedFields(true))
+
+ rb.RegisterDefaultDecoder(reflect.String, bsoncodec.NewStringCodec(bsonoptions.StringCodec().SetDecodeObjectIDAsHex(false))).
+ RegisterDefaultDecoder(reflect.Struct, structcodec).
+ RegisterDefaultDecoder(reflect.Map, bsoncodec.NewMapCodec(bsonoptions.MapCodec().SetDecodeZerosMap(true))).
+ RegisterDefaultEncoder(reflect.Struct, structcodec).
+ RegisterTypeMapEntry(bsontype.Int32, tInt).
+ RegisterTypeMapEntry(bsontype.Type(0), tM).
+ RegisterTypeMapEntry(bsontype.Binary, tByteSlice).
+ RegisterTypeMapEntry(bsontype.DateTime, tTime).
+ RegisterTypeMapEntry(bsontype.Array, tInterfaceSlice)
+
+ return rb
+}
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/primitive/decimal.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/primitive/decimal.go
index d7fdb228055..bd0c5d161a5 100644
--- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/primitive/decimal.go
+++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/primitive/decimal.go
@@ -10,11 +10,27 @@
package primitive
import (
+ "errors"
"fmt"
+ "math/big"
+ "regexp"
"strconv"
"strings"
)
+// These constants are the maximum and minimum values for the exponent field in a decimal128 value.
+const (
+ MaxDecimal128Exp = 6111
+ MinDecimal128Exp = -6176
+)
+
+// These errors are returned when an invalid value is parsed as a big.Int.
+var (
+ ErrParseNaN = errors.New("cannot parse NaN as a *big.Int")
+ ErrParseInf = errors.New("cannot parse Infinity as a *big.Int")
+ ErrParseNegInf = errors.New("cannot parse -Infinity as a *big.Int")
+)
+
// Decimal128 holds decimal128 BSON values.
type Decimal128 struct {
h, l uint64
@@ -25,7 +41,7 @@ func NewDecimal128(h, l uint64) Decimal128 {
return Decimal128{h: h, l: l}
}
-// GetBytes returns the underlying bytes of the BSON decimal value as two uint16 values. The first
+// GetBytes returns the underlying bytes of the BSON decimal value as two uint64 values. The first
// contains the most first 8 bytes of the value and the second contains the latter.
func (d Decimal128) GetBytes() (uint64, uint64) {
return d.h, d.l
@@ -33,52 +49,53 @@ func (d Decimal128) GetBytes() (uint64, uint64) {
// String returns a string representation of the decimal value.
func (d Decimal128) String() string {
- var pos int // positive sign
- var e int // exponent
- var h, l uint64 // significand high/low
+ var posSign int // positive sign
+ var exp int // exponent
+ var high, low uint64 // significand high/low
if d.h>>63&1 == 0 {
- pos = 1
+ posSign = 1
}
switch d.h >> 58 & (1<<5 - 1) {
case 0x1F:
return "NaN"
case 0x1E:
- return "-Infinity"[pos:]
+ return "-Infinity"[posSign:]
}
- l = d.l
+ low = d.l
if d.h>>61&3 == 3 {
// Bits: 1*sign 2*ignored 14*exponent 111*significand.
// Implicit 0b100 prefix in significand.
- e = int(d.h>>47&(1<<14-1)) - 6176
- //h = 4<<47 | d.h&(1<<47-1)
+ exp = int(d.h >> 47 & (1<<14 - 1))
+ //high = 4<<47 | d.h&(1<<47-1)
// Spec says all of these values are out of range.
- h, l = 0, 0
+ high, low = 0, 0
} else {
// Bits: 1*sign 14*exponent 113*significand
- e = int(d.h>>49&(1<<14-1)) - 6176
- h = d.h & (1<<49 - 1)
+ exp = int(d.h >> 49 & (1<<14 - 1))
+ high = d.h & (1<<49 - 1)
}
+ exp += MinDecimal128Exp
// Would be handled by the logic below, but that's trivial and common.
- if h == 0 && l == 0 && e == 0 {
- return "-0"[pos:]
+ if high == 0 && low == 0 && exp == 0 {
+ return "-0"[posSign:]
}
var repr [48]byte // Loop 5 times over 9 digits plus dot, negative sign, and leading zero.
var last = len(repr)
var i = len(repr)
- var dot = len(repr) + e
+ var dot = len(repr) + exp
var rem uint32
Loop:
for d9 := 0; d9 < 5; d9++ {
- h, l, rem = divmod(h, l, 1e9)
+ high, low, rem = divmod(high, low, 1e9)
for d1 := 0; d1 < 9; d1++ {
// Handle "-0.0", "0.00123400", "-1.00E-6", "1.050E+3", etc.
- if i < len(repr) && (dot == i || l == 0 && h == 0 && rem > 0 && rem < 10 && (dot < i-6 || e > 0)) {
- e += len(repr) - i
+ if i < len(repr) && (dot == i || low == 0 && high == 0 && rem > 0 && rem < 10 && (dot < i-6 || exp > 0)) {
+ exp += len(repr) - i
i--
repr[i] = '.'
last = i - 1
@@ -89,7 +106,7 @@ Loop:
i--
repr[i] = c
// Handle "0E+3", "1E+3", etc.
- if l == 0 && h == 0 && rem == 0 && i == len(repr)-1 && (dot < i-5 || e > 0) {
+ if low == 0 && high == 0 && rem == 0 && i == len(repr)-1 && (dot < i-5 || exp > 0) {
last = i
break Loop
}
@@ -97,7 +114,7 @@ Loop:
last = i
}
// Break early. Works without it, but why.
- if dot > i && l == 0 && h == 0 && rem == 0 {
+ if dot > i && low == 0 && high == 0 && rem == 0 {
break Loop
}
}
@@ -105,13 +122,88 @@ Loop:
repr[last-1] = '-'
last--
- if e > 0 {
- return string(repr[last+pos:]) + "E+" + strconv.Itoa(e)
+ if exp > 0 {
+ return string(repr[last+posSign:]) + "E+" + strconv.Itoa(exp)
}
- if e < 0 {
- return string(repr[last+pos:]) + "E" + strconv.Itoa(e)
+ if exp < 0 {
+ return string(repr[last+posSign:]) + "E" + strconv.Itoa(exp)
}
- return string(repr[last+pos:])
+ return string(repr[last+posSign:])
+}
+
+// BigInt returns significand as big.Int and exponent, bi * 10 ^ exp.
+func (d Decimal128) BigInt() (bi *big.Int, exp int, err error) {
+ high, low := d.GetBytes()
+ var posSign bool // positive sign
+
+ posSign = high>>63&1 == 0
+
+ switch high >> 58 & (1<<5 - 1) {
+ case 0x1F:
+ return nil, 0, ErrParseNaN
+ case 0x1E:
+ if posSign {
+ return nil, 0, ErrParseInf
+ }
+ return nil, 0, ErrParseNegInf
+ }
+
+ if high>>61&3 == 3 {
+ // Bits: 1*sign 2*ignored 14*exponent 111*significand.
+ // Implicit 0b100 prefix in significand.
+ exp = int(high >> 47 & (1<<14 - 1))
+ //high = 4<<47 | d.h&(1<<47-1)
+ // Spec says all of these values are out of range.
+ high, low = 0, 0
+ } else {
+ // Bits: 1*sign 14*exponent 113*significand
+ exp = int(high >> 49 & (1<<14 - 1))
+ high = high & (1<<49 - 1)
+ }
+ exp += MinDecimal128Exp
+
+ // Would be handled by the logic below, but that's trivial and common.
+ if high == 0 && low == 0 && exp == 0 {
+ if posSign {
+ return new(big.Int), 0, nil
+ }
+ return new(big.Int), 0, nil
+ }
+
+ bi = big.NewInt(0)
+ const host32bit = ^uint(0)>>32 == 0
+ if host32bit {
+ bi.SetBits([]big.Word{big.Word(low), big.Word(low >> 32), big.Word(high), big.Word(high >> 32)})
+ } else {
+ bi.SetBits([]big.Word{big.Word(low), big.Word(high)})
+ }
+
+ if !posSign {
+ return bi.Neg(bi), exp, nil
+ }
+ return
+}
+
+// IsNaN returns whether d is NaN.
+func (d Decimal128) IsNaN() bool {
+ return d.h>>58&(1<<5-1) == 0x1F
+}
+
+// IsInf returns:
+//
+// +1 d == Infinity
+// 0 other case
+// -1 d == -Infinity
+//
+func (d Decimal128) IsInf() int {
+ if d.h>>58&(1<<5-1) != 0x1E {
+ return 0
+ }
+
+ if d.h>>63&1 == 0 {
+ return 1
+ }
+ return -1
}
func divmod(h, l uint64, div uint32) (qh, ql uint64, rem uint32) {
@@ -139,19 +231,24 @@ func dErr(s string) (Decimal128, error) {
return dNaN, fmt.Errorf("cannot parse %q as a decimal128", s)
}
-//ParseDecimal128 takes the given string and attempts to parse it into a valid
+// match scientific notation number, example -10.15e-18
+var normalNumber = regexp.MustCompile(`^(?P<int>[-+]?\d*)?(?:\.(?P<dec>\d*))?(?:[Ee](?P<exp>[-+]?\d+))?$`)
+
+// ParseDecimal128 takes the given string and attempts to parse it into a valid
// Decimal128 value.
func ParseDecimal128(s string) (Decimal128, error) {
- orig := s
if s == "" {
- return dErr(orig)
- }
- neg := s[0] == '-'
- if neg || s[0] == '+' {
- s = s[1:]
+ return dErr(s)
}
- if (len(s) == 3 || len(s) == 8) && (s[0] == 'N' || s[0] == 'n' || s[0] == 'I' || s[0] == 'i') {
+ matches := normalNumber.FindStringSubmatch(s)
+ if len(matches) == 0 {
+ orig := s
+ neg := s[0] == '-'
+ if neg || s[0] == '+' {
+ s = s[1:]
+ }
+
if s == "NaN" || s == "nan" || strings.EqualFold(s, "nan") {
return dNaN, nil
}
@@ -164,144 +261,116 @@ func ParseDecimal128(s string) (Decimal128, error) {
return dErr(orig)
}
- var h, l uint64
- var e int
-
- var add, ovr uint32
- var mul uint32 = 1
- var dot = -1
- var digits = 0
- var i = 0
- for i < len(s) {
- c := s[i]
- if mul == 1e9 {
- h, l, ovr = muladd(h, l, mul, add)
- mul, add = 1, 0
- if ovr > 0 || h&((1<<15-1)<<49) > 0 {
- return dErr(orig)
- }
- }
- if c >= '0' && c <= '9' {
- i++
- if c > '0' || digits > 0 {
- digits++
- }
- if digits > 34 {
- if c == '0' {
- // Exact rounding.
- e++
- continue
- }
- return dErr(orig)
- }
- mul *= 10
- add *= 10
- add += uint32(c - '0')
- continue
- }
- if c == '.' {
- i++
- if dot >= 0 || i == 1 && len(s) == 1 {
- return dErr(orig)
- }
- if i == len(s) {
- break
- }
- if s[i] < '0' || s[i] > '9' || e > 0 {
- return dErr(orig)
- }
- dot = i
- continue
+ intPart := matches[1]
+ decPart := matches[2]
+ expPart := matches[3]
+
+ var err error
+ exp := 0
+ if expPart != "" {
+ exp, err = strconv.Atoi(expPart)
+ if err != nil {
+ return dErr(s)
}
- break
}
- if i == 0 {
- return dErr(orig)
+ if decPart != "" {
+ exp -= len(decPart)
}
- if mul > 1 {
- h, l, ovr = muladd(h, l, mul, add)
- if ovr > 0 || h&((1<<15-1)<<49) > 0 {
- return dErr(orig)
- }
+
+ if len(strings.Trim(intPart+decPart, "-0")) > 35 {
+ return dErr(s)
}
- if dot >= 0 {
- e += dot - i
+
+ bi, ok := new(big.Int).SetString(intPart+decPart, 10)
+ if !ok {
+ return dErr(s)
}
- if i+1 < len(s) && (s[i] == 'E' || s[i] == 'e') {
- i++
- eneg := s[i] == '-'
- if eneg || s[i] == '+' {
- i++
- if i == len(s) {
- return dErr(orig)
- }
- }
- n := 0
- for i < len(s) && n < 1e4 {
- c := s[i]
- i++
- if c < '0' || c > '9' {
- return dErr(orig)
- }
- n *= 10
- n += int(c - '0')
- }
- if eneg {
- n = -n
+
+ d, ok := ParseDecimal128FromBigInt(bi, exp)
+ if !ok {
+ return dErr(s)
+ }
+
+ if bi.Sign() == 0 && s[0] == '-' {
+ d.h |= 1 << 63
+ }
+
+ return d, nil
+}
+
+var (
+ ten = big.NewInt(10)
+ zero = new(big.Int)
+
+ maxS, _ = new(big.Int).SetString("9999999999999999999999999999999999", 10)
+)
+
+// ParseDecimal128FromBigInt attempts to parse the given significand and exponent into a valid Decimal128 value.
+func ParseDecimal128FromBigInt(bi *big.Int, exp int) (Decimal128, bool) {
+ //copy
+ bi = new(big.Int).Set(bi)
+
+ q := new(big.Int)
+ r := new(big.Int)
+
+ for bigIntCmpAbs(bi, maxS) == 1 {
+ bi, _ = q.QuoRem(bi, ten, r)
+ if r.Cmp(zero) != 0 {
+ return Decimal128{}, false
}
- e += n
- for e < -6176 {
- // Subnormal.
- var div uint32 = 1
- for div < 1e9 && e < -6176 {
- div *= 10
- e++
- }
- var rem uint32
- h, l, rem = divmod(h, l, div)
- if rem > 0 {
- return dErr(orig)
- }
+ exp++
+ if exp > MaxDecimal128Exp {
+ return Decimal128{}, false
}
- for e > 6111 {
- // Clamped.
- var mul uint32 = 1
- for mul < 1e9 && e > 6111 {
- mul *= 10
- e--
- }
- h, l, ovr = muladd(h, l, mul, 0)
- if ovr > 0 || h&((1<<15-1)<<49) > 0 {
- return dErr(orig)
- }
+ }
+
+ for exp < MinDecimal128Exp {
+ // Subnormal.
+ bi, _ = q.QuoRem(bi, ten, r)
+ if r.Cmp(zero) != 0 {
+ return Decimal128{}, false
}
- if e < -6176 || e > 6111 {
- return dErr(orig)
+ exp++
+ }
+ for exp > MaxDecimal128Exp {
+ // Clamped.
+ bi.Mul(bi, ten)
+ if bigIntCmpAbs(bi, maxS) == 1 {
+ return Decimal128{}, false
}
+ exp--
}
- if i < len(s) {
- return dErr(orig)
+ b := bi.Bytes()
+ var h, l uint64
+ for i := 0; i < len(b); i++ {
+ if i < len(b)-8 {
+ h = h<<8 | uint64(b[i])
+ continue
+ }
+ l = l<<8 | uint64(b[i])
}
- h |= uint64(e+6176) & uint64(1<<14-1) << 49
- if neg {
+ h |= uint64(exp-MinDecimal128Exp) & uint64(1<<14-1) << 49
+ if bi.Sign() == -1 {
h |= 1 << 63
}
- return Decimal128{h, l}, nil
-}
-func muladd(h, l uint64, mul uint32, add uint32) (resh, resl uint64, overflow uint32) {
- mul64 := uint64(mul)
- a := mul64 * (l & (1<<32 - 1))
- b := a>>32 + mul64*(l>>32)
- c := b>>32 + mul64*(h&(1<<32-1))
- d := c>>32 + mul64*(h>>32)
+ return Decimal128{h: h, l: l}, true
+}
- a = a&(1<<32-1) + uint64(add)
- b = b&(1<<32-1) + a>>32
- c = c&(1<<32-1) + b>>32
- d = d&(1<<32-1) + c>>32
+// bigIntCmpAbs computes big.Int.Cmp(absoluteValue(x), absoluteValue(y)).
+func bigIntCmpAbs(x, y *big.Int) int {
+ xAbs := bigIntAbsValue(x)
+ yAbs := bigIntAbsValue(y)
+ return xAbs.Cmp(yAbs)
+}
- return (d<<32 | c&(1<<32-1)), (b<<32 | a&(1<<32-1)), uint32(d >> 32)
+// bigIntAbsValue returns a big.Int containing the absolute value of b.
+// If b is already a non-negative number, it is returned without any changes or copies.
+func bigIntAbsValue(b *big.Int) *big.Int {
+ if b.Sign() >= 0 {
+ return b // already positive
+ }
+ return new(big.Int).Abs(b)
}
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/primitive/primitive.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/primitive/primitive.go
index 20a597d0e86..5ec457e069b 100644
--- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/primitive/primitive.go
+++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/go.mongodb.org/mongo-driver/bson/primitive/primitive.go
@@ -21,7 +21,7 @@ type Binary struct {
Data []byte
}
-// Equal compaes bp to bp2 and returns true is the are equal.
+// Equal compares bp to bp2 and returns true is the are equal.
func (bp Binary) Equal(bp2 Binary) bool {
if bp.Subtype != bp2.Subtype {
return false
@@ -29,6 +29,11 @@ func (bp Binary) Equal(bp2 Binary) bool {
return bytes.Equal(bp.Data, bp2.Data)
}
+// IsZero returns if bp is the empty Binary
+func (bp Binary) IsZero() bool {
+ return bp.Subtype == 0 && len(bp.Data) == 0
+}
+
// Undefined represents the BSON undefined value type.
type Undefined struct{}
@@ -50,7 +55,7 @@ func NewDateTimeFromTime(t time.Time) DateTime {
return DateTime(t.UnixNano() / 1000000)
}
-// Null repreesnts the BSON null value.
+// Null represents the BSON null value.
type Null struct{}
// Regex represents a BSON regex value.
@@ -63,11 +68,16 @@ func (rp Regex) String() string {
return fmt.Sprintf(`{"pattern": "%s", "options": "%s"}`, rp.Pattern, rp.Options)
}
-// Equal compaes rp to rp2 and returns true is the are equal.
+// Equal compares rp to rp2 and returns true is the are equal.
func (rp Regex) Equal(rp2 Regex) bool {
return rp.Pattern == rp2.Pattern && rp.Options == rp.Options
}
+// IsZero returns if rp is the empty Regex
+func (rp Regex) IsZero() bool {
+ return rp.Pattern == "" && rp.Options == ""
+}
+
// DBPointer represents a BSON dbpointer value.
type DBPointer struct {
DB string
@@ -78,11 +88,16 @@ func (d DBPointer) String() string {
return fmt.Sprintf(`{"db": "%s", "pointer": "%s"}`, d.DB, d.Pointer)
}
-// Equal compaes d to d2 and returns true is the are equal.
+// Equal compares d to d2 and returns true is the are equal.
func (d DBPointer) Equal(d2 DBPointer) bool {
return d.DB == d2.DB && bytes.Equal(d.Pointer[:], d2.Pointer[:])
}
+// IsZero returns if d is the empty DBPointer
+func (d DBPointer) IsZero() bool {
+ return d.DB == "" && d.Pointer.IsZero()
+}
+
// JavaScript represents a BSON JavaScript code value.
type JavaScript string
@@ -105,11 +120,16 @@ type Timestamp struct {
I uint32
}
-// Equal compaes tp to tp2 and returns true is the are equal.
+// Equal compares tp to tp2 and returns true is the are equal.
func (tp Timestamp) Equal(tp2 Timestamp) bool {
return tp.T == tp2.T && tp.I == tp2.I
}
+// IsZero returns if tp is the zero Timestamp
+func (tp Timestamp) IsZero() bool {
+ return tp.T == 0 && tp.I == 0
+}
+
// CompareTimestamp returns an integer comparing two Timestamps, where T is compared first, followed by I.
// Returns 0 if tp = tp2, 1 if tp > tp2, -1 if tp < tp2.
func CompareTimestamp(tp, tp2 Timestamp) int {
@@ -136,16 +156,12 @@ type MinKey struct{}
// MaxKey represents the BSON maxkey value.
type MaxKey struct{}
-// D represents a BSON Document. This type can be used to represent BSON in a concise and readable
-// manner. It should generally be used when serializing to BSON. For deserializing, the Raw or
-// Document types should be used.
+// D is an ordered representation of a BSON document. This type should be used when the order of the elements matters,
+// such as MongoDB command documents. If the order of the elements does not matter, an M should be used instead.
//
// Example usage:
//
-// primitive.D{{"foo", "bar"}, {"hello", "world"}, {"pi", 3.14159}}
-//
-// This type should be used in situations where order matters, such as MongoDB commands. If the
-// order is not important, a map is more comfortable and concise.
+// bson.D{{"foo", "bar"}, {"hello", "world"}, {"pi", 3.14159}}
type D []E
// Map creates a map from the elements of the D.
@@ -163,24 +179,18 @@ type E struct {
Value interface{}
}
-// M is an unordered, concise representation of a BSON Document. It should generally be used to
-// serialize BSON when the order of the elements of a BSON document do not matter. If the element
-// order matters, use a D instead.
+// M is an unordered representation of a BSON document. This type should be used when the order of the elements does not
+// matter. This type is handled as a regular map[string]interface{} when encoding and decoding. Elements will be
+// serialized in an undefined, random order. If the order of the elements matters, a D should be used instead.
//
// Example usage:
//
-// primitive.M{"foo": "bar", "hello": "world", "pi": 3.14159}
-//
-// This type is handled in the encoders as a regular map[string]interface{}. The elements will be
-// serialized in an undefined, random order, and the order will be different each time.
+// bson.M{"foo": "bar", "hello": "world", "pi": 3.14159}.
type M map[string]interface{}
-// An A represents a BSON array. This type can be used to represent a BSON array in a concise and
-// readable manner. It should generally be used when serializing to BSON. For deserializing, the
-// RawArray or Array types should be used.
+// An A is an ordered representation of a BSON array.
//
// Example usage:
//
-// primitive.A{"bar", "world", 3.14159, primitive.D{{"qux", 12345}}}
-//
+// bson.A{"bar", "world", 3.14159, bson.D{{"qux", 12345}}}
type A []interface{}