diff options
| author | 2024-03-06 09:05:45 -0800 | |
|---|---|---|
| committer | 2024-03-06 18:05:45 +0100 | |
| commit | fc3741365c27f1d703e8a736af95b95ff811cc45 (patch) | |
| tree | 929f1d5e20d1469d63a3dfe81d38d89f9a073c5a /vendor/go.mongodb.org/mongo-driver | |
| parent | [chore/bugfix] Little DB fixes (#2726) (diff) | |
| download | gotosocial-fc3741365c27f1d703e8a736af95b95ff811cc45.tar.xz | |
[bugfix] Fix Swagger spec and add test script (#2698)
* Add Swagger spec test script
* Fix Swagger spec errors not related to statuses with polls
* Add API tests that post a status with a poll
* Fix creating a status with a poll from form params
* Fix Swagger spec errors related to statuses with polls (this is the last error)
* Fix Swagger spec warnings not related to unused definitions
* Suppress a duplicate list update params definition that was somehow causing wrong param names
* Add Swagger test to CI
- updates Drone config
- vendorizes go-swagger
- fixes a file extension issue that caused the test script to generate JSON instead of YAML with the vendorized version
* Put `Sample: ` on its own line everywhere
* Remove unused id param from emojiCategoriesGet
* Add 5 more pairs of profile fields to account update API Swagger
* Remove Swagger prefix from dummy fields
It makes the generated code look weird
* Manually annotate params for statusCreate operation
* Fix all remaining Swagger spec warnings
- Change some models into operation parameters
- Ignore models that already correspond to manually documented operation parameters but can't be trivially changed (those with file fields)
* Documented that creating a status with scheduled_at isn't implemented yet
* sign drone.yml
* Fix filter API Swagger errors
* fixup! Fix filter API Swagger errors
---------
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Diffstat (limited to 'vendor/go.mongodb.org/mongo-driver')
68 files changed, 17506 insertions, 0 deletions
diff --git a/vendor/go.mongodb.org/mongo-driver/LICENSE b/vendor/go.mongodb.org/mongo-driver/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/LICENSE @@ -0,0 +1,201 @@ +                                 Apache License +                           Version 2.0, January 2004 +                        http://www.apache.org/licenses/ + +   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +   1. Definitions. + +      "License" shall mean the terms and conditions for use, reproduction, +      and distribution as defined by Sections 1 through 9 of this document. + +      "Licensor" shall mean the copyright owner or entity authorized by +      the copyright owner that is granting the License. + +      "Legal Entity" shall mean the union of the acting entity and all +      other entities that control, are controlled by, or are under common +      control with that entity. For the purposes of this definition, +      "control" means (i) the power, direct or indirect, to cause the +      direction or management of such entity, whether by contract or +      otherwise, or (ii) ownership of fifty percent (50%) or more of the +      outstanding shares, or (iii) beneficial ownership of such entity. + +      "You" (or "Your") shall mean an individual or Legal Entity +      exercising permissions granted by this License. + +      "Source" form shall mean the preferred form for making modifications, +      including but not limited to software source code, documentation +      source, and configuration files. + +      "Object" form shall mean any form resulting from mechanical +      transformation or translation of a Source form, including but +      not limited to compiled object code, generated documentation, +      and conversions to other media types. + +      "Work" shall mean the work of authorship, whether in Source or +      Object form, made available under the License, as indicated by a +      copyright notice that is included in or attached to the work +      (an example is provided in the Appendix below). + +      "Derivative Works" shall mean any work, whether in Source or Object +      form, that is based on (or derived from) the Work and for which the +      editorial revisions, annotations, elaborations, or other modifications +      represent, as a whole, an original work of authorship. For the purposes +      of this License, Derivative Works shall not include works that remain +      separable from, or merely link (or bind by name) to the interfaces of, +      the Work and Derivative Works thereof. + +      "Contribution" shall mean any work of authorship, including +      the original version of the Work and any modifications or additions +      to that Work or Derivative Works thereof, that is intentionally +      submitted to Licensor for inclusion in the Work by the copyright owner +      or by an individual or Legal Entity authorized to submit on behalf of +      the copyright owner. For the purposes of this definition, "submitted" +      means any form of electronic, verbal, or written communication sent +      to the Licensor or its representatives, including but not limited to +      communication on electronic mailing lists, source code control systems, +      and issue tracking systems that are managed by, or on behalf of, the +      Licensor for the purpose of discussing and improving the Work, but +      excluding communication that is conspicuously marked or otherwise +      designated in writing by the copyright owner as "Not a Contribution." + +      "Contributor" shall mean Licensor and any individual or Legal Entity +      on behalf of whom a Contribution has been received by Licensor and +      subsequently incorporated within the Work. + +   2. Grant of Copyright License. Subject to the terms and conditions of +      this License, each Contributor hereby grants to You a perpetual, +      worldwide, non-exclusive, no-charge, royalty-free, irrevocable +      copyright license to reproduce, prepare Derivative Works of, +      publicly display, publicly perform, sublicense, and distribute the +      Work and such Derivative Works in Source or Object form. + +   3. Grant of Patent License. Subject to the terms and conditions of +      this License, each Contributor hereby grants to You a perpetual, +      worldwide, non-exclusive, no-charge, royalty-free, irrevocable +      (except as stated in this section) patent license to make, have made, +      use, offer to sell, sell, import, and otherwise transfer the Work, +      where such license applies only to those patent claims licensable +      by such Contributor that are necessarily infringed by their +      Contribution(s) alone or by combination of their Contribution(s) +      with the Work to which such Contribution(s) was submitted. If You +      institute patent litigation against any entity (including a +      cross-claim or counterclaim in a lawsuit) alleging that the Work +      or a Contribution incorporated within the Work constitutes direct +      or contributory patent infringement, then any patent licenses +      granted to You under this License for that Work shall terminate +      as of the date such litigation is filed. + +   4. Redistribution. You may reproduce and distribute copies of the +      Work or Derivative Works thereof in any medium, with or without +      modifications, and in Source or Object form, provided that You +      meet the following conditions: + +      (a) You must give any other recipients of the Work or +          Derivative Works a copy of this License; and + +      (b) You must cause any modified files to carry prominent notices +          stating that You changed the files; and + +      (c) You must retain, in the Source form of any Derivative Works +          that You distribute, all copyright, patent, trademark, and +          attribution notices from the Source form of the Work, +          excluding those notices that do not pertain to any part of +          the Derivative Works; and + +      (d) If the Work includes a "NOTICE" text file as part of its +          distribution, then any Derivative Works that You distribute must +          include a readable copy of the attribution notices contained +          within such NOTICE file, excluding those notices that do not +          pertain to any part of the Derivative Works, in at least one +          of the following places: within a NOTICE text file distributed +          as part of the Derivative Works; within the Source form or +          documentation, if provided along with the Derivative Works; or, +          within a display generated by the Derivative Works, if and +          wherever such third-party notices normally appear. The contents +          of the NOTICE file are for informational purposes only and +          do not modify the License. You may add Your own attribution +          notices within Derivative Works that You distribute, alongside +          or as an addendum to the NOTICE text from the Work, provided +          that such additional attribution notices cannot be construed +          as modifying the License. + +      You may add Your own copyright statement to Your modifications and +      may provide additional or different license terms and conditions +      for use, reproduction, or distribution of Your modifications, or +      for any such Derivative Works as a whole, provided Your use, +      reproduction, and distribution of the Work otherwise complies with +      the conditions stated in this License. + +   5. Submission of Contributions. Unless You explicitly state otherwise, +      any Contribution intentionally submitted for inclusion in the Work +      by You to the Licensor shall be under the terms and conditions of +      this License, without any additional terms or conditions. +      Notwithstanding the above, nothing herein shall supersede or modify +      the terms of any separate license agreement you may have executed +      with Licensor regarding such Contributions. + +   6. Trademarks. This License does not grant permission to use the trade +      names, trademarks, service marks, or product names of the Licensor, +      except as required for reasonable and customary use in describing the +      origin of the Work and reproducing the content of the NOTICE file. + +   7. Disclaimer of Warranty. Unless required by applicable law or +      agreed to in writing, Licensor provides the Work (and each +      Contributor provides its Contributions) on an "AS IS" BASIS, +      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +      implied, including, without limitation, any warranties or conditions +      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +      PARTICULAR PURPOSE. You are solely responsible for determining the +      appropriateness of using or redistributing the Work and assume any +      risks associated with Your exercise of permissions under this License. + +   8. Limitation of Liability. In no event and under no legal theory, +      whether in tort (including negligence), contract, or otherwise, +      unless required by applicable law (such as deliberate and grossly +      negligent acts) or agreed to in writing, shall any Contributor be +      liable to You for damages, including any direct, indirect, special, +      incidental, or consequential damages of any character arising as a +      result of this License or out of the use or inability to use the +      Work (including but not limited to damages for loss of goodwill, +      work stoppage, computer failure or malfunction, or any and all +      other commercial damages or losses), even if such Contributor +      has been advised of the possibility of such damages. + +   9. Accepting Warranty or Additional Liability. While redistributing +      the Work or Derivative Works thereof, You may choose to offer, +      and charge a fee for, acceptance of support, warranty, indemnity, +      or other liability obligations and/or rights consistent with this +      License. However, in accepting such obligations, You may act only +      on Your own behalf and on Your sole responsibility, not on behalf +      of any other Contributor, and only if You agree to indemnify, +      defend, and hold each Contributor harmless for any liability +      incurred by, or claims asserted against, such Contributor by reason +      of your accepting any such warranty or additional liability. + +   END OF TERMS AND CONDITIONS + +   APPENDIX: How to apply the Apache License to your work. + +      To apply the Apache License to your work, attach the following +      boilerplate notice, with the fields enclosed by brackets "[]" +      replaced with your own identifying information. (Don't include +      the brackets!)  The text should be enclosed in the appropriate +      comment syntax for the file format. We also recommend that a +      file or class name and description of purpose be included on the +      same "printed page" as the copyright notice for easier +      identification within third-party archives. + +   Copyright [yyyy] [name of copyright owner] + +   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 + +   Unless required by applicable law or agreed to in writing, software +   distributed under the License is distributed on an "AS IS" BASIS, +   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +   See the License for the specific language governing permissions and +   limitations under the License. diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bson.go b/vendor/go.mongodb.org/mongo-driver/bson/bson.go new file mode 100644 index 000000000..a0d818582 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bson.go @@ -0,0 +1,50 @@ +// 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 +// +// Based on gopkg.in/mgo.v2/bson by Gustavo Niemeyer +// See THIRD-PARTY-NOTICES for original license terms. + +package bson // import "go.mongodb.org/mongo-driver/bson" + +import ( +	"go.mongodb.org/mongo-driver/bson/primitive" +) + +// Zeroer allows custom struct types to implement a report of zero +// state. All struct types that don't implement Zeroer or where IsZero +// returns false are considered to be not zero. +type Zeroer interface { +	IsZero() bool +} + +// 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. +// +// A D should not be constructed with duplicate key names, as that can cause undefined server behavior. +// +// Example usage: +// +//	bson.D{{"foo", "bar"}, {"hello", "world"}, {"pi", 3.14159}} +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 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} +type M = primitive.M + +// 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/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/array_codec.go b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/array_codec.go new file mode 100644 index 000000000..4e24f9eed --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/array_codec.go @@ -0,0 +1,50 @@ +// 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 ( +	"reflect" + +	"go.mongodb.org/mongo-driver/bson/bsonrw" +	"go.mongodb.org/mongo-driver/x/bsonx/bsoncore" +) + +// ArrayCodec is the Codec used for bsoncore.Array values. +type ArrayCodec struct{} + +var defaultArrayCodec = NewArrayCodec() + +// NewArrayCodec returns an ArrayCodec. +func NewArrayCodec() *ArrayCodec { +	return &ArrayCodec{} +} + +// EncodeValue is the ValueEncoder for bsoncore.Array values. +func (ac *ArrayCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Type() != tCoreArray { +		return ValueEncoderError{Name: "CoreArrayEncodeValue", Types: []reflect.Type{tCoreArray}, Received: val} +	} + +	arr := val.Interface().(bsoncore.Array) +	return bsonrw.Copier{}.CopyArrayFromBytes(vw, arr) +} + +// DecodeValue is the ValueDecoder for bsoncore.Array values. +func (ac *ArrayCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Type() != tCoreArray { +		return ValueDecoderError{Name: "CoreArrayDecodeValue", Types: []reflect.Type{tCoreArray}, Received: val} +	} + +	if val.IsNil() { +		val.Set(reflect.MakeSlice(val.Type(), 0, 0)) +	} + +	val.SetLen(0) +	arr, err := bsonrw.Copier{}.AppendArrayBytes(val.Interface().(bsoncore.Array), vr) +	val.Set(reflect.ValueOf(arr)) +	return err +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/bsoncodec.go b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/bsoncodec.go new file mode 100644 index 000000000..098ed69f9 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/bsoncodec.go @@ -0,0 +1,238 @@ +// 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 "go.mongodb.org/mongo-driver/bson/bsoncodec" + +import ( +	"fmt" +	"reflect" +	"strings" + +	"go.mongodb.org/mongo-driver/bson/bsonrw" +	"go.mongodb.org/mongo-driver/bson/bsontype" +	"go.mongodb.org/mongo-driver/bson/primitive" +) + +var ( +	emptyValue = reflect.Value{} +) + +// Marshaler is an interface implemented by types that can marshal themselves +// into a BSON document represented as bytes. The bytes returned must be a valid +// BSON document if the error is nil. +type Marshaler interface { +	MarshalBSON() ([]byte, error) +} + +// ValueMarshaler is an interface implemented by types that can marshal +// themselves into a BSON value as bytes. The type must be the valid type for +// the bytes returned. The bytes and byte type together must be valid if the +// error is nil. +type ValueMarshaler interface { +	MarshalBSONValue() (bsontype.Type, []byte, error) +} + +// Unmarshaler is an interface implemented by types that can unmarshal a BSON +// document representation of themselves. The BSON bytes can be assumed to be +// valid. UnmarshalBSON must copy the BSON bytes if it wishes to retain the data +// after returning. +type Unmarshaler interface { +	UnmarshalBSON([]byte) error +} + +// ValueUnmarshaler is an interface implemented by types that can unmarshal a +// BSON value representation of themselves. The BSON bytes and type can be +// assumed to be valid. UnmarshalBSONValue must copy the BSON value bytes if it +// wishes to retain the data after returning. +type ValueUnmarshaler interface { +	UnmarshalBSONValue(bsontype.Type, []byte) error +} + +// ValueEncoderError is an error returned from a ValueEncoder when the provided value can't be +// encoded by the ValueEncoder. +type ValueEncoderError struct { +	Name     string +	Types    []reflect.Type +	Kinds    []reflect.Kind +	Received reflect.Value +} + +func (vee ValueEncoderError) Error() string { +	typeKinds := make([]string, 0, len(vee.Types)+len(vee.Kinds)) +	for _, t := range vee.Types { +		typeKinds = append(typeKinds, t.String()) +	} +	for _, k := range vee.Kinds { +		if k == reflect.Map { +			typeKinds = append(typeKinds, "map[string]*") +			continue +		} +		typeKinds = append(typeKinds, k.String()) +	} +	received := vee.Received.Kind().String() +	if vee.Received.IsValid() { +		received = vee.Received.Type().String() +	} +	return fmt.Sprintf("%s can only encode valid %s, but got %s", vee.Name, strings.Join(typeKinds, ", "), received) +} + +// ValueDecoderError is an error returned from a ValueDecoder when the provided value can't be +// decoded by the ValueDecoder. +type ValueDecoderError struct { +	Name     string +	Types    []reflect.Type +	Kinds    []reflect.Kind +	Received reflect.Value +} + +func (vde ValueDecoderError) Error() string { +	typeKinds := make([]string, 0, len(vde.Types)+len(vde.Kinds)) +	for _, t := range vde.Types { +		typeKinds = append(typeKinds, t.String()) +	} +	for _, k := range vde.Kinds { +		if k == reflect.Map { +			typeKinds = append(typeKinds, "map[string]*") +			continue +		} +		typeKinds = append(typeKinds, k.String()) +	} +	received := vde.Received.Kind().String() +	if vde.Received.IsValid() { +		received = vde.Received.Type().String() +	} +	return fmt.Sprintf("%s can only decode valid and settable %s, but got %s", vde.Name, strings.Join(typeKinds, ", "), received) +} + +// EncodeContext is the contextual information required for a Codec to encode a +// value. +type EncodeContext struct { +	*Registry +	MinSize bool +} + +// DecodeContext is the contextual information required for a Codec to decode a +// value. +type DecodeContext struct { +	*Registry +	Truncate bool + +	// Ancestor is the type of a containing document. This is mainly used to determine what type +	// should be used when decoding an embedded document into an empty interface. For example, if +	// Ancestor is a bson.M, BSON embedded document values being decoded into an empty interface +	// will be decoded into a bson.M. +	// +	// Deprecated: Use DefaultDocumentM or DefaultDocumentD instead. +	Ancestor reflect.Type + +	// defaultDocumentType specifies the Go type to decode top-level and nested BSON documents into. In particular, the +	// usage for this field is restricted to data typed as "interface{}" or "map[string]interface{}". If DocumentType is +	// set to a type that a BSON document cannot be unmarshaled into (e.g. "string"), unmarshalling will result in an +	// error. DocumentType overrides the Ancestor field. +	defaultDocumentType reflect.Type +} + +// DefaultDocumentM will decode empty documents using the primitive.M type. This behavior is restricted to data typed as +// "interface{}" or "map[string]interface{}". +func (dc *DecodeContext) DefaultDocumentM() { +	dc.defaultDocumentType = reflect.TypeOf(primitive.M{}) +} + +// DefaultDocumentD will decode empty documents using the primitive.D type. This behavior is restricted to data typed as +// "interface{}" or "map[string]interface{}". +func (dc *DecodeContext) DefaultDocumentD() { +	dc.defaultDocumentType = reflect.TypeOf(primitive.D{}) +} + +// ValueCodec is the interface that groups the methods to encode and decode +// values. +type ValueCodec interface { +	ValueEncoder +	ValueDecoder +} + +// ValueEncoder is the interface implemented by types that can handle the encoding of a value. +type ValueEncoder interface { +	EncodeValue(EncodeContext, bsonrw.ValueWriter, reflect.Value) error +} + +// ValueEncoderFunc is an adapter function that allows a function with the correct signature to be +// used as a ValueEncoder. +type ValueEncoderFunc func(EncodeContext, bsonrw.ValueWriter, reflect.Value) error + +// EncodeValue implements the ValueEncoder interface. +func (fn ValueEncoderFunc) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	return fn(ec, vw, val) +} + +// ValueDecoder is the interface implemented by types that can handle the decoding of a value. +type ValueDecoder interface { +	DecodeValue(DecodeContext, bsonrw.ValueReader, reflect.Value) error +} + +// ValueDecoderFunc is an adapter function that allows a function with the correct signature to be +// used as a ValueDecoder. +type ValueDecoderFunc func(DecodeContext, bsonrw.ValueReader, reflect.Value) error + +// DecodeValue implements the ValueDecoder interface. +func (fn ValueDecoderFunc) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	return fn(dc, vr, val) +} + +// typeDecoder is the interface implemented by types that can handle the decoding of a value given its type. +type typeDecoder interface { +	decodeType(DecodeContext, bsonrw.ValueReader, reflect.Type) (reflect.Value, error) +} + +// typeDecoderFunc is an adapter function that allows a function with the correct signature to be used as a typeDecoder. +type typeDecoderFunc func(DecodeContext, bsonrw.ValueReader, reflect.Type) (reflect.Value, error) + +func (fn typeDecoderFunc) decodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { +	return fn(dc, vr, t) +} + +// decodeAdapter allows two functions with the correct signatures to be used as both a ValueDecoder and typeDecoder. +type decodeAdapter struct { +	ValueDecoderFunc +	typeDecoderFunc +} + +var _ ValueDecoder = decodeAdapter{} +var _ typeDecoder = decodeAdapter{} + +// decodeTypeOrValue calls decoder.decodeType is decoder is a typeDecoder. Otherwise, it allocates a new element of type +// t and calls decoder.DecodeValue on it. +func decodeTypeOrValue(decoder ValueDecoder, dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { +	td, _ := decoder.(typeDecoder) +	return decodeTypeOrValueWithInfo(decoder, td, dc, vr, t, true) +} + +func decodeTypeOrValueWithInfo(vd ValueDecoder, td typeDecoder, dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type, convert bool) (reflect.Value, error) { +	if td != nil { +		val, err := td.decodeType(dc, vr, t) +		if err == nil && convert && val.Type() != t { +			// This conversion step is necessary for slices and maps. If a user declares variables like: +			// +			// type myBool bool +			// var m map[string]myBool +			// +			// and tries to decode BSON bytes into the map, the decoding will fail if this conversion is not present +			// because we'll try to assign a value of type bool to one of type myBool. +			val = val.Convert(t) +		} +		return val, err +	} + +	val := reflect.New(t).Elem() +	err := vd.DecodeValue(dc, vr, val) +	return val, err +} + +// CodecZeroer is the interface implemented by Codecs that can also determine if +// a value of the type that would be encoded is zero. +type CodecZeroer interface { +	IsTypeZero(interface{}) bool +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/byte_slice_codec.go b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/byte_slice_codec.go new file mode 100644 index 000000000..5a916cc15 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/byte_slice_codec.go @@ -0,0 +1,111 @@ +// 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" +) + +// ByteSliceCodec is the Codec used for []byte values. +type ByteSliceCodec struct { +	EncodeNilAsEmpty bool +} + +var ( +	defaultByteSliceCodec = NewByteSliceCodec() + +	_ ValueCodec  = defaultByteSliceCodec +	_ typeDecoder = defaultByteSliceCodec +) + +// NewByteSliceCodec returns a StringCodec with options opts. +func NewByteSliceCodec(opts ...*bsonoptions.ByteSliceCodecOptions) *ByteSliceCodec { +	byteSliceOpt := bsonoptions.MergeByteSliceCodecOptions(opts...) +	codec := ByteSliceCodec{} +	if byteSliceOpt.EncodeNilAsEmpty != nil { +		codec.EncodeNilAsEmpty = *byteSliceOpt.EncodeNilAsEmpty +	} +	return &codec +} + +// EncodeValue is the ValueEncoder for []byte. +func (bsc *ByteSliceCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Type() != tByteSlice { +		return ValueEncoderError{Name: "ByteSliceEncodeValue", Types: []reflect.Type{tByteSlice}, Received: val} +	} +	if val.IsNil() && !bsc.EncodeNilAsEmpty { +		return vw.WriteNull() +	} +	return vw.WriteBinary(val.Interface().([]byte)) +} + +func (bsc *ByteSliceCodec) decodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { +	if t != tByteSlice { +		return emptyValue, ValueDecoderError{ +			Name:     "ByteSliceDecodeValue", +			Types:    []reflect.Type{tByteSlice}, +			Received: reflect.Zero(t), +		} +	} + +	var data []byte +	var err error +	switch vrType := vr.Type(); vrType { +	case bsontype.String: +		str, err := vr.ReadString() +		if err != nil { +			return emptyValue, err +		} +		data = []byte(str) +	case bsontype.Symbol: +		sym, err := vr.ReadSymbol() +		if err != nil { +			return emptyValue, err +		} +		data = []byte(sym) +	case bsontype.Binary: +		var subtype byte +		data, subtype, err = vr.ReadBinary() +		if err != nil { +			return emptyValue, err +		} +		if subtype != bsontype.BinaryGeneric && subtype != bsontype.BinaryBinaryOld { +			return emptyValue, decodeBinaryError{subtype: subtype, typeName: "[]byte"} +		} +	case bsontype.Null: +		err = vr.ReadNull() +	case bsontype.Undefined: +		err = vr.ReadUndefined() +	default: +		return emptyValue, fmt.Errorf("cannot decode %v into a []byte", vrType) +	} +	if err != nil { +		return emptyValue, err +	} + +	return reflect.ValueOf(data), nil +} + +// DecodeValue is the ValueDecoder for []byte. +func (bsc *ByteSliceCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Type() != tByteSlice { +		return ValueDecoderError{Name: "ByteSliceDecodeValue", Types: []reflect.Type{tByteSlice}, Received: val} +	} + +	elem, err := bsc.decodeType(dc, vr, tByteSlice) +	if err != nil { +		return err +	} + +	val.Set(elem) +	return nil +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/cond_addr_codec.go b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/cond_addr_codec.go new file mode 100644 index 000000000..cb8180f25 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/cond_addr_codec.go @@ -0,0 +1,63 @@ +// 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 ( +	"reflect" + +	"go.mongodb.org/mongo-driver/bson/bsonrw" +) + +// condAddrEncoder is the encoder used when a pointer to the encoding value has an encoder. +type condAddrEncoder struct { +	canAddrEnc ValueEncoder +	elseEnc    ValueEncoder +} + +var _ ValueEncoder = (*condAddrEncoder)(nil) + +// newCondAddrEncoder returns an condAddrEncoder. +func newCondAddrEncoder(canAddrEnc, elseEnc ValueEncoder) *condAddrEncoder { +	encoder := condAddrEncoder{canAddrEnc: canAddrEnc, elseEnc: elseEnc} +	return &encoder +} + +// EncodeValue is the ValueEncoderFunc for a value that may be addressable. +func (cae *condAddrEncoder) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if val.CanAddr() { +		return cae.canAddrEnc.EncodeValue(ec, vw, val) +	} +	if cae.elseEnc != nil { +		return cae.elseEnc.EncodeValue(ec, vw, val) +	} +	return ErrNoEncoder{Type: val.Type()} +} + +// condAddrDecoder is the decoder used when a pointer to the value has a decoder. +type condAddrDecoder struct { +	canAddrDec ValueDecoder +	elseDec    ValueDecoder +} + +var _ ValueDecoder = (*condAddrDecoder)(nil) + +// newCondAddrDecoder returns an CondAddrDecoder. +func newCondAddrDecoder(canAddrDec, elseDec ValueDecoder) *condAddrDecoder { +	decoder := condAddrDecoder{canAddrDec: canAddrDec, elseDec: elseDec} +	return &decoder +} + +// DecodeValue is the ValueDecoderFunc for a value that may be addressable. +func (cad *condAddrDecoder) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if val.CanAddr() { +		return cad.canAddrDec.DecodeValue(dc, vr, val) +	} +	if cad.elseDec != nil { +		return cad.elseDec.DecodeValue(dc, vr, val) +	} +	return ErrNoDecoder{Type: val.Type()} +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/default_value_decoders.go b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/default_value_decoders.go new file mode 100644 index 000000000..e95cab585 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/default_value_decoders.go @@ -0,0 +1,1729 @@ +// 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 ( +	"encoding/json" +	"errors" +	"fmt" +	"math" +	"net/url" +	"reflect" +	"strconv" +	"time" + +	"go.mongodb.org/mongo-driver/bson/bsonrw" +	"go.mongodb.org/mongo-driver/bson/bsontype" +	"go.mongodb.org/mongo-driver/bson/primitive" +	"go.mongodb.org/mongo-driver/x/bsonx/bsoncore" +) + +var ( +	defaultValueDecoders DefaultValueDecoders +	errCannotTruncate    = errors.New("float64 can only be truncated to an integer type when truncation is enabled") +) + +type decodeBinaryError struct { +	subtype  byte +	typeName string +} + +func (d decodeBinaryError) Error() string { +	return fmt.Sprintf("only binary values with subtype 0x00 or 0x02 can be decoded into %s, but got subtype %v", d.typeName, d.subtype) +} + +func newDefaultStructCodec() *StructCodec { +	codec, err := NewStructCodec(DefaultStructTagParser) +	if err != nil { +		// This function is called from the codec registration path, so errors can't be propagated. If there's an error +		// constructing the StructCodec, we panic to avoid losing it. +		panic(fmt.Errorf("error creating default StructCodec: %v", err)) +	} +	return codec +} + +// DefaultValueDecoders is a namespace type for the default ValueDecoders used +// when creating a registry. +type DefaultValueDecoders struct{} + +// RegisterDefaultDecoders will register the decoder methods attached to DefaultValueDecoders with +// the provided RegistryBuilder. +// +// There is no support for decoding map[string]interface{} because there is no decoder for +// interface{}, so users must either register this decoder themselves or use the +// EmptyInterfaceDecoder available in the bson package. +func (dvd DefaultValueDecoders) RegisterDefaultDecoders(rb *RegistryBuilder) { +	if rb == nil { +		panic(errors.New("argument to RegisterDefaultDecoders must not be nil")) +	} + +	intDecoder := decodeAdapter{dvd.IntDecodeValue, dvd.intDecodeType} +	floatDecoder := decodeAdapter{dvd.FloatDecodeValue, dvd.floatDecodeType} + +	rb. +		RegisterTypeDecoder(tD, ValueDecoderFunc(dvd.DDecodeValue)). +		RegisterTypeDecoder(tBinary, decodeAdapter{dvd.BinaryDecodeValue, dvd.binaryDecodeType}). +		RegisterTypeDecoder(tUndefined, decodeAdapter{dvd.UndefinedDecodeValue, dvd.undefinedDecodeType}). +		RegisterTypeDecoder(tDateTime, decodeAdapter{dvd.DateTimeDecodeValue, dvd.dateTimeDecodeType}). +		RegisterTypeDecoder(tNull, decodeAdapter{dvd.NullDecodeValue, dvd.nullDecodeType}). +		RegisterTypeDecoder(tRegex, decodeAdapter{dvd.RegexDecodeValue, dvd.regexDecodeType}). +		RegisterTypeDecoder(tDBPointer, decodeAdapter{dvd.DBPointerDecodeValue, dvd.dBPointerDecodeType}). +		RegisterTypeDecoder(tTimestamp, decodeAdapter{dvd.TimestampDecodeValue, dvd.timestampDecodeType}). +		RegisterTypeDecoder(tMinKey, decodeAdapter{dvd.MinKeyDecodeValue, dvd.minKeyDecodeType}). +		RegisterTypeDecoder(tMaxKey, decodeAdapter{dvd.MaxKeyDecodeValue, dvd.maxKeyDecodeType}). +		RegisterTypeDecoder(tJavaScript, decodeAdapter{dvd.JavaScriptDecodeValue, dvd.javaScriptDecodeType}). +		RegisterTypeDecoder(tSymbol, decodeAdapter{dvd.SymbolDecodeValue, dvd.symbolDecodeType}). +		RegisterTypeDecoder(tByteSlice, defaultByteSliceCodec). +		RegisterTypeDecoder(tTime, defaultTimeCodec). +		RegisterTypeDecoder(tEmpty, defaultEmptyInterfaceCodec). +		RegisterTypeDecoder(tCoreArray, defaultArrayCodec). +		RegisterTypeDecoder(tOID, decodeAdapter{dvd.ObjectIDDecodeValue, dvd.objectIDDecodeType}). +		RegisterTypeDecoder(tDecimal, decodeAdapter{dvd.Decimal128DecodeValue, dvd.decimal128DecodeType}). +		RegisterTypeDecoder(tJSONNumber, decodeAdapter{dvd.JSONNumberDecodeValue, dvd.jsonNumberDecodeType}). +		RegisterTypeDecoder(tURL, decodeAdapter{dvd.URLDecodeValue, dvd.urlDecodeType}). +		RegisterTypeDecoder(tCoreDocument, ValueDecoderFunc(dvd.CoreDocumentDecodeValue)). +		RegisterTypeDecoder(tCodeWithScope, decodeAdapter{dvd.CodeWithScopeDecodeValue, dvd.codeWithScopeDecodeType}). +		RegisterDefaultDecoder(reflect.Bool, decodeAdapter{dvd.BooleanDecodeValue, dvd.booleanDecodeType}). +		RegisterDefaultDecoder(reflect.Int, intDecoder). +		RegisterDefaultDecoder(reflect.Int8, intDecoder). +		RegisterDefaultDecoder(reflect.Int16, intDecoder). +		RegisterDefaultDecoder(reflect.Int32, intDecoder). +		RegisterDefaultDecoder(reflect.Int64, intDecoder). +		RegisterDefaultDecoder(reflect.Uint, defaultUIntCodec). +		RegisterDefaultDecoder(reflect.Uint8, defaultUIntCodec). +		RegisterDefaultDecoder(reflect.Uint16, defaultUIntCodec). +		RegisterDefaultDecoder(reflect.Uint32, defaultUIntCodec). +		RegisterDefaultDecoder(reflect.Uint64, defaultUIntCodec). +		RegisterDefaultDecoder(reflect.Float32, floatDecoder). +		RegisterDefaultDecoder(reflect.Float64, floatDecoder). +		RegisterDefaultDecoder(reflect.Array, ValueDecoderFunc(dvd.ArrayDecodeValue)). +		RegisterDefaultDecoder(reflect.Map, defaultMapCodec). +		RegisterDefaultDecoder(reflect.Slice, defaultSliceCodec). +		RegisterDefaultDecoder(reflect.String, defaultStringCodec). +		RegisterDefaultDecoder(reflect.Struct, newDefaultStructCodec()). +		RegisterDefaultDecoder(reflect.Ptr, NewPointerCodec()). +		RegisterTypeMapEntry(bsontype.Double, tFloat64). +		RegisterTypeMapEntry(bsontype.String, tString). +		RegisterTypeMapEntry(bsontype.Array, tA). +		RegisterTypeMapEntry(bsontype.Binary, tBinary). +		RegisterTypeMapEntry(bsontype.Undefined, tUndefined). +		RegisterTypeMapEntry(bsontype.ObjectID, tOID). +		RegisterTypeMapEntry(bsontype.Boolean, tBool). +		RegisterTypeMapEntry(bsontype.DateTime, tDateTime). +		RegisterTypeMapEntry(bsontype.Regex, tRegex). +		RegisterTypeMapEntry(bsontype.DBPointer, tDBPointer). +		RegisterTypeMapEntry(bsontype.JavaScript, tJavaScript). +		RegisterTypeMapEntry(bsontype.Symbol, tSymbol). +		RegisterTypeMapEntry(bsontype.CodeWithScope, tCodeWithScope). +		RegisterTypeMapEntry(bsontype.Int32, tInt32). +		RegisterTypeMapEntry(bsontype.Int64, tInt64). +		RegisterTypeMapEntry(bsontype.Timestamp, tTimestamp). +		RegisterTypeMapEntry(bsontype.Decimal128, tDecimal). +		RegisterTypeMapEntry(bsontype.MinKey, tMinKey). +		RegisterTypeMapEntry(bsontype.MaxKey, tMaxKey). +		RegisterTypeMapEntry(bsontype.Type(0), tD). +		RegisterTypeMapEntry(bsontype.EmbeddedDocument, tD). +		RegisterHookDecoder(tValueUnmarshaler, ValueDecoderFunc(dvd.ValueUnmarshalerDecodeValue)). +		RegisterHookDecoder(tUnmarshaler, ValueDecoderFunc(dvd.UnmarshalerDecodeValue)) +} + +// DDecodeValue is the ValueDecoderFunc for primitive.D instances. +func (dvd DefaultValueDecoders) DDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.IsValid() || !val.CanSet() || val.Type() != tD { +		return ValueDecoderError{Name: "DDecodeValue", Kinds: []reflect.Kind{reflect.Slice}, Received: val} +	} + +	switch vrType := vr.Type(); vrType { +	case bsontype.Type(0), bsontype.EmbeddedDocument: +		dc.Ancestor = tD +	case bsontype.Null: +		val.Set(reflect.Zero(val.Type())) +		return vr.ReadNull() +	default: +		return fmt.Errorf("cannot decode %v into a primitive.D", vrType) +	} + +	dr, err := vr.ReadDocument() +	if err != nil { +		return err +	} + +	decoder, err := dc.LookupDecoder(tEmpty) +	if err != nil { +		return err +	} +	tEmptyTypeDecoder, _ := decoder.(typeDecoder) + +	// Use the elements in the provided value if it's non nil. Otherwise, allocate a new D instance. +	var elems primitive.D +	if !val.IsNil() { +		val.SetLen(0) +		elems = val.Interface().(primitive.D) +	} else { +		elems = make(primitive.D, 0) +	} + +	for { +		key, elemVr, err := dr.ReadElement() +		if err == bsonrw.ErrEOD { +			break +		} else if err != nil { +			return err +		} + +		// Pass false for convert because we don't need to call reflect.Value.Convert for tEmpty. +		elem, err := decodeTypeOrValueWithInfo(decoder, tEmptyTypeDecoder, dc, elemVr, tEmpty, false) +		if err != nil { +			return err +		} + +		elems = append(elems, primitive.E{Key: key, Value: elem.Interface()}) +	} + +	val.Set(reflect.ValueOf(elems)) +	return nil +} + +func (dvd DefaultValueDecoders) booleanDecodeType(dctx DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { +	if t.Kind() != reflect.Bool { +		return emptyValue, ValueDecoderError{ +			Name:     "BooleanDecodeValue", +			Kinds:    []reflect.Kind{reflect.Bool}, +			Received: reflect.Zero(t), +		} +	} + +	var b bool +	var err error +	switch vrType := vr.Type(); vrType { +	case bsontype.Int32: +		i32, err := vr.ReadInt32() +		if err != nil { +			return emptyValue, err +		} +		b = (i32 != 0) +	case bsontype.Int64: +		i64, err := vr.ReadInt64() +		if err != nil { +			return emptyValue, err +		} +		b = (i64 != 0) +	case bsontype.Double: +		f64, err := vr.ReadDouble() +		if err != nil { +			return emptyValue, err +		} +		b = (f64 != 0) +	case bsontype.Boolean: +		b, err = vr.ReadBoolean() +	case bsontype.Null: +		err = vr.ReadNull() +	case bsontype.Undefined: +		err = vr.ReadUndefined() +	default: +		return emptyValue, fmt.Errorf("cannot decode %v into a boolean", vrType) +	} +	if err != nil { +		return emptyValue, err +	} + +	return reflect.ValueOf(b), nil +} + +// BooleanDecodeValue is the ValueDecoderFunc for bool types. +func (dvd DefaultValueDecoders) BooleanDecodeValue(dctx DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.IsValid() || !val.CanSet() || val.Kind() != reflect.Bool { +		return ValueDecoderError{Name: "BooleanDecodeValue", Kinds: []reflect.Kind{reflect.Bool}, Received: val} +	} + +	elem, err := dvd.booleanDecodeType(dctx, vr, val.Type()) +	if err != nil { +		return err +	} + +	val.SetBool(elem.Bool()) +	return nil +} + +func (DefaultValueDecoders) intDecodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { +	var i64 int64 +	var err error +	switch vrType := vr.Type(); vrType { +	case bsontype.Int32: +		i32, err := vr.ReadInt32() +		if err != nil { +			return emptyValue, err +		} +		i64 = int64(i32) +	case bsontype.Int64: +		i64, err = vr.ReadInt64() +		if err != nil { +			return emptyValue, err +		} +	case bsontype.Double: +		f64, err := vr.ReadDouble() +		if err != nil { +			return emptyValue, err +		} +		if !dc.Truncate && math.Floor(f64) != f64 { +			return emptyValue, errCannotTruncate +		} +		if f64 > float64(math.MaxInt64) { +			return emptyValue, fmt.Errorf("%g overflows int64", f64) +		} +		i64 = int64(f64) +	case bsontype.Boolean: +		b, err := vr.ReadBoolean() +		if err != nil { +			return emptyValue, err +		} +		if b { +			i64 = 1 +		} +	case bsontype.Null: +		if err = vr.ReadNull(); err != nil { +			return emptyValue, err +		} +	case bsontype.Undefined: +		if err = vr.ReadUndefined(); err != nil { +			return emptyValue, err +		} +	default: +		return emptyValue, fmt.Errorf("cannot decode %v into an integer type", vrType) +	} + +	switch t.Kind() { +	case reflect.Int8: +		if i64 < math.MinInt8 || i64 > math.MaxInt8 { +			return emptyValue, fmt.Errorf("%d overflows int8", i64) +		} + +		return reflect.ValueOf(int8(i64)), nil +	case reflect.Int16: +		if i64 < math.MinInt16 || i64 > math.MaxInt16 { +			return emptyValue, fmt.Errorf("%d overflows int16", i64) +		} + +		return reflect.ValueOf(int16(i64)), nil +	case reflect.Int32: +		if i64 < math.MinInt32 || i64 > math.MaxInt32 { +			return emptyValue, fmt.Errorf("%d overflows int32", i64) +		} + +		return reflect.ValueOf(int32(i64)), nil +	case reflect.Int64: +		return reflect.ValueOf(i64), nil +	case reflect.Int: +		if int64(int(i64)) != i64 { // Can we fit this inside of an int +			return emptyValue, fmt.Errorf("%d overflows int", i64) +		} + +		return reflect.ValueOf(int(i64)), nil +	default: +		return emptyValue, ValueDecoderError{ +			Name:     "IntDecodeValue", +			Kinds:    []reflect.Kind{reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int}, +			Received: reflect.Zero(t), +		} +	} +} + +// IntDecodeValue is the ValueDecoderFunc for int types. +func (dvd DefaultValueDecoders) IntDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() { +		return ValueDecoderError{ +			Name:     "IntDecodeValue", +			Kinds:    []reflect.Kind{reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int}, +			Received: val, +		} +	} + +	elem, err := dvd.intDecodeType(dc, vr, val.Type()) +	if err != nil { +		return err +	} + +	val.SetInt(elem.Int()) +	return nil +} + +// UintDecodeValue is the ValueDecoderFunc for uint types. +// +// Deprecated: UintDecodeValue is not registered by default. Use UintCodec.DecodeValue instead. +func (dvd DefaultValueDecoders) UintDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	var i64 int64 +	var err error +	switch vr.Type() { +	case bsontype.Int32: +		i32, err := vr.ReadInt32() +		if err != nil { +			return err +		} +		i64 = int64(i32) +	case bsontype.Int64: +		i64, err = vr.ReadInt64() +		if err != nil { +			return err +		} +	case bsontype.Double: +		f64, err := vr.ReadDouble() +		if err != nil { +			return err +		} +		if !dc.Truncate && math.Floor(f64) != f64 { +			return errors.New("UintDecodeValue can only truncate float64 to an integer type when truncation is enabled") +		} +		if f64 > float64(math.MaxInt64) { +			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()) +	} + +	if !val.CanSet() { +		return ValueDecoderError{ +			Name:     "UintDecodeValue", +			Kinds:    []reflect.Kind{reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint}, +			Received: val, +		} +	} + +	switch val.Kind() { +	case reflect.Uint8: +		if i64 < 0 || i64 > math.MaxUint8 { +			return fmt.Errorf("%d overflows uint8", i64) +		} +	case reflect.Uint16: +		if i64 < 0 || i64 > math.MaxUint16 { +			return fmt.Errorf("%d overflows uint16", i64) +		} +	case reflect.Uint32: +		if i64 < 0 || i64 > math.MaxUint32 { +			return fmt.Errorf("%d overflows uint32", i64) +		} +	case reflect.Uint64: +		if i64 < 0 { +			return fmt.Errorf("%d overflows uint64", i64) +		} +	case reflect.Uint: +		if i64 < 0 || int64(uint(i64)) != i64 { // Can we fit this inside of an uint +			return fmt.Errorf("%d overflows uint", i64) +		} +	default: +		return ValueDecoderError{ +			Name:     "UintDecodeValue", +			Kinds:    []reflect.Kind{reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint}, +			Received: val, +		} +	} + +	val.SetUint(uint64(i64)) +	return nil +} + +func (dvd DefaultValueDecoders) floatDecodeType(ec DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { +	var f float64 +	var err error +	switch vrType := vr.Type(); vrType { +	case bsontype.Int32: +		i32, err := vr.ReadInt32() +		if err != nil { +			return emptyValue, err +		} +		f = float64(i32) +	case bsontype.Int64: +		i64, err := vr.ReadInt64() +		if err != nil { +			return emptyValue, err +		} +		f = float64(i64) +	case bsontype.Double: +		f, err = vr.ReadDouble() +		if err != nil { +			return emptyValue, err +		} +	case bsontype.Boolean: +		b, err := vr.ReadBoolean() +		if err != nil { +			return emptyValue, err +		} +		if b { +			f = 1 +		} +	case bsontype.Null: +		if err = vr.ReadNull(); err != nil { +			return emptyValue, err +		} +	case bsontype.Undefined: +		if err = vr.ReadUndefined(); err != nil { +			return emptyValue, err +		} +	default: +		return emptyValue, fmt.Errorf("cannot decode %v into a float32 or float64 type", vrType) +	} + +	switch t.Kind() { +	case reflect.Float32: +		if !ec.Truncate && float64(float32(f)) != f { +			return emptyValue, errCannotTruncate +		} + +		return reflect.ValueOf(float32(f)), nil +	case reflect.Float64: +		return reflect.ValueOf(f), nil +	default: +		return emptyValue, ValueDecoderError{ +			Name:     "FloatDecodeValue", +			Kinds:    []reflect.Kind{reflect.Float32, reflect.Float64}, +			Received: reflect.Zero(t), +		} +	} +} + +// FloatDecodeValue is the ValueDecoderFunc for float types. +func (dvd DefaultValueDecoders) FloatDecodeValue(ec DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() { +		return ValueDecoderError{ +			Name:     "FloatDecodeValue", +			Kinds:    []reflect.Kind{reflect.Float32, reflect.Float64}, +			Received: val, +		} +	} + +	elem, err := dvd.floatDecodeType(ec, vr, val.Type()) +	if err != nil { +		return err +	} + +	val.SetFloat(elem.Float()) +	return nil +} + +// StringDecodeValue is the ValueDecoderFunc for string types. +// +// Deprecated: StringDecodeValue is not registered by default. Use StringCodec.DecodeValue instead. +func (dvd DefaultValueDecoders) StringDecodeValue(dctx DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	var str string +	var err error +	switch vr.Type() { +	// TODO(GODRIVER-577): Handle JavaScript and Symbol BSON types when allowed. +	case bsontype.String: +		str, err = vr.ReadString() +		if err != nil { +			return err +		} +	default: +		return fmt.Errorf("cannot decode %v into a string type", vr.Type()) +	} +	if !val.CanSet() || val.Kind() != reflect.String { +		return ValueDecoderError{Name: "StringDecodeValue", Kinds: []reflect.Kind{reflect.String}, Received: val} +	} + +	val.SetString(str) +	return nil +} + +func (DefaultValueDecoders) javaScriptDecodeType(dctx DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { +	if t != tJavaScript { +		return emptyValue, ValueDecoderError{ +			Name:     "JavaScriptDecodeValue", +			Types:    []reflect.Type{tJavaScript}, +			Received: reflect.Zero(t), +		} +	} + +	var js string +	var err error +	switch vrType := vr.Type(); vrType { +	case bsontype.JavaScript: +		js, err = vr.ReadJavascript() +	case bsontype.Null: +		err = vr.ReadNull() +	case bsontype.Undefined: +		err = vr.ReadUndefined() +	default: +		return emptyValue, fmt.Errorf("cannot decode %v into a primitive.JavaScript", vrType) +	} +	if err != nil { +		return emptyValue, err +	} + +	return reflect.ValueOf(primitive.JavaScript(js)), nil +} + +// JavaScriptDecodeValue is the ValueDecoderFunc for the primitive.JavaScript type. +func (dvd DefaultValueDecoders) JavaScriptDecodeValue(dctx DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Type() != tJavaScript { +		return ValueDecoderError{Name: "JavaScriptDecodeValue", Types: []reflect.Type{tJavaScript}, Received: val} +	} + +	elem, err := dvd.javaScriptDecodeType(dctx, vr, tJavaScript) +	if err != nil { +		return err +	} + +	val.SetString(elem.String()) +	return nil +} + +func (DefaultValueDecoders) symbolDecodeType(dctx DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { +	if t != tSymbol { +		return emptyValue, ValueDecoderError{ +			Name:     "SymbolDecodeValue", +			Types:    []reflect.Type{tSymbol}, +			Received: reflect.Zero(t), +		} +	} + +	var symbol string +	var err error +	switch vrType := vr.Type(); vrType { +	case bsontype.String: +		symbol, err = vr.ReadString() +	case bsontype.Symbol: +		symbol, err = vr.ReadSymbol() +	case bsontype.Binary: +		data, subtype, err := vr.ReadBinary() +		if err != nil { +			return emptyValue, err +		} + +		if subtype != bsontype.BinaryGeneric && subtype != bsontype.BinaryBinaryOld { +			return emptyValue, decodeBinaryError{subtype: subtype, typeName: "primitive.Symbol"} +		} +		symbol = string(data) +	case bsontype.Null: +		err = vr.ReadNull() +	case bsontype.Undefined: +		err = vr.ReadUndefined() +	default: +		return emptyValue, fmt.Errorf("cannot decode %v into a primitive.Symbol", vrType) +	} +	if err != nil { +		return emptyValue, err +	} + +	return reflect.ValueOf(primitive.Symbol(symbol)), nil +} + +// SymbolDecodeValue is the ValueDecoderFunc for the primitive.Symbol type. +func (dvd DefaultValueDecoders) SymbolDecodeValue(dctx DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Type() != tSymbol { +		return ValueDecoderError{Name: "SymbolDecodeValue", Types: []reflect.Type{tSymbol}, Received: val} +	} + +	elem, err := dvd.symbolDecodeType(dctx, vr, tSymbol) +	if err != nil { +		return err +	} + +	val.SetString(elem.String()) +	return nil +} + +func (DefaultValueDecoders) binaryDecodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { +	if t != tBinary { +		return emptyValue, ValueDecoderError{ +			Name:     "BinaryDecodeValue", +			Types:    []reflect.Type{tBinary}, +			Received: reflect.Zero(t), +		} +	} + +	var data []byte +	var subtype byte +	var err error +	switch vrType := vr.Type(); vrType { +	case bsontype.Binary: +		data, subtype, err = vr.ReadBinary() +	case bsontype.Null: +		err = vr.ReadNull() +	case bsontype.Undefined: +		err = vr.ReadUndefined() +	default: +		return emptyValue, fmt.Errorf("cannot decode %v into a Binary", vrType) +	} +	if err != nil { +		return emptyValue, err +	} + +	return reflect.ValueOf(primitive.Binary{Subtype: subtype, Data: data}), nil +} + +// BinaryDecodeValue is the ValueDecoderFunc for Binary. +func (dvd DefaultValueDecoders) BinaryDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Type() != tBinary { +		return ValueDecoderError{Name: "BinaryDecodeValue", Types: []reflect.Type{tBinary}, Received: val} +	} + +	elem, err := dvd.binaryDecodeType(dc, vr, tBinary) +	if err != nil { +		return err +	} + +	val.Set(elem) +	return nil +} + +func (DefaultValueDecoders) undefinedDecodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { +	if t != tUndefined { +		return emptyValue, ValueDecoderError{ +			Name:     "UndefinedDecodeValue", +			Types:    []reflect.Type{tUndefined}, +			Received: reflect.Zero(t), +		} +	} + +	var err error +	switch vrType := vr.Type(); vrType { +	case bsontype.Undefined: +		err = vr.ReadUndefined() +	case bsontype.Null: +		err = vr.ReadNull() +	default: +		return emptyValue, fmt.Errorf("cannot decode %v into an Undefined", vr.Type()) +	} +	if err != nil { +		return emptyValue, err +	} + +	return reflect.ValueOf(primitive.Undefined{}), nil +} + +// UndefinedDecodeValue is the ValueDecoderFunc for Undefined. +func (dvd DefaultValueDecoders) UndefinedDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Type() != tUndefined { +		return ValueDecoderError{Name: "UndefinedDecodeValue", Types: []reflect.Type{tUndefined}, Received: val} +	} + +	elem, err := dvd.undefinedDecodeType(dc, vr, tUndefined) +	if err != nil { +		return err +	} + +	val.Set(elem) +	return nil +} + +// Accept both 12-byte string and pretty-printed 24-byte hex string formats. +func (dvd DefaultValueDecoders) objectIDDecodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { +	if t != tOID { +		return emptyValue, ValueDecoderError{ +			Name:     "ObjectIDDecodeValue", +			Types:    []reflect.Type{tOID}, +			Received: reflect.Zero(t), +		} +	} + +	var oid primitive.ObjectID +	var err error +	switch vrType := vr.Type(); vrType { +	case bsontype.ObjectID: +		oid, err = vr.ReadObjectID() +		if err != nil { +			return emptyValue, err +		} +	case bsontype.String: +		str, err := vr.ReadString() +		if err != nil { +			return emptyValue, err +		} +		if oid, err = primitive.ObjectIDFromHex(str); err == nil { +			break +		} +		if len(str) != 12 { +			return emptyValue, fmt.Errorf("an ObjectID string must be exactly 12 bytes long (got %v)", len(str)) +		} +		byteArr := []byte(str) +		copy(oid[:], byteArr) +	case bsontype.Null: +		if err = vr.ReadNull(); err != nil { +			return emptyValue, err +		} +	case bsontype.Undefined: +		if err = vr.ReadUndefined(); err != nil { +			return emptyValue, err +		} +	default: +		return emptyValue, fmt.Errorf("cannot decode %v into an ObjectID", vrType) +	} + +	return reflect.ValueOf(oid), nil +} + +// ObjectIDDecodeValue is the ValueDecoderFunc for primitive.ObjectID. +func (dvd DefaultValueDecoders) ObjectIDDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Type() != tOID { +		return ValueDecoderError{Name: "ObjectIDDecodeValue", Types: []reflect.Type{tOID}, Received: val} +	} + +	elem, err := dvd.objectIDDecodeType(dc, vr, tOID) +	if err != nil { +		return err +	} + +	val.Set(elem) +	return nil +} + +func (DefaultValueDecoders) dateTimeDecodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { +	if t != tDateTime { +		return emptyValue, ValueDecoderError{ +			Name:     "DateTimeDecodeValue", +			Types:    []reflect.Type{tDateTime}, +			Received: reflect.Zero(t), +		} +	} + +	var dt int64 +	var err error +	switch vrType := vr.Type(); vrType { +	case bsontype.DateTime: +		dt, err = vr.ReadDateTime() +	case bsontype.Null: +		err = vr.ReadNull() +	case bsontype.Undefined: +		err = vr.ReadUndefined() +	default: +		return emptyValue, fmt.Errorf("cannot decode %v into a DateTime", vrType) +	} +	if err != nil { +		return emptyValue, err +	} + +	return reflect.ValueOf(primitive.DateTime(dt)), nil +} + +// DateTimeDecodeValue is the ValueDecoderFunc for DateTime. +func (dvd DefaultValueDecoders) DateTimeDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Type() != tDateTime { +		return ValueDecoderError{Name: "DateTimeDecodeValue", Types: []reflect.Type{tDateTime}, Received: val} +	} + +	elem, err := dvd.dateTimeDecodeType(dc, vr, tDateTime) +	if err != nil { +		return err +	} + +	val.Set(elem) +	return nil +} + +func (DefaultValueDecoders) nullDecodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { +	if t != tNull { +		return emptyValue, ValueDecoderError{ +			Name:     "NullDecodeValue", +			Types:    []reflect.Type{tNull}, +			Received: reflect.Zero(t), +		} +	} + +	var err error +	switch vrType := vr.Type(); vrType { +	case bsontype.Undefined: +		err = vr.ReadUndefined() +	case bsontype.Null: +		err = vr.ReadNull() +	default: +		return emptyValue, fmt.Errorf("cannot decode %v into a Null", vr.Type()) +	} +	if err != nil { +		return emptyValue, err +	} + +	return reflect.ValueOf(primitive.Null{}), nil +} + +// NullDecodeValue is the ValueDecoderFunc for Null. +func (dvd DefaultValueDecoders) NullDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Type() != tNull { +		return ValueDecoderError{Name: "NullDecodeValue", Types: []reflect.Type{tNull}, Received: val} +	} + +	elem, err := dvd.nullDecodeType(dc, vr, tNull) +	if err != nil { +		return err +	} + +	val.Set(elem) +	return nil +} + +func (DefaultValueDecoders) regexDecodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { +	if t != tRegex { +		return emptyValue, ValueDecoderError{ +			Name:     "RegexDecodeValue", +			Types:    []reflect.Type{tRegex}, +			Received: reflect.Zero(t), +		} +	} + +	var pattern, options string +	var err error +	switch vrType := vr.Type(); vrType { +	case bsontype.Regex: +		pattern, options, err = vr.ReadRegex() +	case bsontype.Null: +		err = vr.ReadNull() +	case bsontype.Undefined: +		err = vr.ReadUndefined() +	default: +		return emptyValue, fmt.Errorf("cannot decode %v into a Regex", vrType) +	} +	if err != nil { +		return emptyValue, err +	} + +	return reflect.ValueOf(primitive.Regex{Pattern: pattern, Options: options}), nil +} + +// RegexDecodeValue is the ValueDecoderFunc for Regex. +func (dvd DefaultValueDecoders) RegexDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Type() != tRegex { +		return ValueDecoderError{Name: "RegexDecodeValue", Types: []reflect.Type{tRegex}, Received: val} +	} + +	elem, err := dvd.regexDecodeType(dc, vr, tRegex) +	if err != nil { +		return err +	} + +	val.Set(elem) +	return nil +} + +func (DefaultValueDecoders) dBPointerDecodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { +	if t != tDBPointer { +		return emptyValue, ValueDecoderError{ +			Name:     "DBPointerDecodeValue", +			Types:    []reflect.Type{tDBPointer}, +			Received: reflect.Zero(t), +		} +	} + +	var ns string +	var pointer primitive.ObjectID +	var err error +	switch vrType := vr.Type(); vrType { +	case bsontype.DBPointer: +		ns, pointer, err = vr.ReadDBPointer() +	case bsontype.Null: +		err = vr.ReadNull() +	case bsontype.Undefined: +		err = vr.ReadUndefined() +	default: +		return emptyValue, fmt.Errorf("cannot decode %v into a DBPointer", vrType) +	} +	if err != nil { +		return emptyValue, err +	} + +	return reflect.ValueOf(primitive.DBPointer{DB: ns, Pointer: pointer}), nil +} + +// DBPointerDecodeValue is the ValueDecoderFunc for DBPointer. +func (dvd DefaultValueDecoders) DBPointerDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Type() != tDBPointer { +		return ValueDecoderError{Name: "DBPointerDecodeValue", Types: []reflect.Type{tDBPointer}, Received: val} +	} + +	elem, err := dvd.dBPointerDecodeType(dc, vr, tDBPointer) +	if err != nil { +		return err +	} + +	val.Set(elem) +	return nil +} + +func (DefaultValueDecoders) timestampDecodeType(dc DecodeContext, vr bsonrw.ValueReader, reflectType reflect.Type) (reflect.Value, error) { +	if reflectType != tTimestamp { +		return emptyValue, ValueDecoderError{ +			Name:     "TimestampDecodeValue", +			Types:    []reflect.Type{tTimestamp}, +			Received: reflect.Zero(reflectType), +		} +	} + +	var t, incr uint32 +	var err error +	switch vrType := vr.Type(); vrType { +	case bsontype.Timestamp: +		t, incr, err = vr.ReadTimestamp() +	case bsontype.Null: +		err = vr.ReadNull() +	case bsontype.Undefined: +		err = vr.ReadUndefined() +	default: +		return emptyValue, fmt.Errorf("cannot decode %v into a Timestamp", vrType) +	} +	if err != nil { +		return emptyValue, err +	} + +	return reflect.ValueOf(primitive.Timestamp{T: t, I: incr}), nil +} + +// TimestampDecodeValue is the ValueDecoderFunc for Timestamp. +func (dvd DefaultValueDecoders) TimestampDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Type() != tTimestamp { +		return ValueDecoderError{Name: "TimestampDecodeValue", Types: []reflect.Type{tTimestamp}, Received: val} +	} + +	elem, err := dvd.timestampDecodeType(dc, vr, tTimestamp) +	if err != nil { +		return err +	} + +	val.Set(elem) +	return nil +} + +func (DefaultValueDecoders) minKeyDecodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { +	if t != tMinKey { +		return emptyValue, ValueDecoderError{ +			Name:     "MinKeyDecodeValue", +			Types:    []reflect.Type{tMinKey}, +			Received: reflect.Zero(t), +		} +	} + +	var err error +	switch vrType := vr.Type(); vrType { +	case bsontype.MinKey: +		err = vr.ReadMinKey() +	case bsontype.Null: +		err = vr.ReadNull() +	case bsontype.Undefined: +		err = vr.ReadUndefined() +	default: +		return emptyValue, fmt.Errorf("cannot decode %v into a MinKey", vr.Type()) +	} +	if err != nil { +		return emptyValue, err +	} + +	return reflect.ValueOf(primitive.MinKey{}), nil +} + +// MinKeyDecodeValue is the ValueDecoderFunc for MinKey. +func (dvd DefaultValueDecoders) MinKeyDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Type() != tMinKey { +		return ValueDecoderError{Name: "MinKeyDecodeValue", Types: []reflect.Type{tMinKey}, Received: val} +	} + +	elem, err := dvd.minKeyDecodeType(dc, vr, tMinKey) +	if err != nil { +		return err +	} + +	val.Set(elem) +	return nil +} + +func (DefaultValueDecoders) maxKeyDecodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { +	if t != tMaxKey { +		return emptyValue, ValueDecoderError{ +			Name:     "MaxKeyDecodeValue", +			Types:    []reflect.Type{tMaxKey}, +			Received: reflect.Zero(t), +		} +	} + +	var err error +	switch vrType := vr.Type(); vrType { +	case bsontype.MaxKey: +		err = vr.ReadMaxKey() +	case bsontype.Null: +		err = vr.ReadNull() +	case bsontype.Undefined: +		err = vr.ReadUndefined() +	default: +		return emptyValue, fmt.Errorf("cannot decode %v into a MaxKey", vr.Type()) +	} +	if err != nil { +		return emptyValue, err +	} + +	return reflect.ValueOf(primitive.MaxKey{}), nil +} + +// MaxKeyDecodeValue is the ValueDecoderFunc for MaxKey. +func (dvd DefaultValueDecoders) MaxKeyDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Type() != tMaxKey { +		return ValueDecoderError{Name: "MaxKeyDecodeValue", Types: []reflect.Type{tMaxKey}, Received: val} +	} + +	elem, err := dvd.maxKeyDecodeType(dc, vr, tMaxKey) +	if err != nil { +		return err +	} + +	val.Set(elem) +	return nil +} + +func (dvd DefaultValueDecoders) decimal128DecodeType(dctx DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { +	if t != tDecimal { +		return emptyValue, ValueDecoderError{ +			Name:     "Decimal128DecodeValue", +			Types:    []reflect.Type{tDecimal}, +			Received: reflect.Zero(t), +		} +	} + +	var d128 primitive.Decimal128 +	var err error +	switch vrType := vr.Type(); vrType { +	case bsontype.Decimal128: +		d128, err = vr.ReadDecimal128() +	case bsontype.Null: +		err = vr.ReadNull() +	case bsontype.Undefined: +		err = vr.ReadUndefined() +	default: +		return emptyValue, fmt.Errorf("cannot decode %v into a primitive.Decimal128", vr.Type()) +	} +	if err != nil { +		return emptyValue, err +	} + +	return reflect.ValueOf(d128), nil +} + +// Decimal128DecodeValue is the ValueDecoderFunc for primitive.Decimal128. +func (dvd DefaultValueDecoders) Decimal128DecodeValue(dctx DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Type() != tDecimal { +		return ValueDecoderError{Name: "Decimal128DecodeValue", Types: []reflect.Type{tDecimal}, Received: val} +	} + +	elem, err := dvd.decimal128DecodeType(dctx, vr, tDecimal) +	if err != nil { +		return err +	} + +	val.Set(elem) +	return nil +} + +func (dvd DefaultValueDecoders) jsonNumberDecodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { +	if t != tJSONNumber { +		return emptyValue, ValueDecoderError{ +			Name:     "JSONNumberDecodeValue", +			Types:    []reflect.Type{tJSONNumber}, +			Received: reflect.Zero(t), +		} +	} + +	var jsonNum json.Number +	var err error +	switch vrType := vr.Type(); vrType { +	case bsontype.Double: +		f64, err := vr.ReadDouble() +		if err != nil { +			return emptyValue, err +		} +		jsonNum = json.Number(strconv.FormatFloat(f64, 'f', -1, 64)) +	case bsontype.Int32: +		i32, err := vr.ReadInt32() +		if err != nil { +			return emptyValue, err +		} +		jsonNum = json.Number(strconv.FormatInt(int64(i32), 10)) +	case bsontype.Int64: +		i64, err := vr.ReadInt64() +		if err != nil { +			return emptyValue, err +		} +		jsonNum = json.Number(strconv.FormatInt(i64, 10)) +	case bsontype.Null: +		err = vr.ReadNull() +	case bsontype.Undefined: +		err = vr.ReadUndefined() +	default: +		return emptyValue, fmt.Errorf("cannot decode %v into a json.Number", vrType) +	} +	if err != nil { +		return emptyValue, err +	} + +	return reflect.ValueOf(jsonNum), nil +} + +// JSONNumberDecodeValue is the ValueDecoderFunc for json.Number. +func (dvd DefaultValueDecoders) JSONNumberDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Type() != tJSONNumber { +		return ValueDecoderError{Name: "JSONNumberDecodeValue", Types: []reflect.Type{tJSONNumber}, Received: val} +	} + +	elem, err := dvd.jsonNumberDecodeType(dc, vr, tJSONNumber) +	if err != nil { +		return err +	} + +	val.Set(elem) +	return nil +} + +func (dvd DefaultValueDecoders) urlDecodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { +	if t != tURL { +		return emptyValue, ValueDecoderError{ +			Name:     "URLDecodeValue", +			Types:    []reflect.Type{tURL}, +			Received: reflect.Zero(t), +		} +	} + +	urlPtr := &url.URL{} +	var err error +	switch vrType := vr.Type(); vrType { +	case bsontype.String: +		var str string // Declare str here to avoid shadowing err during the ReadString call. +		str, err = vr.ReadString() +		if err != nil { +			return emptyValue, err +		} + +		urlPtr, err = url.Parse(str) +	case bsontype.Null: +		err = vr.ReadNull() +	case bsontype.Undefined: +		err = vr.ReadUndefined() +	default: +		return emptyValue, fmt.Errorf("cannot decode %v into a *url.URL", vrType) +	} +	if err != nil { +		return emptyValue, err +	} + +	return reflect.ValueOf(urlPtr).Elem(), nil +} + +// URLDecodeValue is the ValueDecoderFunc for url.URL. +func (dvd DefaultValueDecoders) URLDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Type() != tURL { +		return ValueDecoderError{Name: "URLDecodeValue", Types: []reflect.Type{tURL}, Received: val} +	} + +	elem, err := dvd.urlDecodeType(dc, vr, tURL) +	if err != nil { +		return err +	} + +	val.Set(elem) +	return nil +} + +// TimeDecodeValue is the ValueDecoderFunc for time.Time. +// +// Deprecated: TimeDecodeValue is not registered by default. Use TimeCodec.DecodeValue instead. +func (dvd DefaultValueDecoders) TimeDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if vr.Type() != bsontype.DateTime { +		return fmt.Errorf("cannot decode %v into a time.Time", vr.Type()) +	} + +	dt, err := vr.ReadDateTime() +	if err != nil { +		return err +	} + +	if !val.CanSet() || val.Type() != tTime { +		return ValueDecoderError{Name: "TimeDecodeValue", Types: []reflect.Type{tTime}, Received: val} +	} + +	val.Set(reflect.ValueOf(time.Unix(dt/1000, dt%1000*1000000).UTC())) +	return nil +} + +// ByteSliceDecodeValue is the ValueDecoderFunc for []byte. +// +// Deprecated: ByteSliceDecodeValue is not registered by default. Use ByteSliceCodec.DecodeValue instead. +func (dvd DefaultValueDecoders) ByteSliceDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if vr.Type() != bsontype.Binary && vr.Type() != bsontype.Null { +		return fmt.Errorf("cannot decode %v into a []byte", vr.Type()) +	} + +	if !val.CanSet() || val.Type() != tByteSlice { +		return ValueDecoderError{Name: "ByteSliceDecodeValue", Types: []reflect.Type{tByteSlice}, Received: val} +	} + +	if vr.Type() == bsontype.Null { +		val.Set(reflect.Zero(val.Type())) +		return vr.ReadNull() +	} + +	data, subtype, err := vr.ReadBinary() +	if err != nil { +		return err +	} +	if subtype != 0x00 { +		return fmt.Errorf("ByteSliceDecodeValue can only be used to decode subtype 0x00 for %s, got %v", bsontype.Binary, subtype) +	} + +	val.Set(reflect.ValueOf(data)) +	return nil +} + +// MapDecodeValue is the ValueDecoderFunc for map[string]* types. +// +// Deprecated: MapDecodeValue is not registered by default. Use MapCodec.DecodeValue instead. +func (dvd DefaultValueDecoders) MapDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Kind() != reflect.Map || val.Type().Key().Kind() != reflect.String { +		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())) +	} + +	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() +	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 +		} + +		val.SetMapIndex(reflect.ValueOf(key).Convert(keyType), elem) +	} +	return nil +} + +// ArrayDecodeValue is the ValueDecoderFunc for array types. +func (dvd DefaultValueDecoders) ArrayDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.IsValid() || val.Kind() != reflect.Array { +		return ValueDecoderError{Name: "ArrayDecodeValue", Kinds: []reflect.Kind{reflect.Array}, Received: val} +	} + +	switch vrType := vr.Type(); vrType { +	case bsontype.Array: +	case bsontype.Type(0), bsontype.EmbeddedDocument: +		if val.Type().Elem() != tE { +			return fmt.Errorf("cannot decode document into %s", val.Type()) +		} +	case bsontype.Binary: +		if val.Type().Elem() != tByte { +			return fmt.Errorf("ArrayDecodeValue can only be used to decode binary into a byte array, got %v", vrType) +		} +		data, subtype, err := vr.ReadBinary() +		if err != nil { +			return err +		} +		if subtype != bsontype.BinaryGeneric && subtype != bsontype.BinaryBinaryOld { +			return fmt.Errorf("ArrayDecodeValue can only be used to decode subtype 0x00 or 0x02 for %s, got %v", bsontype.Binary, subtype) +		} + +		if len(data) > val.Len() { +			return fmt.Errorf("more elements returned in array than can fit inside %s", val.Type()) +		} + +		for idx, elem := range data { +			val.Index(idx).Set(reflect.ValueOf(elem)) +		} +		return nil +	case bsontype.Null: +		val.Set(reflect.Zero(val.Type())) +		return vr.ReadNull() +	case bsontype.Undefined: +		val.Set(reflect.Zero(val.Type())) +		return vr.ReadUndefined() +	default: +		return fmt.Errorf("cannot decode %v into an array", vrType) +	} + +	var elemsFunc func(DecodeContext, bsonrw.ValueReader, reflect.Value) ([]reflect.Value, error) +	switch val.Type().Elem() { +	case tE: +		elemsFunc = dvd.decodeD +	default: +		elemsFunc = dvd.decodeDefault +	} + +	elems, err := elemsFunc(dc, vr, val) +	if err != nil { +		return err +	} + +	if len(elems) > val.Len() { +		return fmt.Errorf("more elements returned in array than can fit inside %s, got %v elements", val.Type(), len(elems)) +	} + +	for idx, elem := range elems { +		val.Index(idx).Set(elem) +	} + +	return nil +} + +// SliceDecodeValue is the ValueDecoderFunc for slice types. +// +// Deprecated: SliceDecodeValue is not registered by default. Use SliceCodec.DecodeValue instead. +func (dvd DefaultValueDecoders) SliceDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Kind() != reflect.Slice { +		return ValueDecoderError{Name: "SliceDecodeValue", Kinds: []reflect.Kind{reflect.Slice}, Received: val} +	} + +	switch vr.Type() { +	case bsontype.Array: +	case bsontype.Null: +		val.Set(reflect.Zero(val.Type())) +		return vr.ReadNull() +	case bsontype.Type(0), bsontype.EmbeddedDocument: +		if val.Type().Elem() != tE { +			return fmt.Errorf("cannot decode document into %s", val.Type()) +		} +	default: +		return fmt.Errorf("cannot decode %v into a slice", vr.Type()) +	} + +	var elemsFunc func(DecodeContext, bsonrw.ValueReader, reflect.Value) ([]reflect.Value, error) +	switch val.Type().Elem() { +	case tE: +		dc.Ancestor = val.Type() +		elemsFunc = dvd.decodeD +	default: +		elemsFunc = dvd.decodeDefault +	} + +	elems, err := elemsFunc(dc, vr, val) +	if err != nil { +		return err +	} + +	if val.IsNil() { +		val.Set(reflect.MakeSlice(val.Type(), 0, len(elems))) +	} + +	val.SetLen(0) +	val.Set(reflect.Append(val, elems...)) + +	return nil +} + +// ValueUnmarshalerDecodeValue is the ValueDecoderFunc for ValueUnmarshaler implementations. +func (dvd DefaultValueDecoders) ValueUnmarshalerDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.IsValid() || (!val.Type().Implements(tValueUnmarshaler) && !reflect.PtrTo(val.Type()).Implements(tValueUnmarshaler)) { +		return ValueDecoderError{Name: "ValueUnmarshalerDecodeValue", Types: []reflect.Type{tValueUnmarshaler}, Received: val} +	} + +	if val.Kind() == reflect.Ptr && val.IsNil() { +		if !val.CanSet() { +			return ValueDecoderError{Name: "ValueUnmarshalerDecodeValue", Types: []reflect.Type{tValueUnmarshaler}, Received: val} +		} +		val.Set(reflect.New(val.Type().Elem())) +	} + +	if !val.Type().Implements(tValueUnmarshaler) { +		if !val.CanAddr() { +			return ValueDecoderError{Name: "ValueUnmarshalerDecodeValue", Types: []reflect.Type{tValueUnmarshaler}, Received: val} +		} +		val = val.Addr() // If the type doesn't implement the interface, a pointer to it must. +	} + +	t, src, err := bsonrw.Copier{}.CopyValueToBytes(vr) +	if err != nil { +		return err +	} + +	fn := val.Convert(tValueUnmarshaler).MethodByName("UnmarshalBSONValue") +	errVal := fn.Call([]reflect.Value{reflect.ValueOf(t), reflect.ValueOf(src)})[0] +	if !errVal.IsNil() { +		return errVal.Interface().(error) +	} +	return nil +} + +// UnmarshalerDecodeValue is the ValueDecoderFunc for Unmarshaler implementations. +func (dvd DefaultValueDecoders) UnmarshalerDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.IsValid() || (!val.Type().Implements(tUnmarshaler) && !reflect.PtrTo(val.Type()).Implements(tUnmarshaler)) { +		return ValueDecoderError{Name: "UnmarshalerDecodeValue", Types: []reflect.Type{tUnmarshaler}, Received: val} +	} + +	if val.Kind() == reflect.Ptr && val.IsNil() { +		if !val.CanSet() { +			return ValueDecoderError{Name: "UnmarshalerDecodeValue", Types: []reflect.Type{tUnmarshaler}, Received: val} +		} +		val.Set(reflect.New(val.Type().Elem())) +	} + +	_, src, err := bsonrw.Copier{}.CopyValueToBytes(vr) +	if err != nil { +		return err +	} + +	// If the target Go value is a pointer and the BSON field value is empty, set the value to the +	// zero value of the pointer (nil) and don't call UnmarshalBSON. UnmarshalBSON has no way to +	// change the pointer value from within the function (only the value at the pointer address), +	// so it can't set the pointer to "nil" itself. Since the most common Go value for an empty BSON +	// field value is "nil", we set "nil" here and don't call UnmarshalBSON. This behavior matches +	// the behavior of the Go "encoding/json" unmarshaler when the target Go value is a pointer and +	// the JSON field value is "null". +	if val.Kind() == reflect.Ptr && len(src) == 0 { +		val.Set(reflect.Zero(val.Type())) +		return nil +	} + +	if !val.Type().Implements(tUnmarshaler) { +		if !val.CanAddr() { +			return ValueDecoderError{Name: "UnmarshalerDecodeValue", Types: []reflect.Type{tUnmarshaler}, Received: val} +		} +		val = val.Addr() // If the type doesn't implement the interface, a pointer to it must. +	} + +	fn := val.Convert(tUnmarshaler).MethodByName("UnmarshalBSON") +	errVal := fn.Call([]reflect.Value{reflect.ValueOf(src)})[0] +	if !errVal.IsNil() { +		return errVal.Interface().(error) +	} +	return nil +} + +// EmptyInterfaceDecodeValue is the ValueDecoderFunc for interface{}. +// +// Deprecated: EmptyInterfaceDecodeValue is not registered by default. Use EmptyInterfaceCodec.DecodeValue instead. +func (dvd DefaultValueDecoders) EmptyInterfaceDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Type() != tEmpty { +		return ValueDecoderError{Name: "EmptyInterfaceDecodeValue", Types: []reflect.Type{tEmpty}, Received: val} +	} + +	rtype, err := dc.LookupTypeMapEntry(vr.Type()) +	if err != nil { +		switch vr.Type() { +		case bsontype.EmbeddedDocument: +			if dc.Ancestor != nil { +				rtype = dc.Ancestor +				break +			} +			rtype = tD +		case bsontype.Null: +			val.Set(reflect.Zero(val.Type())) +			return vr.ReadNull() +		default: +			return err +		} +	} + +	decoder, err := dc.LookupDecoder(rtype) +	if err != nil { +		return err +	} + +	elem := reflect.New(rtype).Elem() +	err = decoder.DecodeValue(dc, vr, elem) +	if err != nil { +		return err +	} + +	val.Set(elem) +	return nil +} + +// CoreDocumentDecodeValue is the ValueDecoderFunc for bsoncore.Document. +func (DefaultValueDecoders) CoreDocumentDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Type() != tCoreDocument { +		return ValueDecoderError{Name: "CoreDocumentDecodeValue", Types: []reflect.Type{tCoreDocument}, Received: val} +	} + +	if val.IsNil() { +		val.Set(reflect.MakeSlice(val.Type(), 0, 0)) +	} + +	val.SetLen(0) + +	cdoc, err := bsonrw.Copier{}.AppendDocumentBytes(val.Interface().(bsoncore.Document), vr) +	val.Set(reflect.ValueOf(cdoc)) +	return err +} + +func (dvd DefaultValueDecoders) decodeDefault(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) ([]reflect.Value, error) { +	elems := make([]reflect.Value, 0) + +	ar, err := vr.ReadArray() +	if err != nil { +		return nil, err +	} + +	eType := val.Type().Elem() + +	decoder, err := dc.LookupDecoder(eType) +	if err != nil { +		return nil, err +	} +	eTypeDecoder, _ := decoder.(typeDecoder) + +	idx := 0 +	for { +		vr, err := ar.ReadValue() +		if err == bsonrw.ErrEOA { +			break +		} +		if err != nil { +			return nil, err +		} + +		elem, err := decodeTypeOrValueWithInfo(decoder, eTypeDecoder, dc, vr, eType, true) +		if err != nil { +			return nil, newDecodeError(strconv.Itoa(idx), err) +		} +		elems = append(elems, elem) +		idx++ +	} + +	return elems, nil +} + +func (dvd DefaultValueDecoders) readCodeWithScope(dc DecodeContext, vr bsonrw.ValueReader) (primitive.CodeWithScope, error) { +	var cws primitive.CodeWithScope + +	code, dr, err := vr.ReadCodeWithScope() +	if err != nil { +		return cws, err +	} + +	scope := reflect.New(tD).Elem() +	elems, err := dvd.decodeElemsFromDocumentReader(dc, dr) +	if err != nil { +		return cws, err +	} + +	scope.Set(reflect.MakeSlice(tD, 0, len(elems))) +	scope.Set(reflect.Append(scope, elems...)) + +	cws = primitive.CodeWithScope{ +		Code:  primitive.JavaScript(code), +		Scope: scope.Interface().(primitive.D), +	} +	return cws, nil +} + +func (dvd DefaultValueDecoders) codeWithScopeDecodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { +	if t != tCodeWithScope { +		return emptyValue, ValueDecoderError{ +			Name:     "CodeWithScopeDecodeValue", +			Types:    []reflect.Type{tCodeWithScope}, +			Received: reflect.Zero(t), +		} +	} + +	var cws primitive.CodeWithScope +	var err error +	switch vrType := vr.Type(); vrType { +	case bsontype.CodeWithScope: +		cws, err = dvd.readCodeWithScope(dc, vr) +	case bsontype.Null: +		err = vr.ReadNull() +	case bsontype.Undefined: +		err = vr.ReadUndefined() +	default: +		return emptyValue, fmt.Errorf("cannot decode %v into a primitive.CodeWithScope", vrType) +	} +	if err != nil { +		return emptyValue, err +	} + +	return reflect.ValueOf(cws), nil +} + +// CodeWithScopeDecodeValue is the ValueDecoderFunc for CodeWithScope. +func (dvd DefaultValueDecoders) CodeWithScopeDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Type() != tCodeWithScope { +		return ValueDecoderError{Name: "CodeWithScopeDecodeValue", Types: []reflect.Type{tCodeWithScope}, Received: val} +	} + +	elem, err := dvd.codeWithScopeDecodeType(dc, vr, tCodeWithScope) +	if err != nil { +		return err +	} + +	val.Set(elem) +	return nil +} + +func (dvd DefaultValueDecoders) decodeD(dc DecodeContext, vr bsonrw.ValueReader, _ reflect.Value) ([]reflect.Value, error) { +	switch vr.Type() { +	case bsontype.Type(0), bsontype.EmbeddedDocument: +	default: +		return nil, fmt.Errorf("cannot decode %v into a D", vr.Type()) +	} + +	dr, err := vr.ReadDocument() +	if err != nil { +		return nil, err +	} + +	return dvd.decodeElemsFromDocumentReader(dc, dr) +} + +func (DefaultValueDecoders) decodeElemsFromDocumentReader(dc DecodeContext, dr bsonrw.DocumentReader) ([]reflect.Value, error) { +	decoder, err := dc.LookupDecoder(tEmpty) +	if err != nil { +		return nil, err +	} + +	elems := make([]reflect.Value, 0) +	for { +		key, vr, err := dr.ReadElement() +		if err == bsonrw.ErrEOD { +			break +		} +		if err != nil { +			return nil, err +		} + +		val := reflect.New(tEmpty).Elem() +		err = decoder.DecodeValue(dc, vr, val) +		if err != nil { +			return nil, newDecodeError(key, err) +		} + +		elems = append(elems, reflect.ValueOf(primitive.E{Key: key, Value: val.Interface()})) +	} + +	return elems, nil +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/default_value_encoders.go b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/default_value_encoders.go new file mode 100644 index 000000000..6bdb43cb4 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/default_value_encoders.go @@ -0,0 +1,766 @@ +// 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 ( +	"encoding/json" +	"errors" +	"fmt" +	"math" +	"net/url" +	"reflect" +	"sync" +	"time" + +	"go.mongodb.org/mongo-driver/bson/bsonrw" +	"go.mongodb.org/mongo-driver/bson/bsontype" +	"go.mongodb.org/mongo-driver/bson/primitive" +	"go.mongodb.org/mongo-driver/x/bsonx/bsoncore" +) + +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) +		return &sw +	}, +} + +func encodeElement(ec EncodeContext, dw bsonrw.DocumentWriter, e primitive.E) error { +	vw, err := dw.WriteDocumentElement(e.Key) +	if err != nil { +		return err +	} + +	if e.Value == nil { +		return vw.WriteNull() +	} +	encoder, err := ec.LookupEncoder(reflect.TypeOf(e.Value)) +	if err != nil { +		return err +	} + +	err = encoder.EncodeValue(ec, vw, reflect.ValueOf(e.Value)) +	if err != nil { +		return err +	} +	return nil +} + +// DefaultValueEncoders is a namespace type for the default ValueEncoders used +// when creating a registry. +type DefaultValueEncoders struct{} + +// RegisterDefaultEncoders will register the encoder methods attached to DefaultValueEncoders with +// the provided RegistryBuilder. +func (dve DefaultValueEncoders) RegisterDefaultEncoders(rb *RegistryBuilder) { +	if rb == nil { +		panic(errors.New("argument to RegisterDefaultEncoders must not be nil")) +	} +	rb. +		RegisterTypeEncoder(tByteSlice, defaultByteSliceCodec). +		RegisterTypeEncoder(tTime, defaultTimeCodec). +		RegisterTypeEncoder(tEmpty, defaultEmptyInterfaceCodec). +		RegisterTypeEncoder(tCoreArray, defaultArrayCodec). +		RegisterTypeEncoder(tOID, ValueEncoderFunc(dve.ObjectIDEncodeValue)). +		RegisterTypeEncoder(tDecimal, ValueEncoderFunc(dve.Decimal128EncodeValue)). +		RegisterTypeEncoder(tJSONNumber, ValueEncoderFunc(dve.JSONNumberEncodeValue)). +		RegisterTypeEncoder(tURL, ValueEncoderFunc(dve.URLEncodeValue)). +		RegisterTypeEncoder(tJavaScript, ValueEncoderFunc(dve.JavaScriptEncodeValue)). +		RegisterTypeEncoder(tSymbol, ValueEncoderFunc(dve.SymbolEncodeValue)). +		RegisterTypeEncoder(tBinary, ValueEncoderFunc(dve.BinaryEncodeValue)). +		RegisterTypeEncoder(tUndefined, ValueEncoderFunc(dve.UndefinedEncodeValue)). +		RegisterTypeEncoder(tDateTime, ValueEncoderFunc(dve.DateTimeEncodeValue)). +		RegisterTypeEncoder(tNull, ValueEncoderFunc(dve.NullEncodeValue)). +		RegisterTypeEncoder(tRegex, ValueEncoderFunc(dve.RegexEncodeValue)). +		RegisterTypeEncoder(tDBPointer, ValueEncoderFunc(dve.DBPointerEncodeValue)). +		RegisterTypeEncoder(tTimestamp, ValueEncoderFunc(dve.TimestampEncodeValue)). +		RegisterTypeEncoder(tMinKey, ValueEncoderFunc(dve.MinKeyEncodeValue)). +		RegisterTypeEncoder(tMaxKey, ValueEncoderFunc(dve.MaxKeyEncodeValue)). +		RegisterTypeEncoder(tCoreDocument, ValueEncoderFunc(dve.CoreDocumentEncodeValue)). +		RegisterTypeEncoder(tCodeWithScope, ValueEncoderFunc(dve.CodeWithScopeEncodeValue)). +		RegisterDefaultEncoder(reflect.Bool, ValueEncoderFunc(dve.BooleanEncodeValue)). +		RegisterDefaultEncoder(reflect.Int, ValueEncoderFunc(dve.IntEncodeValue)). +		RegisterDefaultEncoder(reflect.Int8, ValueEncoderFunc(dve.IntEncodeValue)). +		RegisterDefaultEncoder(reflect.Int16, ValueEncoderFunc(dve.IntEncodeValue)). +		RegisterDefaultEncoder(reflect.Int32, ValueEncoderFunc(dve.IntEncodeValue)). +		RegisterDefaultEncoder(reflect.Int64, ValueEncoderFunc(dve.IntEncodeValue)). +		RegisterDefaultEncoder(reflect.Uint, defaultUIntCodec). +		RegisterDefaultEncoder(reflect.Uint8, defaultUIntCodec). +		RegisterDefaultEncoder(reflect.Uint16, defaultUIntCodec). +		RegisterDefaultEncoder(reflect.Uint32, defaultUIntCodec). +		RegisterDefaultEncoder(reflect.Uint64, defaultUIntCodec). +		RegisterDefaultEncoder(reflect.Float32, ValueEncoderFunc(dve.FloatEncodeValue)). +		RegisterDefaultEncoder(reflect.Float64, ValueEncoderFunc(dve.FloatEncodeValue)). +		RegisterDefaultEncoder(reflect.Array, ValueEncoderFunc(dve.ArrayEncodeValue)). +		RegisterDefaultEncoder(reflect.Map, defaultMapCodec). +		RegisterDefaultEncoder(reflect.Slice, defaultSliceCodec). +		RegisterDefaultEncoder(reflect.String, defaultStringCodec). +		RegisterDefaultEncoder(reflect.Struct, newDefaultStructCodec()). +		RegisterDefaultEncoder(reflect.Ptr, NewPointerCodec()). +		RegisterHookEncoder(tValueMarshaler, ValueEncoderFunc(dve.ValueMarshalerEncodeValue)). +		RegisterHookEncoder(tMarshaler, ValueEncoderFunc(dve.MarshalerEncodeValue)). +		RegisterHookEncoder(tProxy, ValueEncoderFunc(dve.ProxyEncodeValue)) +} + +// BooleanEncodeValue is the ValueEncoderFunc for bool types. +func (dve DefaultValueEncoders) BooleanEncodeValue(ectx EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Kind() != reflect.Bool { +		return ValueEncoderError{Name: "BooleanEncodeValue", Kinds: []reflect.Kind{reflect.Bool}, Received: val} +	} +	return vw.WriteBoolean(val.Bool()) +} + +func fitsIn32Bits(i int64) bool { +	return math.MinInt32 <= i && i <= math.MaxInt32 +} + +// IntEncodeValue is the ValueEncoderFunc for int types. +func (dve DefaultValueEncoders) IntEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	switch val.Kind() { +	case reflect.Int8, reflect.Int16, reflect.Int32: +		return vw.WriteInt32(int32(val.Int())) +	case reflect.Int: +		i64 := val.Int() +		if fitsIn32Bits(i64) { +			return vw.WriteInt32(int32(i64)) +		} +		return vw.WriteInt64(i64) +	case reflect.Int64: +		i64 := val.Int() +		if ec.MinSize && fitsIn32Bits(i64) { +			return vw.WriteInt32(int32(i64)) +		} +		return vw.WriteInt64(i64) +	} + +	return ValueEncoderError{ +		Name:     "IntEncodeValue", +		Kinds:    []reflect.Kind{reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int}, +		Received: val, +	} +} + +// UintEncodeValue is the ValueEncoderFunc for uint types. +// +// Deprecated: UintEncodeValue is not registered by default. Use UintCodec.EncodeValue instead. +func (dve DefaultValueEncoders) UintEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	switch val.Kind() { +	case reflect.Uint8, reflect.Uint16: +		return vw.WriteInt32(int32(val.Uint())) +	case reflect.Uint, reflect.Uint32, reflect.Uint64: +		u64 := val.Uint() +		if ec.MinSize && u64 <= math.MaxInt32 { +			return vw.WriteInt32(int32(u64)) +		} +		if u64 > math.MaxInt64 { +			return fmt.Errorf("%d overflows int64", u64) +		} +		return vw.WriteInt64(int64(u64)) +	} + +	return ValueEncoderError{ +		Name:     "UintEncodeValue", +		Kinds:    []reflect.Kind{reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint}, +		Received: val, +	} +} + +// FloatEncodeValue is the ValueEncoderFunc for float types. +func (dve DefaultValueEncoders) FloatEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	switch val.Kind() { +	case reflect.Float32, reflect.Float64: +		return vw.WriteDouble(val.Float()) +	} + +	return ValueEncoderError{Name: "FloatEncodeValue", Kinds: []reflect.Kind{reflect.Float32, reflect.Float64}, Received: val} +} + +// StringEncodeValue is the ValueEncoderFunc for string types. +// +// Deprecated: StringEncodeValue is not registered by default. Use StringCodec.EncodeValue instead. +func (dve DefaultValueEncoders) StringEncodeValue(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()) +} + +// ObjectIDEncodeValue is the ValueEncoderFunc for primitive.ObjectID. +func (dve DefaultValueEncoders) ObjectIDEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Type() != tOID { +		return ValueEncoderError{Name: "ObjectIDEncodeValue", Types: []reflect.Type{tOID}, Received: val} +	} +	return vw.WriteObjectID(val.Interface().(primitive.ObjectID)) +} + +// Decimal128EncodeValue is the ValueEncoderFunc for primitive.Decimal128. +func (dve DefaultValueEncoders) Decimal128EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Type() != tDecimal { +		return ValueEncoderError{Name: "Decimal128EncodeValue", Types: []reflect.Type{tDecimal}, Received: val} +	} +	return vw.WriteDecimal128(val.Interface().(primitive.Decimal128)) +} + +// JSONNumberEncodeValue is the ValueEncoderFunc for json.Number. +func (dve DefaultValueEncoders) JSONNumberEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Type() != tJSONNumber { +		return ValueEncoderError{Name: "JSONNumberEncodeValue", Types: []reflect.Type{tJSONNumber}, Received: val} +	} +	jsnum := val.Interface().(json.Number) + +	// Attempt int first, then float64 +	if i64, err := jsnum.Int64(); err == nil { +		return dve.IntEncodeValue(ec, vw, reflect.ValueOf(i64)) +	} + +	f64, err := jsnum.Float64() +	if err != nil { +		return err +	} + +	return dve.FloatEncodeValue(ec, vw, reflect.ValueOf(f64)) +} + +// URLEncodeValue is the ValueEncoderFunc for url.URL. +func (dve DefaultValueEncoders) URLEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Type() != tURL { +		return ValueEncoderError{Name: "URLEncodeValue", Types: []reflect.Type{tURL}, Received: val} +	} +	u := val.Interface().(url.URL) +	return vw.WriteString(u.String()) +} + +// TimeEncodeValue is the ValueEncoderFunc for time.TIme. +// +// Deprecated: TimeEncodeValue is not registered by default. Use TimeCodec.EncodeValue instead. +func (dve DefaultValueEncoders) TimeEncodeValue(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) +	dt := primitive.NewDateTimeFromTime(tt) +	return vw.WriteDateTime(int64(dt)) +} + +// ByteSliceEncodeValue is the ValueEncoderFunc for []byte. +// +// Deprecated: ByteSliceEncodeValue is not registered by default. Use ByteSliceCodec.EncodeValue instead. +func (dve DefaultValueEncoders) ByteSliceEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Type() != tByteSlice { +		return ValueEncoderError{Name: "ByteSliceEncodeValue", Types: []reflect.Type{tByteSlice}, Received: val} +	} +	if val.IsNil() { +		return vw.WriteNull() +	} +	return vw.WriteBinary(val.Interface().([]byte)) +} + +// MapEncodeValue is the ValueEncoderFunc for map[string]* types. +// +// Deprecated: MapEncodeValue is not registered by default. Use MapCodec.EncodeValue instead. +func (dve DefaultValueEncoders) MapEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Kind() != reflect.Map || val.Type().Key().Kind() != reflect.String { +		return ValueEncoderError{Name: "MapEncodeValue", Kinds: []reflect.Kind{reflect.Map}, Received: val} +	} + +	if val.IsNil() { +		// If we have a nill 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 dve.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 (dve DefaultValueEncoders) 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 { +		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 lookupErr == errInvalidValue { +			err = vw.WriteNull() +			if err != nil { +				return err +			} +			continue +		} + +		err = currEncoder.EncodeValue(ec, vw, currVal) +		if err != nil { +			return err +		} +	} + +	return dw.WriteDocumentEnd() +} + +// ArrayEncodeValue is the ValueEncoderFunc for array types. +func (dve DefaultValueEncoders) ArrayEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Kind() != reflect.Array { +		return ValueEncoderError{Name: "ArrayEncodeValue", Kinds: []reflect.Kind{reflect.Array}, Received: val} +	} + +	// If we have a []primitive.E we want to treat it as a document instead of as an array. +	if val.Type().Elem() == tE { +		dw, err := vw.WriteDocument() +		if err != nil { +			return err +		} + +		for idx := 0; idx < val.Len(); idx++ { +			e := val.Index(idx).Interface().(primitive.E) +			err = encodeElement(ec, dw, e) +			if err != nil { +				return err +			} +		} + +		return dw.WriteDocumentEnd() +	} + +	// If we have a []byte we want to treat it as a binary instead of as an array. +	if val.Type().Elem() == tByte { +		var byteSlice []byte +		for idx := 0; idx < val.Len(); idx++ { +			byteSlice = append(byteSlice, val.Index(idx).Interface().(byte)) +		} +		return vw.WriteBinary(byteSlice) +	} + +	aw, err := vw.WriteArray() +	if err != nil { +		return err +	} + +	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 +		} + +		if lookupErr == errInvalidValue { +			err = vw.WriteNull() +			if err != nil { +				return err +			} +			continue +		} + +		err = currEncoder.EncodeValue(ec, vw, currVal) +		if err != nil { +			return err +		} +	} +	return aw.WriteArrayEnd() +} + +// SliceEncodeValue is the ValueEncoderFunc for slice types. +// +// Deprecated: SliceEncodeValue is not registered by default. Use SliceCodec.EncodeValue instead. +func (dve DefaultValueEncoders) SliceEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Kind() != reflect.Slice { +		return ValueEncoderError{Name: "SliceEncodeValue", Kinds: []reflect.Kind{reflect.Slice}, Received: val} +	} + +	if val.IsNil() { +		return vw.WriteNull() +	} + +	// If we have a []primitive.E we want to treat it as a document instead of as an array. +	if val.Type().ConvertibleTo(tD) { +		d := val.Convert(tD).Interface().(primitive.D) + +		dw, err := vw.WriteDocument() +		if err != nil { +			return err +		} + +		for _, e := range d { +			err = encodeElement(ec, dw, e) +			if err != nil { +				return err +			} +		} + +		return dw.WriteDocumentEnd() +	} + +	aw, err := vw.WriteArray() +	if err != nil { +		return err +	} + +	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 +		} + +		if lookupErr == errInvalidValue { +			err = vw.WriteNull() +			if err != nil { +				return err +			} +			continue +		} + +		err = currEncoder.EncodeValue(ec, vw, currVal) +		if err != nil { +			return err +		} +	} +	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{}. +// +// Deprecated: EmptyInterfaceEncodeValue is not registered by default. Use EmptyInterfaceCodec.EncodeValue instead. +func (dve DefaultValueEncoders) EmptyInterfaceEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Type() != tEmpty { +		return ValueEncoderError{Name: "EmptyInterfaceEncodeValue", Types: []reflect.Type{tEmpty}, Received: val} +	} + +	if val.IsNil() { +		return vw.WriteNull() +	} +	encoder, err := ec.LookupEncoder(val.Elem().Type()) +	if err != nil { +		return err +	} + +	return encoder.EncodeValue(ec, vw, val.Elem()) +} + +// ValueMarshalerEncodeValue is the ValueEncoderFunc for ValueMarshaler implementations. +func (dve DefaultValueEncoders) ValueMarshalerEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	// Either val or a pointer to val must implement ValueMarshaler +	switch { +	case !val.IsValid(): +		return ValueEncoderError{Name: "ValueMarshalerEncodeValue", Types: []reflect.Type{tValueMarshaler}, Received: val} +	case val.Type().Implements(tValueMarshaler): +		// If ValueMarshaler is implemented on a concrete type, make sure that val isn't a nil pointer +		if isImplementationNil(val, tValueMarshaler) { +			return vw.WriteNull() +		} +	case reflect.PtrTo(val.Type()).Implements(tValueMarshaler) && val.CanAddr(): +		val = val.Addr() +	default: +		return ValueEncoderError{Name: "ValueMarshalerEncodeValue", Types: []reflect.Type{tValueMarshaler}, Received: val} +	} + +	fn := val.Convert(tValueMarshaler).MethodByName("MarshalBSONValue") +	returns := fn.Call(nil) +	if !returns[2].IsNil() { +		return returns[2].Interface().(error) +	} +	t, data := returns[0].Interface().(bsontype.Type), returns[1].Interface().([]byte) +	return bsonrw.Copier{}.CopyValueFromBytes(vw, t, data) +} + +// MarshalerEncodeValue is the ValueEncoderFunc for Marshaler implementations. +func (dve DefaultValueEncoders) MarshalerEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	// Either val or a pointer to val must implement Marshaler +	switch { +	case !val.IsValid(): +		return ValueEncoderError{Name: "MarshalerEncodeValue", Types: []reflect.Type{tMarshaler}, Received: val} +	case val.Type().Implements(tMarshaler): +		// If Marshaler is implemented on a concrete type, make sure that val isn't a nil pointer +		if isImplementationNil(val, tMarshaler) { +			return vw.WriteNull() +		} +	case reflect.PtrTo(val.Type()).Implements(tMarshaler) && val.CanAddr(): +		val = val.Addr() +	default: +		return ValueEncoderError{Name: "MarshalerEncodeValue", Types: []reflect.Type{tMarshaler}, Received: val} +	} + +	fn := val.Convert(tMarshaler).MethodByName("MarshalBSON") +	returns := fn.Call(nil) +	if !returns[1].IsNil() { +		return returns[1].Interface().(error) +	} +	data := returns[0].Interface().([]byte) +	return bsonrw.Copier{}.CopyValueFromBytes(vw, bsontype.EmbeddedDocument, data) +} + +// ProxyEncodeValue is the ValueEncoderFunc for Proxy implementations. +func (dve DefaultValueEncoders) ProxyEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	// Either val or a pointer to val must implement Proxy +	switch { +	case !val.IsValid(): +		return ValueEncoderError{Name: "ProxyEncodeValue", Types: []reflect.Type{tProxy}, Received: val} +	case val.Type().Implements(tProxy): +		// If Proxy is implemented on a concrete type, make sure that val isn't a nil pointer +		if isImplementationNil(val, tProxy) { +			return vw.WriteNull() +		} +	case reflect.PtrTo(val.Type()).Implements(tProxy) && val.CanAddr(): +		val = val.Addr() +	default: +		return ValueEncoderError{Name: "ProxyEncodeValue", Types: []reflect.Type{tProxy}, Received: val} +	} + +	fn := val.Convert(tProxy).MethodByName("ProxyBSON") +	returns := fn.Call(nil) +	if !returns[1].IsNil() { +		return returns[1].Interface().(error) +	} +	data := returns[0] +	var encoder ValueEncoder +	var err error +	if data.Elem().IsValid() { +		encoder, err = ec.LookupEncoder(data.Elem().Type()) +	} else { +		encoder, err = ec.LookupEncoder(nil) +	} +	if err != nil { +		return err +	} +	return encoder.EncodeValue(ec, vw, data.Elem()) +} + +// JavaScriptEncodeValue is the ValueEncoderFunc for the primitive.JavaScript type. +func (DefaultValueEncoders) JavaScriptEncodeValue(ectx EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Type() != tJavaScript { +		return ValueEncoderError{Name: "JavaScriptEncodeValue", Types: []reflect.Type{tJavaScript}, Received: val} +	} + +	return vw.WriteJavascript(val.String()) +} + +// SymbolEncodeValue is the ValueEncoderFunc for the primitive.Symbol type. +func (DefaultValueEncoders) SymbolEncodeValue(ectx EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Type() != tSymbol { +		return ValueEncoderError{Name: "SymbolEncodeValue", Types: []reflect.Type{tSymbol}, Received: val} +	} + +	return vw.WriteSymbol(val.String()) +} + +// BinaryEncodeValue is the ValueEncoderFunc for Binary. +func (DefaultValueEncoders) BinaryEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Type() != tBinary { +		return ValueEncoderError{Name: "BinaryEncodeValue", Types: []reflect.Type{tBinary}, Received: val} +	} +	b := val.Interface().(primitive.Binary) + +	return vw.WriteBinaryWithSubtype(b.Data, b.Subtype) +} + +// UndefinedEncodeValue is the ValueEncoderFunc for Undefined. +func (DefaultValueEncoders) UndefinedEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Type() != tUndefined { +		return ValueEncoderError{Name: "UndefinedEncodeValue", Types: []reflect.Type{tUndefined}, Received: val} +	} + +	return vw.WriteUndefined() +} + +// DateTimeEncodeValue is the ValueEncoderFunc for DateTime. +func (DefaultValueEncoders) DateTimeEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Type() != tDateTime { +		return ValueEncoderError{Name: "DateTimeEncodeValue", Types: []reflect.Type{tDateTime}, Received: val} +	} + +	return vw.WriteDateTime(val.Int()) +} + +// NullEncodeValue is the ValueEncoderFunc for Null. +func (DefaultValueEncoders) NullEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Type() != tNull { +		return ValueEncoderError{Name: "NullEncodeValue", Types: []reflect.Type{tNull}, Received: val} +	} + +	return vw.WriteNull() +} + +// RegexEncodeValue is the ValueEncoderFunc for Regex. +func (DefaultValueEncoders) RegexEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Type() != tRegex { +		return ValueEncoderError{Name: "RegexEncodeValue", Types: []reflect.Type{tRegex}, Received: val} +	} + +	regex := val.Interface().(primitive.Regex) + +	return vw.WriteRegex(regex.Pattern, regex.Options) +} + +// DBPointerEncodeValue is the ValueEncoderFunc for DBPointer. +func (DefaultValueEncoders) DBPointerEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Type() != tDBPointer { +		return ValueEncoderError{Name: "DBPointerEncodeValue", Types: []reflect.Type{tDBPointer}, Received: val} +	} + +	dbp := val.Interface().(primitive.DBPointer) + +	return vw.WriteDBPointer(dbp.DB, dbp.Pointer) +} + +// TimestampEncodeValue is the ValueEncoderFunc for Timestamp. +func (DefaultValueEncoders) TimestampEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Type() != tTimestamp { +		return ValueEncoderError{Name: "TimestampEncodeValue", Types: []reflect.Type{tTimestamp}, Received: val} +	} + +	ts := val.Interface().(primitive.Timestamp) + +	return vw.WriteTimestamp(ts.T, ts.I) +} + +// MinKeyEncodeValue is the ValueEncoderFunc for MinKey. +func (DefaultValueEncoders) MinKeyEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Type() != tMinKey { +		return ValueEncoderError{Name: "MinKeyEncodeValue", Types: []reflect.Type{tMinKey}, Received: val} +	} + +	return vw.WriteMinKey() +} + +// MaxKeyEncodeValue is the ValueEncoderFunc for MaxKey. +func (DefaultValueEncoders) MaxKeyEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Type() != tMaxKey { +		return ValueEncoderError{Name: "MaxKeyEncodeValue", Types: []reflect.Type{tMaxKey}, Received: val} +	} + +	return vw.WriteMaxKey() +} + +// CoreDocumentEncodeValue is the ValueEncoderFunc for bsoncore.Document. +func (DefaultValueEncoders) CoreDocumentEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Type() != tCoreDocument { +		return ValueEncoderError{Name: "CoreDocumentEncodeValue", Types: []reflect.Type{tCoreDocument}, Received: val} +	} + +	cdoc := val.Interface().(bsoncore.Document) + +	return bsonrw.Copier{}.CopyDocumentFromBytes(vw, cdoc) +} + +// CodeWithScopeEncodeValue is the ValueEncoderFunc for CodeWithScope. +func (dve DefaultValueEncoders) CodeWithScopeEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Type() != tCodeWithScope { +		return ValueEncoderError{Name: "CodeWithScopeEncodeValue", Types: []reflect.Type{tCodeWithScope}, Received: val} +	} + +	cws := val.Interface().(primitive.CodeWithScope) + +	dw, err := vw.WriteCodeWithScope(string(cws.Code)) +	if err != nil { +		return err +	} + +	sw := sliceWriterPool.Get().(*bsonrw.SliceWriter) +	defer sliceWriterPool.Put(sw) +	*sw = (*sw)[:0] + +	scopeVW := bvwPool.Get(sw) +	defer bvwPool.Put(scopeVW) + +	encoder, err := ec.LookupEncoder(reflect.TypeOf(cws.Scope)) +	if err != nil { +		return err +	} + +	err = encoder.EncodeValue(ec, scopeVW, reflect.ValueOf(cws.Scope)) +	if err != nil { +		return err +	} + +	err = bsonrw.Copier{}.CopyBytesToDocumentWriter(dw, *sw) +	if err != nil { +		return err +	} +	return dw.WriteDocumentEnd() +} + +// isImplementationNil returns if val is a nil pointer and inter is implemented on a concrete type +func isImplementationNil(val reflect.Value, inter reflect.Type) bool { +	vt := val.Type() +	for vt.Kind() == reflect.Ptr { +		vt = vt.Elem() +	} +	return vt.Implements(inter) && val.Kind() == reflect.Ptr && val.IsNil() +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/doc.go b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/doc.go new file mode 100644 index 000000000..5f903ebea --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/doc.go @@ -0,0 +1,90 @@ +// Copyright (C) MongoDB, Inc. 2022-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 provides a system for encoding values to BSON representations and decoding +// values from BSON representations. This package considers both binary BSON and ExtendedJSON as +// BSON representations. The types in this package enable a flexible system for handling this +// encoding and decoding. +// +// The codec system is composed of two parts: +// +// 1) ValueEncoders and ValueDecoders that handle encoding and decoding Go values to and from BSON +// representations. +// +// 2) A Registry that holds these ValueEncoders and ValueDecoders and provides methods for +// retrieving them. +// +// # ValueEncoders and ValueDecoders +// +// The ValueEncoder interface is implemented by types that can encode a provided Go type to BSON. +// The value to encode is provided as a reflect.Value and a bsonrw.ValueWriter is used within the +// EncodeValue method to actually create the BSON representation. For convenience, ValueEncoderFunc +// is provided to allow use of a function with the correct signature as a ValueEncoder. An +// EncodeContext instance is provided to allow implementations to lookup further ValueEncoders and +// to provide configuration information. +// +// The ValueDecoder interface is the inverse of the ValueEncoder. Implementations should ensure that +// the value they receive is settable. Similar to ValueEncoderFunc, ValueDecoderFunc is provided to +// allow the use of a function with the correct signature as a ValueDecoder. A DecodeContext +// instance is provided and serves similar functionality to the EncodeContext. +// +// # Registry and RegistryBuilder +// +// A Registry is an immutable store for ValueEncoders, ValueDecoders, and a type map. See the Registry type +// documentation for examples of registering various custom encoders and decoders. A Registry can be constructed using a +// RegistryBuilder, which handles three main types of codecs: +// +// 1. Type encoders/decoders - These can be registered using the RegisterTypeEncoder and RegisterTypeDecoder methods. +// The registered codec will be invoked when encoding/decoding a value whose type matches the registered type exactly. +// If the registered type is an interface, the codec will be invoked when encoding or decoding values whose type is the +// interface, but not for values with concrete types that implement the interface. +// +// 2. Hook encoders/decoders - These can be registered using the RegisterHookEncoder and RegisterHookDecoder methods. +// These methods only accept interface types and the registered codecs will be invoked when encoding or decoding values +// whose types implement the interface. An example of a hook defined by the driver is bson.Marshaler. The driver will +// call the MarshalBSON method for any value whose type implements bson.Marshaler, regardless of the value's concrete +// type. +// +// 3. Type map entries - This can be used to associate a BSON type with a Go type. These type associations are used when +// decoding into a bson.D/bson.M or a struct field of type interface{}. For example, by default, BSON int32 and int64 +// values decode as Go int32 and int64 instances, respectively, when decoding into a bson.D. The following code would +// change the behavior so these values decode as Go int instances instead: +// +//	intType := reflect.TypeOf(int(0)) +//	registryBuilder.RegisterTypeMapEntry(bsontype.Int32, intType).RegisterTypeMapEntry(bsontype.Int64, intType) +// +// 4. Kind encoder/decoders - These can be registered using the RegisterDefaultEncoder and RegisterDefaultDecoder +// methods. The registered codec will be invoked when encoding or decoding values whose reflect.Kind matches the +// registered reflect.Kind as long as the value's type doesn't match a registered type or hook encoder/decoder first. +// These methods should be used to change the behavior for all values for a specific kind. +// +// # Registry Lookup Procedure +// +// When looking up an encoder in a Registry, the precedence rules are as follows: +// +// 1. A type encoder registered for the exact type of the value. +// +// 2. A hook encoder registered for an interface that is implemented by the value or by a pointer to the value. If the +// value matches multiple hooks (e.g. the type implements bsoncodec.Marshaler and bsoncodec.ValueMarshaler), the first +// one registered will be selected. Note that registries constructed using bson.NewRegistryBuilder have driver-defined +// hooks registered for the bsoncodec.Marshaler, bsoncodec.ValueMarshaler, and bsoncodec.Proxy interfaces, so those +// will take precedence over any new hooks. +// +// 3. A kind encoder registered for the value's kind. +// +// If all of these lookups fail to find an encoder, an error of type ErrNoEncoder is returned. The same precedence +// rules apply for decoders, with the exception that an error of type ErrNoDecoder will be returned if no decoder is +// found. +// +// # DefaultValueEncoders and DefaultValueDecoders +// +// The DefaultValueEncoders and DefaultValueDecoders types provide a full set of ValueEncoders and +// ValueDecoders for handling a wide range of Go types, including all of the types within the +// primitive package. To make registering these codecs easier, a helper method on each type is +// provided. For the DefaultValueEncoders type the method is called RegisterDefaultEncoders and for +// the DefaultValueDecoders type the method is called RegisterDefaultDecoders, this method also +// handles registering type map entries for each BSON type. +package bsoncodec diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/empty_interface_codec.go b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/empty_interface_codec.go new file mode 100644 index 000000000..eda417cff --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/empty_interface_codec.go @@ -0,0 +1,147 @@ +// 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 ( +	"reflect" + +	"go.mongodb.org/mongo-driver/bson/bsonoptions" +	"go.mongodb.org/mongo-driver/bson/bsonrw" +	"go.mongodb.org/mongo-driver/bson/bsontype" +	"go.mongodb.org/mongo-driver/bson/primitive" +) + +// EmptyInterfaceCodec is the Codec used for interface{} values. +type EmptyInterfaceCodec struct { +	DecodeBinaryAsSlice bool +} + +var ( +	defaultEmptyInterfaceCodec = NewEmptyInterfaceCodec() + +	_ ValueCodec  = defaultEmptyInterfaceCodec +	_ typeDecoder = defaultEmptyInterfaceCodec +) + +// NewEmptyInterfaceCodec returns a EmptyInterfaceCodec with options opts. +func NewEmptyInterfaceCodec(opts ...*bsonoptions.EmptyInterfaceCodecOptions) *EmptyInterfaceCodec { +	interfaceOpt := bsonoptions.MergeEmptyInterfaceCodecOptions(opts...) + +	codec := EmptyInterfaceCodec{} +	if interfaceOpt.DecodeBinaryAsSlice != nil { +		codec.DecodeBinaryAsSlice = *interfaceOpt.DecodeBinaryAsSlice +	} +	return &codec +} + +// EncodeValue is the ValueEncoderFunc for interface{}. +func (eic EmptyInterfaceCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Type() != tEmpty { +		return ValueEncoderError{Name: "EmptyInterfaceEncodeValue", Types: []reflect.Type{tEmpty}, Received: val} +	} + +	if val.IsNil() { +		return vw.WriteNull() +	} +	encoder, err := ec.LookupEncoder(val.Elem().Type()) +	if err != nil { +		return err +	} + +	return encoder.EncodeValue(ec, vw, val.Elem()) +} + +func (eic EmptyInterfaceCodec) getEmptyInterfaceDecodeType(dc DecodeContext, valueType bsontype.Type) (reflect.Type, error) { +	isDocument := valueType == bsontype.Type(0) || valueType == bsontype.EmbeddedDocument +	if isDocument { +		if dc.defaultDocumentType != nil { +			// If the bsontype is an embedded document and the DocumentType is set on the DecodeContext, then return +			// that type. +			return dc.defaultDocumentType, nil +		} +		if dc.Ancestor != nil { +			// Using ancestor information rather than looking up the type map entry forces consistent decoding. +			// If we're decoding into a bson.D, subdocuments should also be decoded as bson.D, even if a type map entry +			// has been registered. +			return dc.Ancestor, nil +		} +	} + +	rtype, err := dc.LookupTypeMapEntry(valueType) +	if err == nil { +		return rtype, nil +	} + +	if isDocument { +		// For documents, fallback to looking up a type map entry for bsontype.Type(0) or bsontype.EmbeddedDocument, +		// depending on the original valueType. +		var lookupType bsontype.Type +		switch valueType { +		case bsontype.Type(0): +			lookupType = bsontype.EmbeddedDocument +		case bsontype.EmbeddedDocument: +			lookupType = bsontype.Type(0) +		} + +		rtype, err = dc.LookupTypeMapEntry(lookupType) +		if err == nil { +			return rtype, nil +		} +	} + +	return nil, err +} + +func (eic EmptyInterfaceCodec) decodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { +	if t != tEmpty { +		return emptyValue, ValueDecoderError{Name: "EmptyInterfaceDecodeValue", Types: []reflect.Type{tEmpty}, Received: reflect.Zero(t)} +	} + +	rtype, err := eic.getEmptyInterfaceDecodeType(dc, vr.Type()) +	if err != nil { +		switch vr.Type() { +		case bsontype.Null: +			return reflect.Zero(t), vr.ReadNull() +		default: +			return emptyValue, err +		} +	} + +	decoder, err := dc.LookupDecoder(rtype) +	if err != nil { +		return emptyValue, err +	} + +	elem, err := decodeTypeOrValue(decoder, dc, vr, rtype) +	if err != nil { +		return emptyValue, err +	} + +	if eic.DecodeBinaryAsSlice && rtype == tBinary { +		binElem := elem.Interface().(primitive.Binary) +		if binElem.Subtype == bsontype.BinaryGeneric || binElem.Subtype == bsontype.BinaryBinaryOld { +			elem = reflect.ValueOf(binElem.Data) +		} +	} + +	return elem, nil +} + +// DecodeValue is the ValueDecoderFunc for interface{}. +func (eic EmptyInterfaceCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Type() != tEmpty { +		return ValueDecoderError{Name: "EmptyInterfaceDecodeValue", Types: []reflect.Type{tEmpty}, Received: val} +	} + +	elem, err := eic.decodeType(dc, vr, val.Type()) +	if err != nil { +		return err +	} + +	val.Set(elem) +	return nil +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/map_codec.go b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/map_codec.go new file mode 100644 index 000000000..e1fbef9c6 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/map_codec.go @@ -0,0 +1,309 @@ +// 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 ( +	"encoding" +	"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 +	EncodeNilAsEmpty       bool +	EncodeKeysWithStringer bool +} + +var _ ValueCodec = &MapCodec{} + +// KeyMarshaler is the interface implemented by an object that can marshal itself into a string key. +// This applies to types used as map keys and is similar to encoding.TextMarshaler. +type KeyMarshaler interface { +	MarshalKey() (key string, err error) +} + +// KeyUnmarshaler is the interface implemented by an object that can unmarshal a string representation +// of itself. This applies to types used as map keys and is similar to encoding.TextUnmarshaler. +// +// UnmarshalKey must be able to decode the form generated by MarshalKey. +// UnmarshalKey must copy the text if it wishes to retain the text +// after returning. +type KeyUnmarshaler interface { +	UnmarshalKey(key string) error +} + +// 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 +	} +	if mapOpt.EncodeNilAsEmpty != nil { +		codec.EncodeNilAsEmpty = *mapOpt.EncodeNilAsEmpty +	} +	if mapOpt.EncodeKeysWithStringer != nil { +		codec.EncodeKeysWithStringer = *mapOpt.EncodeKeysWithStringer +	} +	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() && !mc.EncodeNilAsEmpty { +		// 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, err := mc.encodeKey(key) +		if err != nil { +			return err +		} + +		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 +		} + +		err = currEncoder.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.Kind() != reflect.Map || (!val.CanSet() && val.IsNil()) { +		return ValueDecoderError{Name: "MapDecodeValue", Kinds: []reflect.Kind{reflect.Map}, Received: val} +	} + +	switch vrType := vr.Type(); vrType { +	case bsontype.Type(0), bsontype.EmbeddedDocument: +	case bsontype.Null: +		val.Set(reflect.Zero(val.Type())) +		return vr.ReadNull() +	case bsontype.Undefined: +		val.Set(reflect.Zero(val.Type())) +		return vr.ReadUndefined() +	default: +		return fmt.Errorf("cannot decode %v into a %s", vrType, 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 +	} +	eTypeDecoder, _ := decoder.(typeDecoder) + +	if eType == tEmpty { +		dc.Ancestor = val.Type() +	} + +	keyType := val.Type().Key() + +	for { +		key, vr, err := dr.ReadElement() +		if err == bsonrw.ErrEOD { +			break +		} +		if err != nil { +			return err +		} + +		k, err := mc.decodeKey(key, keyType) +		if err != nil { +			return err +		} + +		elem, err := decodeTypeOrValueWithInfo(decoder, eTypeDecoder, dc, vr, eType, true) +		if err != nil { +			return newDecodeError(key, err) +		} + +		val.SetMapIndex(k, elem) +	} +	return nil +} + +func clearMap(m reflect.Value) { +	var none reflect.Value +	for _, k := range m.MapKeys() { +		m.SetMapIndex(k, none) +	} +} + +func (mc *MapCodec) encodeKey(val reflect.Value) (string, error) { +	if mc.EncodeKeysWithStringer { +		return fmt.Sprint(val), nil +	} + +	// keys of any string type are used directly +	if val.Kind() == reflect.String { +		return val.String(), nil +	} +	// KeyMarshalers are marshaled +	if km, ok := val.Interface().(KeyMarshaler); ok { +		if val.Kind() == reflect.Ptr && val.IsNil() { +			return "", nil +		} +		buf, err := km.MarshalKey() +		if err == nil { +			return buf, nil +		} +		return "", err +	} +	// keys implement encoding.TextMarshaler are marshaled. +	if km, ok := val.Interface().(encoding.TextMarshaler); ok { +		if val.Kind() == reflect.Ptr && val.IsNil() { +			return "", nil +		} + +		buf, err := km.MarshalText() +		if err != nil { +			return "", err +		} + +		return string(buf), nil +	} + +	switch val.Kind() { +	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: +		return strconv.FormatInt(val.Int(), 10), nil +	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: +		return strconv.FormatUint(val.Uint(), 10), nil +	} +	return "", fmt.Errorf("unsupported key type: %v", val.Type()) +} + +var keyUnmarshalerType = reflect.TypeOf((*KeyUnmarshaler)(nil)).Elem() +var textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() + +func (mc *MapCodec) decodeKey(key string, keyType reflect.Type) (reflect.Value, error) { +	keyVal := reflect.ValueOf(key) +	var err error +	switch { +	// First, if EncodeKeysWithStringer is not enabled, try to decode withKeyUnmarshaler +	case !mc.EncodeKeysWithStringer && reflect.PtrTo(keyType).Implements(keyUnmarshalerType): +		keyVal = reflect.New(keyType) +		v := keyVal.Interface().(KeyUnmarshaler) +		err = v.UnmarshalKey(key) +		keyVal = keyVal.Elem() +	// Try to decode encoding.TextUnmarshalers. +	case reflect.PtrTo(keyType).Implements(textUnmarshalerType): +		keyVal = reflect.New(keyType) +		v := keyVal.Interface().(encoding.TextUnmarshaler) +		err = v.UnmarshalText([]byte(key)) +		keyVal = keyVal.Elem() +	// Otherwise, go to type specific behavior +	default: +		switch keyType.Kind() { +		case reflect.String: +			keyVal = reflect.ValueOf(key).Convert(keyType) +		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: +			n, parseErr := strconv.ParseInt(key, 10, 64) +			if parseErr != nil || reflect.Zero(keyType).OverflowInt(n) { +				err = fmt.Errorf("failed to unmarshal number key %v", key) +			} +			keyVal = reflect.ValueOf(n).Convert(keyType) +		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: +			n, parseErr := strconv.ParseUint(key, 10, 64) +			if parseErr != nil || reflect.Zero(keyType).OverflowUint(n) { +				err = fmt.Errorf("failed to unmarshal number key %v", key) +				break +			} +			keyVal = reflect.ValueOf(n).Convert(keyType) +		case reflect.Float32, reflect.Float64: +			if mc.EncodeKeysWithStringer { +				parsed, err := strconv.ParseFloat(key, 64) +				if err != nil { +					return keyVal, fmt.Errorf("Map key is defined to be a decimal type (%v) but got error %v", keyType.Kind(), err) +				} +				keyVal = reflect.ValueOf(parsed) +				break +			} +			fallthrough +		default: +			return keyVal, fmt.Errorf("unsupported key type: %v", keyType) +		} +	} +	return keyVal, err +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/mode.go b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/mode.go new file mode 100644 index 000000000..fbd9f0a9e --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/mode.go @@ -0,0 +1,65 @@ +// 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" + +type mode int + +const ( +	_ mode = iota +	mTopLevel +	mDocument +	mArray +	mValue +	mElement +	mCodeWithScope +	mSpacer +) + +func (m mode) String() string { +	var str string + +	switch m { +	case mTopLevel: +		str = "TopLevel" +	case mDocument: +		str = "DocumentMode" +	case mArray: +		str = "ArrayMode" +	case mValue: +		str = "ValueMode" +	case mElement: +		str = "ElementMode" +	case mCodeWithScope: +		str = "CodeWithScopeMode" +	case mSpacer: +		str = "CodeWithScopeSpacerFrame" +	default: +		str = "UnknownMode" +	} + +	return str +} + +// TransitionError is an error returned when an invalid progressing a +// ValueReader or ValueWriter state machine occurs. +type TransitionError struct { +	parent      mode +	current     mode +	destination mode +} + +func (te TransitionError) Error() string { +	if te.destination == mode(0) { +		return fmt.Sprintf("invalid state transition: cannot read/write value while in %s", te.current) +	} +	if te.parent == mode(0) { +		return fmt.Sprintf("invalid state transition: %s -> %s", te.current, te.destination) +	} +	return fmt.Sprintf("invalid state transition: %s -> %s; parent %s", te.current, te.destination, te.parent) +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/pointer_codec.go b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/pointer_codec.go new file mode 100644 index 000000000..616a3e701 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/pointer_codec.go @@ -0,0 +1,109 @@ +// 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 ( +	"reflect" +	"sync" + +	"go.mongodb.org/mongo-driver/bson/bsonrw" +	"go.mongodb.org/mongo-driver/bson/bsontype" +) + +var _ ValueEncoder = &PointerCodec{} +var _ ValueDecoder = &PointerCodec{} + +// PointerCodec is the Codec used for pointers. +type PointerCodec struct { +	ecache map[reflect.Type]ValueEncoder +	dcache map[reflect.Type]ValueDecoder +	l      sync.RWMutex +} + +// NewPointerCodec returns a PointerCodec that has been initialized. +func NewPointerCodec() *PointerCodec { +	return &PointerCodec{ +		ecache: make(map[reflect.Type]ValueEncoder), +		dcache: make(map[reflect.Type]ValueDecoder), +	} +} + +// EncodeValue handles encoding a pointer by either encoding it to BSON Null if the pointer is nil +// or looking up an encoder for the type of value the pointer points to. +func (pc *PointerCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if val.Kind() != reflect.Ptr { +		if !val.IsValid() { +			return vw.WriteNull() +		} +		return ValueEncoderError{Name: "PointerCodec.EncodeValue", Kinds: []reflect.Kind{reflect.Ptr}, Received: val} +	} + +	if val.IsNil() { +		return vw.WriteNull() +	} + +	pc.l.RLock() +	enc, ok := pc.ecache[val.Type()] +	pc.l.RUnlock() +	if ok { +		if enc == nil { +			return ErrNoEncoder{Type: val.Type()} +		} +		return enc.EncodeValue(ec, vw, val.Elem()) +	} + +	enc, err := ec.LookupEncoder(val.Type().Elem()) +	pc.l.Lock() +	pc.ecache[val.Type()] = enc +	pc.l.Unlock() +	if err != nil { +		return err +	} + +	return enc.EncodeValue(ec, vw, val.Elem()) +} + +// DecodeValue handles decoding a pointer by looking up a decoder for the type it points to and +// using that to decode. If the BSON value is Null, this method will set the pointer to nil. +func (pc *PointerCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Kind() != reflect.Ptr { +		return ValueDecoderError{Name: "PointerCodec.DecodeValue", Kinds: []reflect.Kind{reflect.Ptr}, Received: val} +	} + +	if vr.Type() == bsontype.Null { +		val.Set(reflect.Zero(val.Type())) +		return vr.ReadNull() +	} +	if vr.Type() == bsontype.Undefined { +		val.Set(reflect.Zero(val.Type())) +		return vr.ReadUndefined() +	} + +	if val.IsNil() { +		val.Set(reflect.New(val.Type().Elem())) +	} + +	pc.l.RLock() +	dec, ok := pc.dcache[val.Type()] +	pc.l.RUnlock() +	if ok { +		if dec == nil { +			return ErrNoDecoder{Type: val.Type()} +		} +		return dec.DecodeValue(dc, vr, val.Elem()) +	} + +	dec, err := dc.LookupDecoder(val.Type().Elem()) +	pc.l.Lock() +	pc.dcache[val.Type()] = dec +	pc.l.Unlock() +	if err != nil { +		return err +	} + +	return dec.DecodeValue(dc, vr, val.Elem()) +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/proxy.go b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/proxy.go new file mode 100644 index 000000000..4cf2b01ab --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/proxy.go @@ -0,0 +1,14 @@ +// 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 + +// Proxy is an interface implemented by types that cannot themselves be directly encoded. Types +// that implement this interface with have ProxyBSON called during the encoding process and that +// value will be encoded in place for the implementer. +type Proxy interface { +	ProxyBSON() (interface{}, error) +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/registry.go b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/registry.go new file mode 100644 index 000000000..80644023c --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/registry.go @@ -0,0 +1,469 @@ +// 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 ( +	"errors" +	"fmt" +	"reflect" +	"sync" + +	"go.mongodb.org/mongo-driver/bson/bsontype" +) + +// ErrNilType is returned when nil is passed to either LookupEncoder or LookupDecoder. +var ErrNilType = errors.New("cannot perform a decoder lookup on <nil>") + +// ErrNotPointer is returned when a non-pointer type is provided to LookupDecoder. +var ErrNotPointer = errors.New("non-pointer provided to LookupDecoder") + +// ErrNoEncoder is returned when there wasn't an encoder available for a type. +type ErrNoEncoder struct { +	Type reflect.Type +} + +func (ene ErrNoEncoder) Error() string { +	if ene.Type == nil { +		return "no encoder found for <nil>" +	} +	return "no encoder found for " + ene.Type.String() +} + +// ErrNoDecoder is returned when there wasn't a decoder available for a type. +type ErrNoDecoder struct { +	Type reflect.Type +} + +func (end ErrNoDecoder) Error() string { +	return "no decoder found for " + end.Type.String() +} + +// ErrNoTypeMapEntry is returned when there wasn't a type available for the provided BSON type. +type ErrNoTypeMapEntry struct { +	Type bsontype.Type +} + +func (entme ErrNoTypeMapEntry) Error() string { +	return "no type map entry found for " + entme.Type.String() +} + +// ErrNotInterface is returned when the provided type is not an interface. +var ErrNotInterface = errors.New("The provided type is not an interface") + +// A RegistryBuilder is used to build a Registry. This type is not goroutine +// safe. +type RegistryBuilder struct { +	typeEncoders      map[reflect.Type]ValueEncoder +	interfaceEncoders []interfaceValueEncoder +	kindEncoders      map[reflect.Kind]ValueEncoder + +	typeDecoders      map[reflect.Type]ValueDecoder +	interfaceDecoders []interfaceValueDecoder +	kindDecoders      map[reflect.Kind]ValueDecoder + +	typeMap map[bsontype.Type]reflect.Type +} + +// A Registry is used to store and retrieve codecs for types and interfaces. This type is the main +// typed passed around and Encoders and Decoders are constructed from it. +type Registry struct { +	typeEncoders map[reflect.Type]ValueEncoder +	typeDecoders map[reflect.Type]ValueDecoder + +	interfaceEncoders []interfaceValueEncoder +	interfaceDecoders []interfaceValueDecoder + +	kindEncoders map[reflect.Kind]ValueEncoder +	kindDecoders map[reflect.Kind]ValueDecoder + +	typeMap map[bsontype.Type]reflect.Type + +	mu sync.RWMutex +} + +// NewRegistryBuilder creates a new empty RegistryBuilder. +func NewRegistryBuilder() *RegistryBuilder { +	return &RegistryBuilder{ +		typeEncoders: make(map[reflect.Type]ValueEncoder), +		typeDecoders: make(map[reflect.Type]ValueDecoder), + +		interfaceEncoders: make([]interfaceValueEncoder, 0), +		interfaceDecoders: make([]interfaceValueDecoder, 0), + +		kindEncoders: make(map[reflect.Kind]ValueEncoder), +		kindDecoders: make(map[reflect.Kind]ValueDecoder), + +		typeMap: make(map[bsontype.Type]reflect.Type), +	} +} + +func buildDefaultRegistry() *Registry { +	rb := NewRegistryBuilder() +	defaultValueEncoders.RegisterDefaultEncoders(rb) +	defaultValueDecoders.RegisterDefaultDecoders(rb) +	return rb.Build() +} + +// RegisterCodec will register the provided ValueCodec for the provided type. +func (rb *RegistryBuilder) RegisterCodec(t reflect.Type, codec ValueCodec) *RegistryBuilder { +	rb.RegisterTypeEncoder(t, codec) +	rb.RegisterTypeDecoder(t, codec) +	return rb +} + +// RegisterTypeEncoder will register the provided ValueEncoder for the provided type. +// +// The type will be used directly, so an encoder can be registered for a type and a different encoder can be registered +// for a pointer to that type. +// +// If the given type is an interface, the encoder will be called when marshalling a type that is that interface. It +// will not be called when marshalling a non-interface type that implements the interface. +func (rb *RegistryBuilder) RegisterTypeEncoder(t reflect.Type, enc ValueEncoder) *RegistryBuilder { +	rb.typeEncoders[t] = enc +	return rb +} + +// RegisterHookEncoder will register an encoder for the provided interface type t. This encoder will be called when +// marshalling a type if the type implements t or a pointer to the type implements t. If the provided type is not +// an interface (i.e. t.Kind() != reflect.Interface), this method will panic. +func (rb *RegistryBuilder) RegisterHookEncoder(t reflect.Type, enc ValueEncoder) *RegistryBuilder { +	if t.Kind() != reflect.Interface { +		panicStr := fmt.Sprintf("RegisterHookEncoder expects a type with kind reflect.Interface, "+ +			"got type %s with kind %s", t, t.Kind()) +		panic(panicStr) +	} + +	for idx, encoder := range rb.interfaceEncoders { +		if encoder.i == t { +			rb.interfaceEncoders[idx].ve = enc +			return rb +		} +	} + +	rb.interfaceEncoders = append(rb.interfaceEncoders, interfaceValueEncoder{i: t, ve: enc}) +	return rb +} + +// RegisterTypeDecoder will register the provided ValueDecoder for the provided type. +// +// The type will be used directly, so a decoder can be registered for a type and a different decoder can be registered +// for a pointer to that type. +// +// If the given type is an interface, the decoder will be called when unmarshalling into a type that is that interface. +// It will not be called when unmarshalling into a non-interface type that implements the interface. +func (rb *RegistryBuilder) RegisterTypeDecoder(t reflect.Type, dec ValueDecoder) *RegistryBuilder { +	rb.typeDecoders[t] = dec +	return rb +} + +// RegisterHookDecoder will register an decoder for the provided interface type t. This decoder will be called when +// unmarshalling into a type if the type implements t or a pointer to the type implements t. If the provided type is not +// an interface (i.e. t.Kind() != reflect.Interface), this method will panic. +func (rb *RegistryBuilder) RegisterHookDecoder(t reflect.Type, dec ValueDecoder) *RegistryBuilder { +	if t.Kind() != reflect.Interface { +		panicStr := fmt.Sprintf("RegisterHookDecoder expects a type with kind reflect.Interface, "+ +			"got type %s with kind %s", t, t.Kind()) +		panic(panicStr) +	} + +	for idx, decoder := range rb.interfaceDecoders { +		if decoder.i == t { +			rb.interfaceDecoders[idx].vd = dec +			return rb +		} +	} + +	rb.interfaceDecoders = append(rb.interfaceDecoders, interfaceValueDecoder{i: t, vd: dec}) +	return rb +} + +// RegisterEncoder registers the provided type and encoder pair. +// +// Deprecated: Use RegisterTypeEncoder or RegisterHookEncoder instead. +func (rb *RegistryBuilder) RegisterEncoder(t reflect.Type, enc ValueEncoder) *RegistryBuilder { +	if t == tEmpty { +		rb.typeEncoders[t] = enc +		return rb +	} +	switch t.Kind() { +	case reflect.Interface: +		for idx, ir := range rb.interfaceEncoders { +			if ir.i == t { +				rb.interfaceEncoders[idx].ve = enc +				return rb +			} +		} + +		rb.interfaceEncoders = append(rb.interfaceEncoders, interfaceValueEncoder{i: t, ve: enc}) +	default: +		rb.typeEncoders[t] = enc +	} +	return rb +} + +// RegisterDecoder registers the provided type and decoder pair. +// +// Deprecated: Use RegisterTypeDecoder or RegisterHookDecoder instead. +func (rb *RegistryBuilder) RegisterDecoder(t reflect.Type, dec ValueDecoder) *RegistryBuilder { +	if t == nil { +		rb.typeDecoders[nil] = dec +		return rb +	} +	if t == tEmpty { +		rb.typeDecoders[t] = dec +		return rb +	} +	switch t.Kind() { +	case reflect.Interface: +		for idx, ir := range rb.interfaceDecoders { +			if ir.i == t { +				rb.interfaceDecoders[idx].vd = dec +				return rb +			} +		} + +		rb.interfaceDecoders = append(rb.interfaceDecoders, interfaceValueDecoder{i: t, vd: dec}) +	default: +		rb.typeDecoders[t] = dec +	} +	return rb +} + +// RegisterDefaultEncoder will registr the provided ValueEncoder to the provided +// kind. +func (rb *RegistryBuilder) RegisterDefaultEncoder(kind reflect.Kind, enc ValueEncoder) *RegistryBuilder { +	rb.kindEncoders[kind] = enc +	return rb +} + +// RegisterDefaultDecoder will register the provided ValueDecoder to the +// provided kind. +func (rb *RegistryBuilder) RegisterDefaultDecoder(kind reflect.Kind, dec ValueDecoder) *RegistryBuilder { +	rb.kindDecoders[kind] = dec +	return rb +} + +// RegisterTypeMapEntry will register the provided type to the BSON type. The primary usage for this +// mapping is decoding situations where an empty interface is used and a default type needs to be +// created and decoded into. +// +// By default, BSON documents will decode into interface{} values as bson.D. To change the default type for BSON +// documents, a type map entry for bsontype.EmbeddedDocument should be registered. For example, to force BSON documents +// to decode to bson.Raw, use the following code: +// +//	rb.RegisterTypeMapEntry(bsontype.EmbeddedDocument, reflect.TypeOf(bson.Raw{})) +func (rb *RegistryBuilder) RegisterTypeMapEntry(bt bsontype.Type, rt reflect.Type) *RegistryBuilder { +	rb.typeMap[bt] = rt +	return rb +} + +// Build creates a Registry from the current state of this RegistryBuilder. +func (rb *RegistryBuilder) Build() *Registry { +	registry := new(Registry) + +	registry.typeEncoders = make(map[reflect.Type]ValueEncoder) +	for t, enc := range rb.typeEncoders { +		registry.typeEncoders[t] = enc +	} + +	registry.typeDecoders = make(map[reflect.Type]ValueDecoder) +	for t, dec := range rb.typeDecoders { +		registry.typeDecoders[t] = dec +	} + +	registry.interfaceEncoders = make([]interfaceValueEncoder, len(rb.interfaceEncoders)) +	copy(registry.interfaceEncoders, rb.interfaceEncoders) + +	registry.interfaceDecoders = make([]interfaceValueDecoder, len(rb.interfaceDecoders)) +	copy(registry.interfaceDecoders, rb.interfaceDecoders) + +	registry.kindEncoders = make(map[reflect.Kind]ValueEncoder) +	for kind, enc := range rb.kindEncoders { +		registry.kindEncoders[kind] = enc +	} + +	registry.kindDecoders = make(map[reflect.Kind]ValueDecoder) +	for kind, dec := range rb.kindDecoders { +		registry.kindDecoders[kind] = dec +	} + +	registry.typeMap = make(map[bsontype.Type]reflect.Type) +	for bt, rt := range rb.typeMap { +		registry.typeMap[bt] = rt +	} + +	return registry +} + +// LookupEncoder inspects the registry for an encoder for the given type. The lookup precedence works as follows: +// +// 1. An encoder registered for the exact type. If the given type represents an interface, an encoder registered using +// RegisterTypeEncoder for the interface will be selected. +// +// 2. An encoder registered using RegisterHookEncoder for an interface implemented by the type or by a pointer to the +// type. +// +// 3. An encoder registered for the reflect.Kind of the value. +// +// If no encoder is found, an error of type ErrNoEncoder is returned. +func (r *Registry) LookupEncoder(t reflect.Type) (ValueEncoder, error) { +	encodererr := ErrNoEncoder{Type: t} +	r.mu.RLock() +	enc, found := r.lookupTypeEncoder(t) +	r.mu.RUnlock() +	if found { +		if enc == nil { +			return nil, ErrNoEncoder{Type: t} +		} +		return enc, nil +	} + +	enc, found = r.lookupInterfaceEncoder(t, true) +	if found { +		r.mu.Lock() +		r.typeEncoders[t] = enc +		r.mu.Unlock() +		return enc, nil +	} + +	if t == nil { +		r.mu.Lock() +		r.typeEncoders[t] = nil +		r.mu.Unlock() +		return nil, encodererr +	} + +	enc, found = r.kindEncoders[t.Kind()] +	if !found { +		r.mu.Lock() +		r.typeEncoders[t] = nil +		r.mu.Unlock() +		return nil, encodererr +	} + +	r.mu.Lock() +	r.typeEncoders[t] = enc +	r.mu.Unlock() +	return enc, nil +} + +func (r *Registry) lookupTypeEncoder(t reflect.Type) (ValueEncoder, bool) { +	enc, found := r.typeEncoders[t] +	return enc, found +} + +func (r *Registry) lookupInterfaceEncoder(t reflect.Type, allowAddr bool) (ValueEncoder, bool) { +	if t == nil { +		return nil, false +	} +	for _, ienc := range r.interfaceEncoders { +		if t.Implements(ienc.i) { +			return ienc.ve, true +		} +		if allowAddr && t.Kind() != reflect.Ptr && reflect.PtrTo(t).Implements(ienc.i) { +			// if *t implements an interface, this will catch if t implements an interface further ahead +			// in interfaceEncoders +			defaultEnc, found := r.lookupInterfaceEncoder(t, false) +			if !found { +				defaultEnc = r.kindEncoders[t.Kind()] +			} +			return newCondAddrEncoder(ienc.ve, defaultEnc), true +		} +	} +	return nil, false +} + +// LookupDecoder inspects the registry for an decoder for the given type. The lookup precedence works as follows: +// +// 1. A decoder registered for the exact type. If the given type represents an interface, a decoder registered using +// RegisterTypeDecoder for the interface will be selected. +// +// 2. A decoder registered using RegisterHookDecoder for an interface implemented by the type or by a pointer to the +// type. +// +// 3. A decoder registered for the reflect.Kind of the value. +// +// If no decoder is found, an error of type ErrNoDecoder is returned. +func (r *Registry) LookupDecoder(t reflect.Type) (ValueDecoder, error) { +	if t == nil { +		return nil, ErrNilType +	} +	decodererr := ErrNoDecoder{Type: t} +	r.mu.RLock() +	dec, found := r.lookupTypeDecoder(t) +	r.mu.RUnlock() +	if found { +		if dec == nil { +			return nil, ErrNoDecoder{Type: t} +		} +		return dec, nil +	} + +	dec, found = r.lookupInterfaceDecoder(t, true) +	if found { +		r.mu.Lock() +		r.typeDecoders[t] = dec +		r.mu.Unlock() +		return dec, nil +	} + +	dec, found = r.kindDecoders[t.Kind()] +	if !found { +		r.mu.Lock() +		r.typeDecoders[t] = nil +		r.mu.Unlock() +		return nil, decodererr +	} + +	r.mu.Lock() +	r.typeDecoders[t] = dec +	r.mu.Unlock() +	return dec, nil +} + +func (r *Registry) lookupTypeDecoder(t reflect.Type) (ValueDecoder, bool) { +	dec, found := r.typeDecoders[t] +	return dec, found +} + +func (r *Registry) lookupInterfaceDecoder(t reflect.Type, allowAddr bool) (ValueDecoder, bool) { +	for _, idec := range r.interfaceDecoders { +		if t.Implements(idec.i) { +			return idec.vd, true +		} +		if allowAddr && t.Kind() != reflect.Ptr && reflect.PtrTo(t).Implements(idec.i) { +			// if *t implements an interface, this will catch if t implements an interface further ahead +			// in interfaceDecoders +			defaultDec, found := r.lookupInterfaceDecoder(t, false) +			if !found { +				defaultDec = r.kindDecoders[t.Kind()] +			} +			return newCondAddrDecoder(idec.vd, defaultDec), true +		} +	} +	return nil, false +} + +// LookupTypeMapEntry inspects the registry's type map for a Go type for the corresponding BSON +// type. If no type is found, ErrNoTypeMapEntry is returned. +func (r *Registry) LookupTypeMapEntry(bt bsontype.Type) (reflect.Type, error) { +	t, ok := r.typeMap[bt] +	if !ok || t == nil { +		return nil, ErrNoTypeMapEntry{Type: bt} +	} +	return t, nil +} + +type interfaceValueEncoder struct { +	i  reflect.Type +	ve ValueEncoder +} + +type interfaceValueDecoder struct { +	i  reflect.Type +	vd ValueDecoder +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/slice_codec.go b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/slice_codec.go new file mode 100644 index 000000000..3c1b6b860 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/slice_codec.go @@ -0,0 +1,199 @@ +// 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" +	"go.mongodb.org/mongo-driver/bson/primitive" +) + +var defaultSliceCodec = NewSliceCodec() + +// SliceCodec is the Codec used for slice values. +type SliceCodec struct { +	EncodeNilAsEmpty bool +} + +var _ ValueCodec = &MapCodec{} + +// NewSliceCodec returns a MapCodec with options opts. +func NewSliceCodec(opts ...*bsonoptions.SliceCodecOptions) *SliceCodec { +	sliceOpt := bsonoptions.MergeSliceCodecOptions(opts...) + +	codec := SliceCodec{} +	if sliceOpt.EncodeNilAsEmpty != nil { +		codec.EncodeNilAsEmpty = *sliceOpt.EncodeNilAsEmpty +	} +	return &codec +} + +// EncodeValue is the ValueEncoder for slice types. +func (sc SliceCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Kind() != reflect.Slice { +		return ValueEncoderError{Name: "SliceEncodeValue", Kinds: []reflect.Kind{reflect.Slice}, Received: val} +	} + +	if val.IsNil() && !sc.EncodeNilAsEmpty { +		return vw.WriteNull() +	} + +	// If we have a []byte we want to treat it as a binary instead of as an array. +	if val.Type().Elem() == tByte { +		var byteSlice []byte +		for idx := 0; idx < val.Len(); idx++ { +			byteSlice = append(byteSlice, val.Index(idx).Interface().(byte)) +		} +		return vw.WriteBinary(byteSlice) +	} + +	// If we have a []primitive.E we want to treat it as a document instead of as an array. +	if val.Type().ConvertibleTo(tD) { +		d := val.Convert(tD).Interface().(primitive.D) + +		dw, err := vw.WriteDocument() +		if err != nil { +			return err +		} + +		for _, e := range d { +			err = encodeElement(ec, dw, e) +			if err != nil { +				return err +			} +		} + +		return dw.WriteDocumentEnd() +	} + +	aw, err := vw.WriteArray() +	if err != nil { +		return err +	} + +	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 := defaultValueEncoders.lookupElementEncoder(ec, encoder, val.Index(idx)) +		if lookupErr != nil && lookupErr != errInvalidValue { +			return lookupErr +		} + +		vw, err := aw.WriteArrayElement() +		if err != nil { +			return err +		} + +		if lookupErr == errInvalidValue { +			err = vw.WriteNull() +			if err != nil { +				return err +			} +			continue +		} + +		err = currEncoder.EncodeValue(ec, vw, currVal) +		if err != nil { +			return err +		} +	} +	return aw.WriteArrayEnd() +} + +// DecodeValue is the ValueDecoder for slice types. +func (sc *SliceCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Kind() != reflect.Slice { +		return ValueDecoderError{Name: "SliceDecodeValue", Kinds: []reflect.Kind{reflect.Slice}, Received: val} +	} + +	switch vrType := vr.Type(); vrType { +	case bsontype.Array: +	case bsontype.Null: +		val.Set(reflect.Zero(val.Type())) +		return vr.ReadNull() +	case bsontype.Undefined: +		val.Set(reflect.Zero(val.Type())) +		return vr.ReadUndefined() +	case bsontype.Type(0), bsontype.EmbeddedDocument: +		if val.Type().Elem() != tE { +			return fmt.Errorf("cannot decode document into %s", val.Type()) +		} +	case bsontype.Binary: +		if val.Type().Elem() != tByte { +			return fmt.Errorf("SliceDecodeValue can only decode a binary into a byte array, got %v", vrType) +		} +		data, subtype, err := vr.ReadBinary() +		if err != nil { +			return err +		} +		if subtype != bsontype.BinaryGeneric && subtype != bsontype.BinaryBinaryOld { +			return fmt.Errorf("SliceDecodeValue can only be used to decode subtype 0x00 or 0x02 for %s, got %v", bsontype.Binary, subtype) +		} + +		if val.IsNil() { +			val.Set(reflect.MakeSlice(val.Type(), 0, len(data))) +		} + +		val.SetLen(0) +		for _, elem := range data { +			val.Set(reflect.Append(val, reflect.ValueOf(elem))) +		} +		return nil +	case bsontype.String: +		if sliceType := val.Type().Elem(); sliceType != tByte { +			return fmt.Errorf("SliceDecodeValue can only decode a string into a byte array, got %v", sliceType) +		} +		str, err := vr.ReadString() +		if err != nil { +			return err +		} +		byteStr := []byte(str) + +		if val.IsNil() { +			val.Set(reflect.MakeSlice(val.Type(), 0, len(byteStr))) +		} + +		val.SetLen(0) +		for _, elem := range byteStr { +			val.Set(reflect.Append(val, reflect.ValueOf(elem))) +		} +		return nil +	default: +		return fmt.Errorf("cannot decode %v into a slice", vrType) +	} + +	var elemsFunc func(DecodeContext, bsonrw.ValueReader, reflect.Value) ([]reflect.Value, error) +	switch val.Type().Elem() { +	case tE: +		dc.Ancestor = val.Type() +		elemsFunc = defaultValueDecoders.decodeD +	default: +		elemsFunc = defaultValueDecoders.decodeDefault +	} + +	elems, err := elemsFunc(dc, vr, val) +	if err != nil { +		return err +	} + +	if val.IsNil() { +		val.Set(reflect.MakeSlice(val.Type(), 0, len(elems))) +	} + +	val.SetLen(0) +	val.Set(reflect.Append(val, elems...)) + +	return nil +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/string_codec.go b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/string_codec.go new file mode 100644 index 000000000..5332b7c3b --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/string_codec.go @@ -0,0 +1,119 @@ +// 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" +) + +// StringCodec is the Codec used for struct values. +type StringCodec struct { +	DecodeObjectIDAsHex bool +} + +var ( +	defaultStringCodec = NewStringCodec() + +	_ ValueCodec  = defaultStringCodec +	_ typeDecoder = defaultStringCodec +) + +// 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()) +} + +func (sc *StringCodec) decodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { +	if t.Kind() != reflect.String { +		return emptyValue, ValueDecoderError{ +			Name:     "StringDecodeValue", +			Kinds:    []reflect.Kind{reflect.String}, +			Received: reflect.Zero(t), +		} +	} + +	var str string +	var err error +	switch vr.Type() { +	case bsontype.String: +		str, err = vr.ReadString() +		if err != nil { +			return emptyValue, err +		} +	case bsontype.ObjectID: +		oid, err := vr.ReadObjectID() +		if err != nil { +			return emptyValue, 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 emptyValue, err +		} +	case bsontype.Binary: +		data, subtype, err := vr.ReadBinary() +		if err != nil { +			return emptyValue, err +		} +		if subtype != bsontype.BinaryGeneric && subtype != bsontype.BinaryBinaryOld { +			return emptyValue, decodeBinaryError{subtype: subtype, typeName: "string"} +		} +		str = string(data) +	case bsontype.Null: +		if err = vr.ReadNull(); err != nil { +			return emptyValue, err +		} +	case bsontype.Undefined: +		if err = vr.ReadUndefined(); err != nil { +			return emptyValue, err +		} +	default: +		return emptyValue, fmt.Errorf("cannot decode %v into a string type", vr.Type()) +	} + +	return reflect.ValueOf(str), nil +} + +// 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} +	} + +	elem, err := sc.decodeType(dctx, vr, val.Type()) +	if err != nil { +		return err +	} + +	val.SetString(elem.String()) +	return nil +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/struct_codec.go b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/struct_codec.go new file mode 100644 index 000000000..be3f2081e --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/struct_codec.go @@ -0,0 +1,664 @@ +// 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 ( +	"errors" +	"fmt" +	"reflect" +	"sort" +	"strings" +	"sync" +	"time" + +	"go.mongodb.org/mongo-driver/bson/bsonoptions" +	"go.mongodb.org/mongo-driver/bson/bsonrw" +	"go.mongodb.org/mongo-driver/bson/bsontype" +) + +// DecodeError represents an error that occurs when unmarshalling BSON bytes into a native Go type. +type DecodeError struct { +	keys    []string +	wrapped error +} + +// Unwrap returns the underlying error +func (de *DecodeError) Unwrap() error { +	return de.wrapped +} + +// Error implements the error interface. +func (de *DecodeError) Error() string { +	// The keys are stored in reverse order because the de.keys slice is builtup while propagating the error up the +	// stack of BSON keys, so we call de.Keys(), which reverses them. +	keyPath := strings.Join(de.Keys(), ".") +	return fmt.Sprintf("error decoding key %s: %v", keyPath, de.wrapped) +} + +// Keys returns the BSON key path that caused an error as a slice of strings. The keys in the slice are in top-down +// order. For example, if the document being unmarshalled was {a: {b: {c: 1}}} and the value for c was supposed to be +// a string, the keys slice will be ["a", "b", "c"]. +func (de *DecodeError) Keys() []string { +	reversedKeys := make([]string, 0, len(de.keys)) +	for idx := len(de.keys) - 1; idx >= 0; idx-- { +		reversedKeys = append(reversedKeys, de.keys[idx]) +	} + +	return reversedKeys +} + +// Zeroer allows custom struct types to implement a report of zero +// state. All struct types that don't implement Zeroer or where IsZero +// returns false are considered to be not zero. +type Zeroer interface { +	IsZero() bool +} + +// StructCodec is the Codec used for struct values. +type StructCodec struct { +	cache                            map[reflect.Type]*structDescription +	l                                sync.RWMutex +	parser                           StructTagParser +	DecodeZeroStruct                 bool +	DecodeDeepZeroInline             bool +	EncodeOmitDefaultStruct          bool +	AllowUnexportedFields            bool +	OverwriteDuplicatedInlinedFields bool +} + +var _ ValueEncoder = &StructCodec{} +var _ ValueDecoder = &StructCodec{} + +// NewStructCodec returns a StructCodec that uses p for struct tag parsing. +func NewStructCodec(p StructTagParser, opts ...*bsonoptions.StructCodecOptions) (*StructCodec, error) { +	if p == nil { +		return nil, errors.New("a StructTagParser must be provided to NewStructCodec") +	} + +	structOpt := bsonoptions.MergeStructCodecOptions(opts...) + +	codec := &StructCodec{ +		cache:  make(map[reflect.Type]*structDescription), +		parser: p, +	} + +	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.OverwriteDuplicatedInlinedFields != nil { +		codec.OverwriteDuplicatedInlinedFields = *structOpt.OverwriteDuplicatedInlinedFields +	} +	if structOpt.AllowUnexportedFields != nil { +		codec.AllowUnexportedFields = *structOpt.AllowUnexportedFields +	} + +	return codec, nil +} + +// EncodeValue handles encoding generic struct types. +func (sc *StructCodec) EncodeValue(r EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Kind() != reflect.Struct { +		return ValueEncoderError{Name: "StructCodec.EncodeValue", Kinds: []reflect.Kind{reflect.Struct}, Received: val} +	} + +	sd, err := sc.describeStruct(r.Registry, val.Type()) +	if err != nil { +		return err +	} + +	dw, err := vw.WriteDocument() +	if err != nil { +		return err +	} +	var rv reflect.Value +	for _, desc := range sd.fl { +		if desc.inline == nil { +			rv = val.Field(desc.idx) +		} else { +			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 { +			return ErrNoEncoder{Type: rv.Type()} +		} + +		encoder := desc.encoder + +		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 { +			continue +		} + +		vw2, err := dw.WriteDocumentElement(desc.name) +		if err != nil { +			return err +		} + +		ectx := EncodeContext{Registry: r.Registry, MinSize: desc.minSize} +		err = encoder.EncodeValue(ectx, vw2, rv) +		if err != nil { +			return err +		} +	} + +	if sd.inlineMap >= 0 { +		rv := val.Field(sd.inlineMap) +		collisionFn := func(key string) bool { +			_, exists := sd.fm[key] +			return exists +		} + +		return defaultMapCodec.mapEncodeValue(r, dw, rv, collisionFn) +	} + +	return dw.WriteDocumentEnd() +} + +func newDecodeError(key string, original error) error { +	de, ok := original.(*DecodeError) +	if !ok { +		return &DecodeError{ +			keys:    []string{key}, +			wrapped: original, +		} +	} + +	de.keys = append(de.keys, key) +	return de +} + +// DecodeValue implements the Codec interface. +// By default, map types in val will not be cleared. If a map has existing key/value pairs, it will be extended with the new ones from vr. +// For slices, the decoder will set the length of the slice to zero and append all elements. The underlying array will not be cleared. +func (sc *StructCodec) DecodeValue(r DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Kind() != reflect.Struct { +		return ValueDecoderError{Name: "StructCodec.DecodeValue", Kinds: []reflect.Kind{reflect.Struct}, Received: val} +	} + +	switch vrType := vr.Type(); vrType { +	case bsontype.Type(0), bsontype.EmbeddedDocument: +	case bsontype.Null: +		if err := vr.ReadNull(); err != nil { +			return err +		} + +		val.Set(reflect.Zero(val.Type())) +		return nil +	case bsontype.Undefined: +		if err := vr.ReadUndefined(); err != nil { +			return err +		} + +		val.Set(reflect.Zero(val.Type())) +		return nil +	default: +		return fmt.Errorf("cannot decode %v into a %s", vrType, val.Type()) +	} + +	sd, err := sc.describeStruct(r.Registry, val.Type()) +	if err != nil { +		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) +		decoder, err = r.LookupDecoder(inlineMap.Type().Elem()) +		if err != nil { +			return err +		} +	} + +	dr, err := vr.ReadDocument() +	if err != nil { +		return err +	} + +	for { +		name, vr, err := dr.ReadElement() +		if err == bsonrw.ErrEOD { +			break +		} +		if err != nil { +			return err +		} + +		fd, exists := sd.fm[name] +		if !exists { +			// if the original name isn't found in the struct description, try again with the name in lowercase +			// this could match if a BSON tag isn't specified because by default, describeStruct lowercases all field +			// names +			fd, exists = sd.fm[strings.ToLower(name)] +		} + +		if !exists { +			if sd.inlineMap < 0 { +				// The encoding/json package requires a flag to return on error for non-existent fields. +				// This functionality seems appropriate for the struct codec. +				err = vr.Skip() +				if err != nil { +					return err +				} +				continue +			} + +			if inlineMap.IsNil() { +				inlineMap.Set(reflect.MakeMap(inlineMap.Type())) +			} + +			elem := reflect.New(inlineMap.Type().Elem()).Elem() +			r.Ancestor = inlineMap.Type() +			err = decoder.DecodeValue(r, vr, elem) +			if err != nil { +				return err +			} +			inlineMap.SetMapIndex(reflect.ValueOf(name), elem) +			continue +		} + +		var field reflect.Value +		if fd.inline == nil { +			field = val.Field(fd.idx) +		} else { +			field, err = getInlineField(val, fd.inline) +			if err != nil { +				return err +			} +		} + +		if !field.CanSet() { // Being settable is a super set of being addressable. +			innerErr := fmt.Errorf("field %v is not settable", field) +			return newDecodeError(fd.name, innerErr) +		} +		if field.Kind() == reflect.Ptr && field.IsNil() { +			field.Set(reflect.New(field.Type().Elem())) +		} +		field = field.Addr() + +		dctx := DecodeContext{Registry: r.Registry, Truncate: fd.truncate || r.Truncate} +		if fd.decoder == nil { +			return newDecodeError(fd.name, ErrNoDecoder{Type: field.Elem().Type()}) +		} + +		err = fd.decoder.DecodeValue(dctx, vr, field.Elem()) +		if err != nil { +			return newDecodeError(fd.name, err) +		} +	} + +	return nil +} + +func (sc *StructCodec) isZero(i interface{}) bool { +	v := reflect.ValueOf(i) + +	// check the value validity +	if !v.IsValid() { +		return true +	} + +	if z, ok := v.Interface().(Zeroer); ok && (v.Kind() != reflect.Ptr || !v.IsNil()) { +		return z.IsZero() +	} + +	switch v.Kind() { +	case reflect.Array, reflect.Map, reflect.Slice, reflect.String: +		return v.Len() == 0 +	case reflect.Bool: +		return !v.Bool() +	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: +		return v.Int() == 0 +	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: +		return v.Uint() == 0 +	case reflect.Float32, reflect.Float64: +		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 +} + +type structDescription struct { +	fm        map[string]fieldDescription +	fl        []fieldDescription +	inlineMap int +	inline    bool +} + +type fieldDescription struct { +	name      string // BSON key name +	fieldName string // struct field name +	idx       int +	omitEmpty bool +	minSize   bool +	truncate  bool +	inline    []int +	encoder   ValueEncoder +	decoder   ValueDecoder +} + +type byIndex []fieldDescription + +func (bi byIndex) Len() int { return len(bi) } + +func (bi byIndex) Swap(i, j int) { bi[i], bi[j] = bi[j], bi[i] } + +func (bi byIndex) Less(i, j int) bool { +	// If a field is inlined, its index in the top level struct is stored at inline[0] +	iIdx, jIdx := bi[i].idx, bi[j].idx +	if len(bi[i].inline) > 0 { +		iIdx = bi[i].inline[0] +	} +	if len(bi[j].inline) > 0 { +		jIdx = bi[j].inline[0] +	} +	if iIdx != jIdx { +		return iIdx < jIdx +	} +	for k, biik := range bi[i].inline { +		if k >= len(bi[j].inline) { +			return false +		} +		if biik != bi[j].inline[k] { +			return biik < bi[j].inline[k] +		} +	} +	return len(bi[i].inline) < len(bi[j].inline) +} + +func (sc *StructCodec) describeStruct(r *Registry, t reflect.Type) (*structDescription, error) { +	// We need to analyze the struct, including getting the tags, collecting +	// information about inlining, and create a map of the field name to the field. +	sc.l.RLock() +	ds, exists := sc.cache[t] +	sc.l.RUnlock() +	if exists { +		return ds, nil +	} + +	numFields := t.NumField() +	sd := &structDescription{ +		fm:        make(map[string]fieldDescription, numFields), +		fl:        make([]fieldDescription, 0, numFields), +		inlineMap: -1, +	} + +	var fields []fieldDescription +	for i := 0; i < numFields; i++ { +		sf := t.Field(i) +		if sf.PkgPath != "" && (!sc.AllowUnexportedFields || !sf.Anonymous) { +			// field is private or unexported fields aren't allowed, ignore +			continue +		} + +		sfType := sf.Type +		encoder, err := r.LookupEncoder(sfType) +		if err != nil { +			encoder = nil +		} +		decoder, err := r.LookupDecoder(sfType) +		if err != nil { +			decoder = nil +		} + +		description := fieldDescription{ +			fieldName: sf.Name, +			idx:       i, +			encoder:   encoder, +			decoder:   decoder, +		} + +		stags, err := sc.parser.ParseStructTags(sf) +		if err != nil { +			return nil, err +		} +		if stags.Skip { +			continue +		} +		description.name = stags.Name +		description.omitEmpty = stags.OmitEmpty +		description.minSize = stags.MinSize +		description.truncate = stags.Truncate + +		if stags.Inline { +			sd.inline = true +			switch sfType.Kind() { +			case reflect.Map: +				if sd.inlineMap >= 0 { +					return nil, errors.New("(struct " + t.String() + ") multiple inline maps") +				} +				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, sfType) +				if err != nil { +					return nil, err +				} +				for _, fd := range inlinesf.fl { +					if fd.inline == nil { +						fd.inline = []int{i, fd.idx} +					} else { +						fd.inline = append([]int{i}, fd.inline...) +					} +					fields = append(fields, fd) + +				} +			default: +				return nil, fmt.Errorf("(struct %s) inline fields must be a struct, a struct pointer, or a map", t.String()) +			} +			continue +		} +		fields = append(fields, description) +	} + +	// Sort fieldDescriptions by name and use dominance rules to determine which should be added for each name +	sort.Slice(fields, func(i, j int) bool { +		x := fields +		// sort field by name, breaking ties with depth, then +		// breaking ties with index sequence. +		if x[i].name != x[j].name { +			return x[i].name < x[j].name +		} +		if len(x[i].inline) != len(x[j].inline) { +			return len(x[i].inline) < len(x[j].inline) +		} +		return byIndex(x).Less(i, j) +	}) + +	for advance, i := 0, 0; i < len(fields); i += advance { +		// One iteration per name. +		// Find the sequence of fields with the name of this first field. +		fi := fields[i] +		name := fi.name +		for advance = 1; i+advance < len(fields); advance++ { +			fj := fields[i+advance] +			if fj.name != name { +				break +			} +		} +		if advance == 1 { // Only one field with this name +			sd.fl = append(sd.fl, fi) +			sd.fm[name] = fi +			continue +		} +		dominant, ok := dominantField(fields[i : i+advance]) +		if !ok || !sc.OverwriteDuplicatedInlinedFields { +			return nil, fmt.Errorf("struct %s has duplicated key %s", t.String(), name) +		} +		sd.fl = append(sd.fl, dominant) +		sd.fm[name] = dominant +	} + +	sort.Sort(byIndex(sd.fl)) + +	sc.l.Lock() +	sc.cache[t] = sd +	sc.l.Unlock() + +	return sd, nil +} + +// dominantField looks through the fields, all of which are known to +// have the same name, to find the single field that dominates the +// others using Go's inlining rules. If there are multiple top-level +// fields, the boolean will be false: This condition is an error in Go +// and we skip all the fields. +func dominantField(fields []fieldDescription) (fieldDescription, bool) { +	// The fields are sorted in increasing index-length order, then by presence of tag. +	// That means that the first field is the dominant one. We need only check +	// for error cases: two fields at top level. +	if len(fields) > 1 && +		len(fields[0].inline) == len(fields[1].inline) { +		return fieldDescription{}, false +	} +	return fields[0], true +} + +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/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/struct_tag_parser.go b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/struct_tag_parser.go new file mode 100644 index 000000000..62708c5c7 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/struct_tag_parser.go @@ -0,0 +1,139 @@ +// 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 ( +	"reflect" +	"strings" +) + +// StructTagParser returns the struct tags for a given struct field. +type StructTagParser interface { +	ParseStructTags(reflect.StructField) (StructTags, error) +} + +// StructTagParserFunc is an adapter that allows a generic function to be used +// as a StructTagParser. +type StructTagParserFunc func(reflect.StructField) (StructTags, error) + +// ParseStructTags implements the StructTagParser interface. +func (stpf StructTagParserFunc) ParseStructTags(sf reflect.StructField) (StructTags, error) { +	return stpf(sf) +} + +// StructTags represents the struct tag fields that the StructCodec uses during +// the encoding and decoding process. +// +// In the case of a struct, the lowercased field name is used as the key for each exported +// field but this behavior may be changed using a struct tag. The tag may also contain flags to +// adjust the marshalling behavior for the field. +// +// The properties are defined below: +// +//	OmitEmpty  Only include the field if it's not set to the zero value for the type or to +//	           empty slices or maps. +// +//	MinSize    Marshal an integer of a type larger than 32 bits value as an int32, if that's +//	           feasible while preserving the numeric value. +// +//	Truncate   When unmarshaling a BSON double, it is permitted to lose precision to fit within +//	           a float32. +// +//	Inline     Inline the field, which must be a struct or a map, causing all of its fields +//	           or keys to be processed as if they were part of the outer struct. For maps, +//	           keys must not conflict with the bson keys of other struct fields. +// +//	Skip       This struct field should be skipped. This is usually denoted by parsing a "-" +//	           for the name. +// +// TODO(skriptble): Add tags for undefined as nil and for null as nil. +type StructTags struct { +	Name      string +	OmitEmpty bool +	MinSize   bool +	Truncate  bool +	Inline    bool +	Skip      bool +} + +// DefaultStructTagParser is the StructTagParser used by the StructCodec by default. +// It will handle the bson struct tag. See the documentation for StructTags to see +// what each of the returned fields means. +// +// If there is no name in the struct tag fields, the struct field name is lowercased. +// The tag formats accepted are: +// +//	"[<key>][,<flag1>[,<flag2>]]" +// +//	`(...) bson:"[<key>][,<flag1>[,<flag2>]]" (...)` +// +// An example: +// +//	type T struct { +//	    A bool +//	    B int    "myb" +//	    C string "myc,omitempty" +//	    D string `bson:",omitempty" json:"jsonkey"` +//	    E int64  ",minsize" +//	    F int64  "myf,omitempty,minsize" +//	} +// +// A struct tag either consisting entirely of '-' or with a bson key with a +// value consisting entirely of '-' will return a StructTags with Skip true and +// the remaining fields will be their default values. +var DefaultStructTagParser StructTagParserFunc = func(sf reflect.StructField) (StructTags, error) { +	key := strings.ToLower(sf.Name) +	tag, ok := sf.Tag.Lookup("bson") +	if !ok && !strings.Contains(string(sf.Tag), ":") && len(sf.Tag) > 0 { +		tag = string(sf.Tag) +	} +	return parseTags(key, tag) +} + +func parseTags(key string, tag string) (StructTags, error) { +	var st StructTags +	if tag == "-" { +		st.Skip = true +		return st, nil +	} + +	for idx, str := range strings.Split(tag, ",") { +		if idx == 0 && str != "" { +			key = str +		} +		switch str { +		case "omitempty": +			st.OmitEmpty = true +		case "minsize": +			st.MinSize = true +		case "truncate": +			st.Truncate = true +		case "inline": +			st.Inline = true +		} +	} + +	st.Name = key + +	return st, nil +} + +// JSONFallbackStructTagParser has the same behavior as DefaultStructTagParser +// but will also fallback to parsing the json tag instead on a field where the +// bson tag isn't available. +var JSONFallbackStructTagParser StructTagParserFunc = func(sf reflect.StructField) (StructTags, error) { +	key := strings.ToLower(sf.Name) +	tag, ok := sf.Tag.Lookup("bson") +	if !ok { +		tag, ok = sf.Tag.Lookup("json") +	} +	if !ok && !strings.Contains(string(sf.Tag), ":") && len(sf.Tag) > 0 { +		tag = string(sf.Tag) +	} + +	return parseTags(key, tag) +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/time_codec.go b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/time_codec.go new file mode 100644 index 000000000..ec7e30f72 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/time_codec.go @@ -0,0 +1,127 @@ +// 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" +	"go.mongodb.org/mongo-driver/bson/primitive" +) + +const ( +	timeFormatString = "2006-01-02T15:04:05.999Z07:00" +) + +// TimeCodec is the Codec used for time.Time values. +type TimeCodec struct { +	UseLocalTimeZone bool +} + +var ( +	defaultTimeCodec = NewTimeCodec() + +	_ ValueCodec  = defaultTimeCodec +	_ typeDecoder = defaultTimeCodec +) + +// 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 +} + +func (tc *TimeCodec) decodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { +	if t != tTime { +		return emptyValue, ValueDecoderError{ +			Name:     "TimeDecodeValue", +			Types:    []reflect.Type{tTime}, +			Received: reflect.Zero(t), +		} +	} + +	var timeVal time.Time +	switch vrType := vr.Type(); vrType { +	case bsontype.DateTime: +		dt, err := vr.ReadDateTime() +		if err != nil { +			return emptyValue, 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 emptyValue, err +		} +		timeVal, err = time.Parse(timeFormatString, timeStr) +		if err != nil { +			return emptyValue, err +		} +	case bsontype.Int64: +		i64, err := vr.ReadInt64() +		if err != nil { +			return emptyValue, err +		} +		timeVal = time.Unix(i64/1000, i64%1000*1000000) +	case bsontype.Timestamp: +		t, _, err := vr.ReadTimestamp() +		if err != nil { +			return emptyValue, err +		} +		timeVal = time.Unix(int64(t), 0) +	case bsontype.Null: +		if err := vr.ReadNull(); err != nil { +			return emptyValue, err +		} +	case bsontype.Undefined: +		if err := vr.ReadUndefined(); err != nil { +			return emptyValue, err +		} +	default: +		return emptyValue, fmt.Errorf("cannot decode %v into a time.Time", vrType) +	} + +	if !tc.UseLocalTimeZone { +		timeVal = timeVal.UTC() +	} +	return reflect.ValueOf(timeVal), nil +} + +// 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} +	} + +	elem, err := tc.decodeType(dc, vr, tTime) +	if err != nil { +		return err +	} + +	val.Set(elem) +	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) +	dt := primitive.NewDateTimeFromTime(tt) +	return vw.WriteDateTime(int64(dt)) +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/types.go b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/types.go new file mode 100644 index 000000000..07f4b70e6 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/types.go @@ -0,0 +1,57 @@ +// 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 ( +	"encoding/json" +	"net/url" +	"reflect" +	"time" + +	"go.mongodb.org/mongo-driver/bson/primitive" +	"go.mongodb.org/mongo-driver/x/bsonx/bsoncore" +) + +var tBool = reflect.TypeOf(false) +var tFloat64 = reflect.TypeOf(float64(0)) +var tInt32 = reflect.TypeOf(int32(0)) +var tInt64 = reflect.TypeOf(int64(0)) +var tString = reflect.TypeOf("") +var tTime = reflect.TypeOf(time.Time{}) + +var tEmpty = reflect.TypeOf((*interface{})(nil)).Elem() +var tByteSlice = reflect.TypeOf([]byte(nil)) +var tByte = reflect.TypeOf(byte(0x00)) +var tURL = reflect.TypeOf(url.URL{}) +var tJSONNumber = reflect.TypeOf(json.Number("")) + +var tValueMarshaler = reflect.TypeOf((*ValueMarshaler)(nil)).Elem() +var tValueUnmarshaler = reflect.TypeOf((*ValueUnmarshaler)(nil)).Elem() +var tMarshaler = reflect.TypeOf((*Marshaler)(nil)).Elem() +var tUnmarshaler = reflect.TypeOf((*Unmarshaler)(nil)).Elem() +var tProxy = reflect.TypeOf((*Proxy)(nil)).Elem() + +var tBinary = reflect.TypeOf(primitive.Binary{}) +var tUndefined = reflect.TypeOf(primitive.Undefined{}) +var tOID = reflect.TypeOf(primitive.ObjectID{}) +var tDateTime = reflect.TypeOf(primitive.DateTime(0)) +var tNull = reflect.TypeOf(primitive.Null{}) +var tRegex = reflect.TypeOf(primitive.Regex{}) +var tCodeWithScope = reflect.TypeOf(primitive.CodeWithScope{}) +var tDBPointer = reflect.TypeOf(primitive.DBPointer{}) +var tJavaScript = reflect.TypeOf(primitive.JavaScript("")) +var tSymbol = reflect.TypeOf(primitive.Symbol("")) +var tTimestamp = reflect.TypeOf(primitive.Timestamp{}) +var tDecimal = reflect.TypeOf(primitive.Decimal128{}) +var tMinKey = reflect.TypeOf(primitive.MinKey{}) +var tMaxKey = reflect.TypeOf(primitive.MaxKey{}) +var tD = reflect.TypeOf(primitive.D{}) +var tA = reflect.TypeOf(primitive.A{}) +var tE = reflect.TypeOf(primitive.E{}) + +var tCoreDocument = reflect.TypeOf(bsoncore.Document{}) +var tCoreArray = reflect.TypeOf(bsoncore.Array{}) diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/uint_codec.go b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/uint_codec.go new file mode 100644 index 000000000..0b21ce999 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/uint_codec.go @@ -0,0 +1,173 @@ +// 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" +	"math" +	"reflect" + +	"go.mongodb.org/mongo-driver/bson/bsonoptions" +	"go.mongodb.org/mongo-driver/bson/bsonrw" +	"go.mongodb.org/mongo-driver/bson/bsontype" +) + +// UIntCodec is the Codec used for uint values. +type UIntCodec struct { +	EncodeToMinSize bool +} + +var ( +	defaultUIntCodec = NewUIntCodec() + +	_ ValueCodec  = defaultUIntCodec +	_ typeDecoder = defaultUIntCodec +) + +// NewUIntCodec returns a UIntCodec with options opts. +func NewUIntCodec(opts ...*bsonoptions.UIntCodecOptions) *UIntCodec { +	uintOpt := bsonoptions.MergeUIntCodecOptions(opts...) + +	codec := UIntCodec{} +	if uintOpt.EncodeToMinSize != nil { +		codec.EncodeToMinSize = *uintOpt.EncodeToMinSize +	} +	return &codec +} + +// EncodeValue is the ValueEncoder for uint types. +func (uic *UIntCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	switch val.Kind() { +	case reflect.Uint8, reflect.Uint16: +		return vw.WriteInt32(int32(val.Uint())) +	case reflect.Uint, reflect.Uint32, reflect.Uint64: +		u64 := val.Uint() + +		// If ec.MinSize or if encodeToMinSize is true for a non-uint64 value we should write val as an int32 +		useMinSize := ec.MinSize || (uic.EncodeToMinSize && val.Kind() != reflect.Uint64) + +		if u64 <= math.MaxInt32 && useMinSize { +			return vw.WriteInt32(int32(u64)) +		} +		if u64 > math.MaxInt64 { +			return fmt.Errorf("%d overflows int64", u64) +		} +		return vw.WriteInt64(int64(u64)) +	} + +	return ValueEncoderError{ +		Name:     "UintEncodeValue", +		Kinds:    []reflect.Kind{reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint}, +		Received: val, +	} +} + +func (uic *UIntCodec) decodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { +	var i64 int64 +	var err error +	switch vrType := vr.Type(); vrType { +	case bsontype.Int32: +		i32, err := vr.ReadInt32() +		if err != nil { +			return emptyValue, err +		} +		i64 = int64(i32) +	case bsontype.Int64: +		i64, err = vr.ReadInt64() +		if err != nil { +			return emptyValue, err +		} +	case bsontype.Double: +		f64, err := vr.ReadDouble() +		if err != nil { +			return emptyValue, err +		} +		if !dc.Truncate && math.Floor(f64) != f64 { +			return emptyValue, errCannotTruncate +		} +		if f64 > float64(math.MaxInt64) { +			return emptyValue, fmt.Errorf("%g overflows int64", f64) +		} +		i64 = int64(f64) +	case bsontype.Boolean: +		b, err := vr.ReadBoolean() +		if err != nil { +			return emptyValue, err +		} +		if b { +			i64 = 1 +		} +	case bsontype.Null: +		if err = vr.ReadNull(); err != nil { +			return emptyValue, err +		} +	case bsontype.Undefined: +		if err = vr.ReadUndefined(); err != nil { +			return emptyValue, err +		} +	default: +		return emptyValue, fmt.Errorf("cannot decode %v into an integer type", vrType) +	} + +	switch t.Kind() { +	case reflect.Uint8: +		if i64 < 0 || i64 > math.MaxUint8 { +			return emptyValue, fmt.Errorf("%d overflows uint8", i64) +		} + +		return reflect.ValueOf(uint8(i64)), nil +	case reflect.Uint16: +		if i64 < 0 || i64 > math.MaxUint16 { +			return emptyValue, fmt.Errorf("%d overflows uint16", i64) +		} + +		return reflect.ValueOf(uint16(i64)), nil +	case reflect.Uint32: +		if i64 < 0 || i64 > math.MaxUint32 { +			return emptyValue, fmt.Errorf("%d overflows uint32", i64) +		} + +		return reflect.ValueOf(uint32(i64)), nil +	case reflect.Uint64: +		if i64 < 0 { +			return emptyValue, fmt.Errorf("%d overflows uint64", i64) +		} + +		return reflect.ValueOf(uint64(i64)), nil +	case reflect.Uint: +		if i64 < 0 || int64(uint(i64)) != i64 { // Can we fit this inside of an uint +			return emptyValue, fmt.Errorf("%d overflows uint", i64) +		} + +		return reflect.ValueOf(uint(i64)), nil +	default: +		return emptyValue, ValueDecoderError{ +			Name:     "UintDecodeValue", +			Kinds:    []reflect.Kind{reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint}, +			Received: reflect.Zero(t), +		} +	} +} + +// DecodeValue is the ValueDecoder for uint types. +func (uic *UIntCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() { +		return ValueDecoderError{ +			Name:     "UintDecodeValue", +			Kinds:    []reflect.Kind{reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint}, +			Received: val, +		} +	} + +	elem, err := uic.decodeType(dc, vr, val.Type()) +	if err != nil { +		return err +	} + +	val.SetUint(elem.Uint()) +	return nil +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/byte_slice_codec_options.go b/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/byte_slice_codec_options.go new file mode 100644 index 000000000..b1256a4dc --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/byte_slice_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 + +// ByteSliceCodecOptions represents all possible options for byte slice encoding and decoding. +type ByteSliceCodecOptions struct { +	EncodeNilAsEmpty *bool // Specifies if a nil byte slice should encode as an empty binary instead of null. Defaults to false. +} + +// ByteSliceCodec creates a new *ByteSliceCodecOptions +func ByteSliceCodec() *ByteSliceCodecOptions { +	return &ByteSliceCodecOptions{} +} + +// SetEncodeNilAsEmpty specifies  if a nil byte slice should encode as an empty binary instead of null. Defaults to false. +func (bs *ByteSliceCodecOptions) SetEncodeNilAsEmpty(b bool) *ByteSliceCodecOptions { +	bs.EncodeNilAsEmpty = &b +	return bs +} + +// MergeByteSliceCodecOptions combines the given *ByteSliceCodecOptions into a single *ByteSliceCodecOptions in a last one wins fashion. +func MergeByteSliceCodecOptions(opts ...*ByteSliceCodecOptions) *ByteSliceCodecOptions { +	bs := ByteSliceCodec() +	for _, opt := range opts { +		if opt == nil { +			continue +		} +		if opt.EncodeNilAsEmpty != nil { +			bs.EncodeNilAsEmpty = opt.EncodeNilAsEmpty +		} +	} + +	return bs +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/doc.go b/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/doc.go new file mode 100644 index 000000000..c40973c8d --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/doc.go @@ -0,0 +1,8 @@ +// Copyright (C) MongoDB, Inc. 2022-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 defines the optional configurations for the BSON codecs. +package bsonoptions diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/empty_interface_codec_options.go b/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/empty_interface_codec_options.go new file mode 100644 index 000000000..6caaa000e --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/empty_interface_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 + +// EmptyInterfaceCodecOptions represents all possible options for interface{} encoding and decoding. +type EmptyInterfaceCodecOptions struct { +	DecodeBinaryAsSlice *bool // Specifies if Old and Generic type binarys should default to []slice instead of primitive.Binary. Defaults to false. +} + +// EmptyInterfaceCodec creates a new *EmptyInterfaceCodecOptions +func EmptyInterfaceCodec() *EmptyInterfaceCodecOptions { +	return &EmptyInterfaceCodecOptions{} +} + +// SetDecodeBinaryAsSlice specifies if Old and Generic type binarys should default to []slice instead of primitive.Binary. Defaults to false. +func (e *EmptyInterfaceCodecOptions) SetDecodeBinaryAsSlice(b bool) *EmptyInterfaceCodecOptions { +	e.DecodeBinaryAsSlice = &b +	return e +} + +// MergeEmptyInterfaceCodecOptions combines the given *EmptyInterfaceCodecOptions into a single *EmptyInterfaceCodecOptions in a last one wins fashion. +func MergeEmptyInterfaceCodecOptions(opts ...*EmptyInterfaceCodecOptions) *EmptyInterfaceCodecOptions { +	e := EmptyInterfaceCodec() +	for _, opt := range opts { +		if opt == nil { +			continue +		} +		if opt.DecodeBinaryAsSlice != nil { +			e.DecodeBinaryAsSlice = opt.DecodeBinaryAsSlice +		} +	} + +	return e +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/map_codec_options.go b/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/map_codec_options.go new file mode 100644 index 000000000..7a6a880b8 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/map_codec_options.go @@ -0,0 +1,67 @@ +// 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. +	EncodeNilAsEmpty *bool // Specifies if a nil map should encode as an empty document instead of null. Defaults to false. +	// Specifies how keys should be handled. If false, the behavior matches encoding/json, where the encoding key type must +	// either be a string, an integer type, or implement bsoncodec.KeyMarshaler and the decoding key type must either be a +	// string, an integer type, or implement bsoncodec.KeyUnmarshaler. If true, keys are encoded with fmt.Sprint() and the +	// encoding key type must be a string, an integer type, or a float. If true, the use of Stringer will override +	// TextMarshaler/TextUnmarshaler. Defaults to false. +	EncodeKeysWithStringer *bool +} + +// 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 +} + +// SetEncodeNilAsEmpty specifies if a nil map should encode as an empty document instead of null. Defaults to false. +func (t *MapCodecOptions) SetEncodeNilAsEmpty(b bool) *MapCodecOptions { +	t.EncodeNilAsEmpty = &b +	return t +} + +// SetEncodeKeysWithStringer specifies how keys should be handled. If false, the behavior matches encoding/json, where the +// encoding key type must either be a string, an integer type, or implement bsoncodec.KeyMarshaler and the decoding key +// type must either be a string, an integer type, or implement bsoncodec.KeyUnmarshaler. If true, keys are encoded with +// fmt.Sprint() and the encoding key type must be a string, an integer type, or a float. If true, the use of Stringer +// will override TextMarshaler/TextUnmarshaler. Defaults to false. +func (t *MapCodecOptions) SetEncodeKeysWithStringer(b bool) *MapCodecOptions { +	t.EncodeKeysWithStringer = &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 +		} +		if opt.EncodeNilAsEmpty != nil { +			s.EncodeNilAsEmpty = opt.EncodeNilAsEmpty +		} +		if opt.EncodeKeysWithStringer != nil { +			s.EncodeKeysWithStringer = opt.EncodeKeysWithStringer +		} +	} + +	return s +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/slice_codec_options.go b/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/slice_codec_options.go new file mode 100644 index 000000000..ef965e4b4 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/slice_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 + +// SliceCodecOptions represents all possible options for slice encoding and decoding. +type SliceCodecOptions struct { +	EncodeNilAsEmpty *bool // Specifies if a nil slice should encode as an empty array instead of null. Defaults to false. +} + +// SliceCodec creates a new *SliceCodecOptions +func SliceCodec() *SliceCodecOptions { +	return &SliceCodecOptions{} +} + +// SetEncodeNilAsEmpty specifies  if a nil slice should encode as an empty array instead of null. Defaults to false. +func (s *SliceCodecOptions) SetEncodeNilAsEmpty(b bool) *SliceCodecOptions { +	s.EncodeNilAsEmpty = &b +	return s +} + +// MergeSliceCodecOptions combines the given *SliceCodecOptions into a single *SliceCodecOptions in a last one wins fashion. +func MergeSliceCodecOptions(opts ...*SliceCodecOptions) *SliceCodecOptions { +	s := SliceCodec() +	for _, opt := range opts { +		if opt == nil { +			continue +		} +		if opt.EncodeNilAsEmpty != nil { +			s.EncodeNilAsEmpty = opt.EncodeNilAsEmpty +		} +	} + +	return s +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/string_codec_options.go b/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/string_codec_options.go new file mode 100644 index 000000000..65964f420 --- /dev/null +++ b/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/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/struct_codec_options.go b/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/struct_codec_options.go new file mode 100644 index 000000000..78d1dd866 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/struct_codec_options.go @@ -0,0 +1,87 @@ +// 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 defaultOverwriteDuplicatedInlinedFields = true + +// 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. +	OverwriteDuplicatedInlinedFields *bool // Specifies if fields in inlined structs can be overwritten by higher level struct fields with the same key. Defaults to true. +} + +// 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 +} + +// SetOverwriteDuplicatedInlinedFields specifies if inlined struct fields can be overwritten by higher level struct fields with the +// same bson key. When true and decoding, values will be written to the outermost struct with a matching key, and when +// encoding, keys will have the value of the top-most matching field. When false, decoding and encoding will error if +// there are duplicate keys after the struct is inlined. Defaults to true. +func (t *StructCodecOptions) SetOverwriteDuplicatedInlinedFields(b bool) *StructCodecOptions { +	t.OverwriteDuplicatedInlinedFields = &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 := &StructCodecOptions{ +		OverwriteDuplicatedInlinedFields: &defaultOverwriteDuplicatedInlinedFields, +	} +	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.OverwriteDuplicatedInlinedFields != nil { +			s.OverwriteDuplicatedInlinedFields = opt.OverwriteDuplicatedInlinedFields +		} +		if opt.AllowUnexportedFields != nil { +			s.AllowUnexportedFields = opt.AllowUnexportedFields +		} +	} + +	return s +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/time_codec_options.go b/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/time_codec_options.go new file mode 100644 index 000000000..13496d121 --- /dev/null +++ b/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/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/uint_codec_options.go b/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/uint_codec_options.go new file mode 100644 index 000000000..e08b7f192 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsonoptions/uint_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 + +// UIntCodecOptions represents all possible options for uint encoding and decoding. +type UIntCodecOptions struct { +	EncodeToMinSize *bool // Specifies if all uints except uint64 should be decoded to minimum size bsontype. Defaults to false. +} + +// UIntCodec creates a new *UIntCodecOptions +func UIntCodec() *UIntCodecOptions { +	return &UIntCodecOptions{} +} + +// SetEncodeToMinSize specifies if all uints except uint64 should be decoded to minimum size bsontype. Defaults to false. +func (u *UIntCodecOptions) SetEncodeToMinSize(b bool) *UIntCodecOptions { +	u.EncodeToMinSize = &b +	return u +} + +// MergeUIntCodecOptions combines the given *UIntCodecOptions into a single *UIntCodecOptions in a last one wins fashion. +func MergeUIntCodecOptions(opts ...*UIntCodecOptions) *UIntCodecOptions { +	u := UIntCodec() +	for _, opt := range opts { +		if opt == nil { +			continue +		} +		if opt.EncodeToMinSize != nil { +			u.EncodeToMinSize = opt.EncodeToMinSize +		} +	} + +	return u +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/copier.go b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/copier.go new file mode 100644 index 000000000..5cdf6460b --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/copier.go @@ -0,0 +1,445 @@ +// 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 bsonrw + +import ( +	"fmt" +	"io" + +	"go.mongodb.org/mongo-driver/bson/bsontype" +	"go.mongodb.org/mongo-driver/bson/primitive" +	"go.mongodb.org/mongo-driver/x/bsonx/bsoncore" +) + +// Copier is a type that allows copying between ValueReaders, ValueWriters, and +// []byte values. +type Copier struct{} + +// NewCopier creates a new copier with the given registry. If a nil registry is provided +// a default registry is used. +func NewCopier() Copier { +	return Copier{} +} + +// CopyDocument handles copying a document from src to dst. +func CopyDocument(dst ValueWriter, src ValueReader) error { +	return Copier{}.CopyDocument(dst, src) +} + +// CopyDocument handles copying one document from the src to the dst. +func (c Copier) CopyDocument(dst ValueWriter, src ValueReader) error { +	dr, err := src.ReadDocument() +	if err != nil { +		return err +	} + +	dw, err := dst.WriteDocument() +	if err != nil { +		return err +	} + +	return c.copyDocumentCore(dw, dr) +} + +// CopyArrayFromBytes copies the values from a BSON array represented as a +// []byte to a ValueWriter. +func (c Copier) CopyArrayFromBytes(dst ValueWriter, src []byte) error { +	aw, err := dst.WriteArray() +	if err != nil { +		return err +	} + +	err = c.CopyBytesToArrayWriter(aw, src) +	if err != nil { +		return err +	} + +	return aw.WriteArrayEnd() +} + +// CopyDocumentFromBytes copies the values from a BSON document represented as a +// []byte to a ValueWriter. +func (c Copier) CopyDocumentFromBytes(dst ValueWriter, src []byte) error { +	dw, err := dst.WriteDocument() +	if err != nil { +		return err +	} + +	err = c.CopyBytesToDocumentWriter(dw, src) +	if err != nil { +		return err +	} + +	return dw.WriteDocumentEnd() +} + +type writeElementFn func(key string) (ValueWriter, error) + +// CopyBytesToArrayWriter copies the values from a BSON Array represented as a []byte to an +// ArrayWriter. +func (c Copier) CopyBytesToArrayWriter(dst ArrayWriter, src []byte) error { +	wef := func(_ string) (ValueWriter, error) { +		return dst.WriteArrayElement() +	} + +	return c.copyBytesToValueWriter(src, wef) +} + +// CopyBytesToDocumentWriter copies the values from a BSON document represented as a []byte to a +// DocumentWriter. +func (c Copier) CopyBytesToDocumentWriter(dst DocumentWriter, src []byte) error { +	wef := func(key string) (ValueWriter, error) { +		return dst.WriteDocumentElement(key) +	} + +	return c.copyBytesToValueWriter(src, wef) +} + +func (c Copier) copyBytesToValueWriter(src []byte, wef writeElementFn) error { +	// TODO(skriptble): Create errors types here. Anything thats a tag should be a property. +	length, rem, ok := bsoncore.ReadLength(src) +	if !ok { +		return fmt.Errorf("couldn't read length from src, not enough bytes. length=%d", len(src)) +	} +	if len(src) < int(length) { +		return fmt.Errorf("length read exceeds number of bytes available. length=%d bytes=%d", len(src), length) +	} +	rem = rem[:length-4] + +	var t bsontype.Type +	var key string +	var val bsoncore.Value +	for { +		t, rem, ok = bsoncore.ReadType(rem) +		if !ok { +			return io.EOF +		} +		if t == bsontype.Type(0) { +			if len(rem) != 0 { +				return fmt.Errorf("document end byte found before end of document. remaining bytes=%v", rem) +			} +			break +		} + +		key, rem, ok = bsoncore.ReadKey(rem) +		if !ok { +			return fmt.Errorf("invalid key found. remaining bytes=%v", rem) +		} + +		// write as either array element or document element using writeElementFn +		vw, err := wef(key) +		if err != nil { +			return err +		} + +		val, rem, ok = bsoncore.ReadValue(rem, t) +		if !ok { +			return fmt.Errorf("not enough bytes available to read type. bytes=%d type=%s", len(rem), t) +		} +		err = c.CopyValueFromBytes(vw, t, val.Data) +		if err != nil { +			return err +		} +	} +	return nil +} + +// CopyDocumentToBytes copies an entire document from the ValueReader and +// returns it as bytes. +func (c Copier) CopyDocumentToBytes(src ValueReader) ([]byte, error) { +	return c.AppendDocumentBytes(nil, src) +} + +// AppendDocumentBytes functions the same as CopyDocumentToBytes, but will +// append the result to dst. +func (c Copier) AppendDocumentBytes(dst []byte, src ValueReader) ([]byte, error) { +	if br, ok := src.(BytesReader); ok { +		_, dst, err := br.ReadValueBytes(dst) +		return dst, err +	} + +	vw := vwPool.Get().(*valueWriter) +	defer vwPool.Put(vw) + +	vw.reset(dst) + +	err := c.CopyDocument(vw, src) +	dst = vw.buf +	return dst, err +} + +// AppendArrayBytes copies an array from the ValueReader to dst. +func (c Copier) AppendArrayBytes(dst []byte, src ValueReader) ([]byte, error) { +	if br, ok := src.(BytesReader); ok { +		_, dst, err := br.ReadValueBytes(dst) +		return dst, err +	} + +	vw := vwPool.Get().(*valueWriter) +	defer vwPool.Put(vw) + +	vw.reset(dst) + +	err := c.copyArray(vw, src) +	dst = vw.buf +	return dst, err +} + +// CopyValueFromBytes will write the value represtend by t and src to dst. +func (c Copier) CopyValueFromBytes(dst ValueWriter, t bsontype.Type, src []byte) error { +	if wvb, ok := dst.(BytesWriter); ok { +		return wvb.WriteValueBytes(t, src) +	} + +	vr := vrPool.Get().(*valueReader) +	defer vrPool.Put(vr) + +	vr.reset(src) +	vr.pushElement(t) + +	return c.CopyValue(dst, vr) +} + +// CopyValueToBytes copies a value from src and returns it as a bsontype.Type and a +// []byte. +func (c Copier) CopyValueToBytes(src ValueReader) (bsontype.Type, []byte, error) { +	return c.AppendValueBytes(nil, src) +} + +// AppendValueBytes functions the same as CopyValueToBytes, but will append the +// result to dst. +func (c Copier) AppendValueBytes(dst []byte, src ValueReader) (bsontype.Type, []byte, error) { +	if br, ok := src.(BytesReader); ok { +		return br.ReadValueBytes(dst) +	} + +	vw := vwPool.Get().(*valueWriter) +	defer vwPool.Put(vw) + +	start := len(dst) + +	vw.reset(dst) +	vw.push(mElement) + +	err := c.CopyValue(vw, src) +	if err != nil { +		return 0, dst, err +	} + +	return bsontype.Type(vw.buf[start]), vw.buf[start+2:], nil +} + +// CopyValue will copy a single value from src to dst. +func (c Copier) CopyValue(dst ValueWriter, src ValueReader) error { +	var err error +	switch src.Type() { +	case bsontype.Double: +		var f64 float64 +		f64, err = src.ReadDouble() +		if err != nil { +			break +		} +		err = dst.WriteDouble(f64) +	case bsontype.String: +		var str string +		str, err = src.ReadString() +		if err != nil { +			return err +		} +		err = dst.WriteString(str) +	case bsontype.EmbeddedDocument: +		err = c.CopyDocument(dst, src) +	case bsontype.Array: +		err = c.copyArray(dst, src) +	case bsontype.Binary: +		var data []byte +		var subtype byte +		data, subtype, err = src.ReadBinary() +		if err != nil { +			break +		} +		err = dst.WriteBinaryWithSubtype(data, subtype) +	case bsontype.Undefined: +		err = src.ReadUndefined() +		if err != nil { +			break +		} +		err = dst.WriteUndefined() +	case bsontype.ObjectID: +		var oid primitive.ObjectID +		oid, err = src.ReadObjectID() +		if err != nil { +			break +		} +		err = dst.WriteObjectID(oid) +	case bsontype.Boolean: +		var b bool +		b, err = src.ReadBoolean() +		if err != nil { +			break +		} +		err = dst.WriteBoolean(b) +	case bsontype.DateTime: +		var dt int64 +		dt, err = src.ReadDateTime() +		if err != nil { +			break +		} +		err = dst.WriteDateTime(dt) +	case bsontype.Null: +		err = src.ReadNull() +		if err != nil { +			break +		} +		err = dst.WriteNull() +	case bsontype.Regex: +		var pattern, options string +		pattern, options, err = src.ReadRegex() +		if err != nil { +			break +		} +		err = dst.WriteRegex(pattern, options) +	case bsontype.DBPointer: +		var ns string +		var pointer primitive.ObjectID +		ns, pointer, err = src.ReadDBPointer() +		if err != nil { +			break +		} +		err = dst.WriteDBPointer(ns, pointer) +	case bsontype.JavaScript: +		var js string +		js, err = src.ReadJavascript() +		if err != nil { +			break +		} +		err = dst.WriteJavascript(js) +	case bsontype.Symbol: +		var symbol string +		symbol, err = src.ReadSymbol() +		if err != nil { +			break +		} +		err = dst.WriteSymbol(symbol) +	case bsontype.CodeWithScope: +		var code string +		var srcScope DocumentReader +		code, srcScope, err = src.ReadCodeWithScope() +		if err != nil { +			break +		} + +		var dstScope DocumentWriter +		dstScope, err = dst.WriteCodeWithScope(code) +		if err != nil { +			break +		} +		err = c.copyDocumentCore(dstScope, srcScope) +	case bsontype.Int32: +		var i32 int32 +		i32, err = src.ReadInt32() +		if err != nil { +			break +		} +		err = dst.WriteInt32(i32) +	case bsontype.Timestamp: +		var t, i uint32 +		t, i, err = src.ReadTimestamp() +		if err != nil { +			break +		} +		err = dst.WriteTimestamp(t, i) +	case bsontype.Int64: +		var i64 int64 +		i64, err = src.ReadInt64() +		if err != nil { +			break +		} +		err = dst.WriteInt64(i64) +	case bsontype.Decimal128: +		var d128 primitive.Decimal128 +		d128, err = src.ReadDecimal128() +		if err != nil { +			break +		} +		err = dst.WriteDecimal128(d128) +	case bsontype.MinKey: +		err = src.ReadMinKey() +		if err != nil { +			break +		} +		err = dst.WriteMinKey() +	case bsontype.MaxKey: +		err = src.ReadMaxKey() +		if err != nil { +			break +		} +		err = dst.WriteMaxKey() +	default: +		err = fmt.Errorf("Cannot copy unknown BSON type %s", src.Type()) +	} + +	return err +} + +func (c Copier) copyArray(dst ValueWriter, src ValueReader) error { +	ar, err := src.ReadArray() +	if err != nil { +		return err +	} + +	aw, err := dst.WriteArray() +	if err != nil { +		return err +	} + +	for { +		vr, err := ar.ReadValue() +		if err == ErrEOA { +			break +		} +		if err != nil { +			return err +		} + +		vw, err := aw.WriteArrayElement() +		if err != nil { +			return err +		} + +		err = c.CopyValue(vw, vr) +		if err != nil { +			return err +		} +	} + +	return aw.WriteArrayEnd() +} + +func (c Copier) copyDocumentCore(dw DocumentWriter, dr DocumentReader) error { +	for { +		key, vr, err := dr.ReadElement() +		if err == ErrEOD { +			break +		} +		if err != nil { +			return err +		} + +		vw, err := dw.WriteDocumentElement(key) +		if err != nil { +			return err +		} + +		err = c.CopyValue(vw, vr) +		if err != nil { +			return err +		} +	} + +	return dw.WriteDocumentEnd() +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/doc.go b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/doc.go new file mode 100644 index 000000000..750b0d2af --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/doc.go @@ -0,0 +1,9 @@ +// 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 bsonrw contains abstractions for reading and writing +// BSON and BSON like types from sources. +package bsonrw // import "go.mongodb.org/mongo-driver/bson/bsonrw" diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_parser.go b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_parser.go new file mode 100644 index 000000000..54c76bf74 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_parser.go @@ -0,0 +1,806 @@ +// 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 bsonrw + +import ( +	"encoding/base64" +	"encoding/hex" +	"errors" +	"fmt" +	"io" +	"strings" + +	"go.mongodb.org/mongo-driver/bson/bsontype" +) + +const maxNestingDepth = 200 + +// ErrInvalidJSON indicates the JSON input is invalid +var ErrInvalidJSON = errors.New("invalid JSON input") + +type jsonParseState byte + +const ( +	jpsStartState jsonParseState = iota +	jpsSawBeginObject +	jpsSawEndObject +	jpsSawBeginArray +	jpsSawEndArray +	jpsSawColon +	jpsSawComma +	jpsSawKey +	jpsSawValue +	jpsDoneState +	jpsInvalidState +) + +type jsonParseMode byte + +const ( +	jpmInvalidMode jsonParseMode = iota +	jpmObjectMode +	jpmArrayMode +) + +type extJSONValue struct { +	t bsontype.Type +	v interface{} +} + +type extJSONObject struct { +	keys   []string +	values []*extJSONValue +} + +type extJSONParser struct { +	js *jsonScanner +	s  jsonParseState +	m  []jsonParseMode +	k  string +	v  *extJSONValue + +	err       error +	canonical bool +	depth     int +	maxDepth  int + +	emptyObject bool +	relaxedUUID bool +} + +// newExtJSONParser returns a new extended JSON parser, ready to to begin +// parsing from the first character of the argued json input. It will not +// perform any read-ahead and will therefore not report any errors about +// malformed JSON at this point. +func newExtJSONParser(r io.Reader, canonical bool) *extJSONParser { +	return &extJSONParser{ +		js:        &jsonScanner{r: r}, +		s:         jpsStartState, +		m:         []jsonParseMode{}, +		canonical: canonical, +		maxDepth:  maxNestingDepth, +	} +} + +// peekType examines the next value and returns its BSON Type +func (ejp *extJSONParser) peekType() (bsontype.Type, error) { +	var t bsontype.Type +	var err error +	initialState := ejp.s + +	ejp.advanceState() +	switch ejp.s { +	case jpsSawValue: +		t = ejp.v.t +	case jpsSawBeginArray: +		t = bsontype.Array +	case jpsInvalidState: +		err = ejp.err +	case jpsSawComma: +		// in array mode, seeing a comma means we need to progress again to actually observe a type +		if ejp.peekMode() == jpmArrayMode { +			return ejp.peekType() +		} +	case jpsSawEndArray: +		// this would only be a valid state if we were in array mode, so return end-of-array error +		err = ErrEOA +	case jpsSawBeginObject: +		// peek key to determine type +		ejp.advanceState() +		switch ejp.s { +		case jpsSawEndObject: // empty embedded document +			t = bsontype.EmbeddedDocument +			ejp.emptyObject = true +		case jpsInvalidState: +			err = ejp.err +		case jpsSawKey: +			if initialState == jpsStartState { +				return bsontype.EmbeddedDocument, nil +			} +			t = wrapperKeyBSONType(ejp.k) + +			// if $uuid is encountered, parse as binary subtype 4 +			if ejp.k == "$uuid" { +				ejp.relaxedUUID = true +				t = bsontype.Binary +			} + +			switch t { +			case bsontype.JavaScript: +				// just saw $code, need to check for $scope at same level +				_, err = ejp.readValue(bsontype.JavaScript) +				if err != nil { +					break +				} + +				switch ejp.s { +				case jpsSawEndObject: // type is TypeJavaScript +				case jpsSawComma: +					ejp.advanceState() + +					if ejp.s == jpsSawKey && ejp.k == "$scope" { +						t = bsontype.CodeWithScope +					} else { +						err = fmt.Errorf("invalid extended JSON: unexpected key %s in CodeWithScope object", ejp.k) +					} +				case jpsInvalidState: +					err = ejp.err +				default: +					err = ErrInvalidJSON +				} +			case bsontype.CodeWithScope: +				err = errors.New("invalid extended JSON: code with $scope must contain $code before $scope") +			} +		} +	} + +	return t, err +} + +// readKey parses the next key and its type and returns them +func (ejp *extJSONParser) readKey() (string, bsontype.Type, error) { +	if ejp.emptyObject { +		ejp.emptyObject = false +		return "", 0, ErrEOD +	} + +	// advance to key (or return with error) +	switch ejp.s { +	case jpsStartState: +		ejp.advanceState() +		if ejp.s == jpsSawBeginObject { +			ejp.advanceState() +		} +	case jpsSawBeginObject: +		ejp.advanceState() +	case jpsSawValue, jpsSawEndObject, jpsSawEndArray: +		ejp.advanceState() +		switch ejp.s { +		case jpsSawBeginObject, jpsSawComma: +			ejp.advanceState() +		case jpsSawEndObject: +			return "", 0, ErrEOD +		case jpsDoneState: +			return "", 0, io.EOF +		case jpsInvalidState: +			return "", 0, ejp.err +		default: +			return "", 0, ErrInvalidJSON +		} +	case jpsSawKey: // do nothing (key was peeked before) +	default: +		return "", 0, invalidRequestError("key") +	} + +	// read key +	var key string + +	switch ejp.s { +	case jpsSawKey: +		key = ejp.k +	case jpsSawEndObject: +		return "", 0, ErrEOD +	case jpsInvalidState: +		return "", 0, ejp.err +	default: +		return "", 0, invalidRequestError("key") +	} + +	// check for colon +	ejp.advanceState() +	if err := ensureColon(ejp.s, key); err != nil { +		return "", 0, err +	} + +	// peek at the value to determine type +	t, err := ejp.peekType() +	if err != nil { +		return "", 0, err +	} + +	return key, t, nil +} + +// readValue returns the value corresponding to the Type returned by peekType +func (ejp *extJSONParser) readValue(t bsontype.Type) (*extJSONValue, error) { +	if ejp.s == jpsInvalidState { +		return nil, ejp.err +	} + +	var v *extJSONValue + +	switch t { +	case bsontype.Null, bsontype.Boolean, bsontype.String: +		if ejp.s != jpsSawValue { +			return nil, invalidRequestError(t.String()) +		} +		v = ejp.v +	case bsontype.Int32, bsontype.Int64, bsontype.Double: +		// relaxed version allows these to be literal number values +		if ejp.s == jpsSawValue { +			v = ejp.v +			break +		} +		fallthrough +	case bsontype.Decimal128, bsontype.Symbol, bsontype.ObjectID, bsontype.MinKey, bsontype.MaxKey, bsontype.Undefined: +		switch ejp.s { +		case jpsSawKey: +			// read colon +			ejp.advanceState() +			if err := ensureColon(ejp.s, ejp.k); err != nil { +				return nil, err +			} + +			// read value +			ejp.advanceState() +			if ejp.s != jpsSawValue || !ejp.ensureExtValueType(t) { +				return nil, invalidJSONErrorForType("value", t) +			} + +			v = ejp.v + +			// read end object +			ejp.advanceState() +			if ejp.s != jpsSawEndObject { +				return nil, invalidJSONErrorForType("} after value", t) +			} +		default: +			return nil, invalidRequestError(t.String()) +		} +	case bsontype.Binary, bsontype.Regex, bsontype.Timestamp, bsontype.DBPointer: +		if ejp.s != jpsSawKey { +			return nil, invalidRequestError(t.String()) +		} +		// read colon +		ejp.advanceState() +		if err := ensureColon(ejp.s, ejp.k); err != nil { +			return nil, err +		} + +		ejp.advanceState() +		if t == bsontype.Binary && ejp.s == jpsSawValue { +			// convert relaxed $uuid format +			if ejp.relaxedUUID { +				defer func() { ejp.relaxedUUID = false }() +				uuid, err := ejp.v.parseSymbol() +				if err != nil { +					return nil, err +				} + +				// RFC 4122 defines the length of a UUID as 36 and the hyphens in a UUID as appearing +				// in the 8th, 13th, 18th, and 23rd characters. +				// +				// See https://tools.ietf.org/html/rfc4122#section-3 +				valid := len(uuid) == 36 && +					string(uuid[8]) == "-" && +					string(uuid[13]) == "-" && +					string(uuid[18]) == "-" && +					string(uuid[23]) == "-" +				if !valid { +					return nil, fmt.Errorf("$uuid value does not follow RFC 4122 format regarding length and hyphens") +				} + +				// remove hyphens +				uuidNoHyphens := strings.Replace(uuid, "-", "", -1) +				if len(uuidNoHyphens) != 32 { +					return nil, fmt.Errorf("$uuid value does not follow RFC 4122 format regarding length and hyphens") +				} + +				// convert hex to bytes +				bytes, err := hex.DecodeString(uuidNoHyphens) +				if err != nil { +					return nil, fmt.Errorf("$uuid value does not follow RFC 4122 format regarding hex bytes: %v", err) +				} + +				ejp.advanceState() +				if ejp.s != jpsSawEndObject { +					return nil, invalidJSONErrorForType("$uuid and value and then }", bsontype.Binary) +				} + +				base64 := &extJSONValue{ +					t: bsontype.String, +					v: base64.StdEncoding.EncodeToString(bytes), +				} +				subType := &extJSONValue{ +					t: bsontype.String, +					v: "04", +				} + +				v = &extJSONValue{ +					t: bsontype.EmbeddedDocument, +					v: &extJSONObject{ +						keys:   []string{"base64", "subType"}, +						values: []*extJSONValue{base64, subType}, +					}, +				} + +				break +			} + +			// convert legacy $binary format +			base64 := ejp.v + +			ejp.advanceState() +			if ejp.s != jpsSawComma { +				return nil, invalidJSONErrorForType(",", bsontype.Binary) +			} + +			ejp.advanceState() +			key, t, err := ejp.readKey() +			if err != nil { +				return nil, err +			} +			if key != "$type" { +				return nil, invalidJSONErrorForType("$type", bsontype.Binary) +			} + +			subType, err := ejp.readValue(t) +			if err != nil { +				return nil, err +			} + +			ejp.advanceState() +			if ejp.s != jpsSawEndObject { +				return nil, invalidJSONErrorForType("2 key-value pairs and then }", bsontype.Binary) +			} + +			v = &extJSONValue{ +				t: bsontype.EmbeddedDocument, +				v: &extJSONObject{ +					keys:   []string{"base64", "subType"}, +					values: []*extJSONValue{base64, subType}, +				}, +			} +			break +		} + +		// read KV pairs +		if ejp.s != jpsSawBeginObject { +			return nil, invalidJSONErrorForType("{", t) +		} + +		keys, vals, err := ejp.readObject(2, true) +		if err != nil { +			return nil, err +		} + +		ejp.advanceState() +		if ejp.s != jpsSawEndObject { +			return nil, invalidJSONErrorForType("2 key-value pairs and then }", t) +		} + +		v = &extJSONValue{t: bsontype.EmbeddedDocument, v: &extJSONObject{keys: keys, values: vals}} + +	case bsontype.DateTime: +		switch ejp.s { +		case jpsSawValue: +			v = ejp.v +		case jpsSawKey: +			// read colon +			ejp.advanceState() +			if err := ensureColon(ejp.s, ejp.k); err != nil { +				return nil, err +			} + +			ejp.advanceState() +			switch ejp.s { +			case jpsSawBeginObject: +				keys, vals, err := ejp.readObject(1, true) +				if err != nil { +					return nil, err +				} +				v = &extJSONValue{t: bsontype.EmbeddedDocument, v: &extJSONObject{keys: keys, values: vals}} +			case jpsSawValue: +				if ejp.canonical { +					return nil, invalidJSONError("{") +				} +				v = ejp.v +			default: +				if ejp.canonical { +					return nil, invalidJSONErrorForType("object", t) +				} +				return nil, invalidJSONErrorForType("ISO-8601 Internet Date/Time Format as described in RFC-3339", t) +			} + +			ejp.advanceState() +			if ejp.s != jpsSawEndObject { +				return nil, invalidJSONErrorForType("value and then }", t) +			} +		default: +			return nil, invalidRequestError(t.String()) +		} +	case bsontype.JavaScript: +		switch ejp.s { +		case jpsSawKey: +			// read colon +			ejp.advanceState() +			if err := ensureColon(ejp.s, ejp.k); err != nil { +				return nil, err +			} + +			// read value +			ejp.advanceState() +			if ejp.s != jpsSawValue { +				return nil, invalidJSONErrorForType("value", t) +			} +			v = ejp.v + +			// read end object or comma and just return +			ejp.advanceState() +		case jpsSawEndObject: +			v = ejp.v +		default: +			return nil, invalidRequestError(t.String()) +		} +	case bsontype.CodeWithScope: +		if ejp.s == jpsSawKey && ejp.k == "$scope" { +			v = ejp.v // this is the $code string from earlier + +			// read colon +			ejp.advanceState() +			if err := ensureColon(ejp.s, ejp.k); err != nil { +				return nil, err +			} + +			// read { +			ejp.advanceState() +			if ejp.s != jpsSawBeginObject { +				return nil, invalidJSONError("$scope to be embedded document") +			} +		} else { +			return nil, invalidRequestError(t.String()) +		} +	case bsontype.EmbeddedDocument, bsontype.Array: +		return nil, invalidRequestError(t.String()) +	} + +	return v, nil +} + +// readObject is a utility method for reading full objects of known (or expected) size +// it is useful for extended JSON types such as binary, datetime, regex, and timestamp +func (ejp *extJSONParser) readObject(numKeys int, started bool) ([]string, []*extJSONValue, error) { +	keys := make([]string, numKeys) +	vals := make([]*extJSONValue, numKeys) + +	if !started { +		ejp.advanceState() +		if ejp.s != jpsSawBeginObject { +			return nil, nil, invalidJSONError("{") +		} +	} + +	for i := 0; i < numKeys; i++ { +		key, t, err := ejp.readKey() +		if err != nil { +			return nil, nil, err +		} + +		switch ejp.s { +		case jpsSawKey: +			v, err := ejp.readValue(t) +			if err != nil { +				return nil, nil, err +			} + +			keys[i] = key +			vals[i] = v +		case jpsSawValue: +			keys[i] = key +			vals[i] = ejp.v +		default: +			return nil, nil, invalidJSONError("value") +		} +	} + +	ejp.advanceState() +	if ejp.s != jpsSawEndObject { +		return nil, nil, invalidJSONError("}") +	} + +	return keys, vals, nil +} + +// advanceState reads the next JSON token from the scanner and transitions +// from the current state based on that token's type +func (ejp *extJSONParser) advanceState() { +	if ejp.s == jpsDoneState || ejp.s == jpsInvalidState { +		return +	} + +	jt, err := ejp.js.nextToken() + +	if err != nil { +		ejp.err = err +		ejp.s = jpsInvalidState +		return +	} + +	valid := ejp.validateToken(jt.t) +	if !valid { +		ejp.err = unexpectedTokenError(jt) +		ejp.s = jpsInvalidState +		return +	} + +	switch jt.t { +	case jttBeginObject: +		ejp.s = jpsSawBeginObject +		ejp.pushMode(jpmObjectMode) +		ejp.depth++ + +		if ejp.depth > ejp.maxDepth { +			ejp.err = nestingDepthError(jt.p, ejp.depth) +			ejp.s = jpsInvalidState +		} +	case jttEndObject: +		ejp.s = jpsSawEndObject +		ejp.depth-- + +		if ejp.popMode() != jpmObjectMode { +			ejp.err = unexpectedTokenError(jt) +			ejp.s = jpsInvalidState +		} +	case jttBeginArray: +		ejp.s = jpsSawBeginArray +		ejp.pushMode(jpmArrayMode) +	case jttEndArray: +		ejp.s = jpsSawEndArray + +		if ejp.popMode() != jpmArrayMode { +			ejp.err = unexpectedTokenError(jt) +			ejp.s = jpsInvalidState +		} +	case jttColon: +		ejp.s = jpsSawColon +	case jttComma: +		ejp.s = jpsSawComma +	case jttEOF: +		ejp.s = jpsDoneState +		if len(ejp.m) != 0 { +			ejp.err = unexpectedTokenError(jt) +			ejp.s = jpsInvalidState +		} +	case jttString: +		switch ejp.s { +		case jpsSawComma: +			if ejp.peekMode() == jpmArrayMode { +				ejp.s = jpsSawValue +				ejp.v = extendJSONToken(jt) +				return +			} +			fallthrough +		case jpsSawBeginObject: +			ejp.s = jpsSawKey +			ejp.k = jt.v.(string) +			return +		} +		fallthrough +	default: +		ejp.s = jpsSawValue +		ejp.v = extendJSONToken(jt) +	} +} + +var jpsValidTransitionTokens = map[jsonParseState]map[jsonTokenType]bool{ +	jpsStartState: { +		jttBeginObject: true, +		jttBeginArray:  true, +		jttInt32:       true, +		jttInt64:       true, +		jttDouble:      true, +		jttString:      true, +		jttBool:        true, +		jttNull:        true, +		jttEOF:         true, +	}, +	jpsSawBeginObject: { +		jttEndObject: true, +		jttString:    true, +	}, +	jpsSawEndObject: { +		jttEndObject: true, +		jttEndArray:  true, +		jttComma:     true, +		jttEOF:       true, +	}, +	jpsSawBeginArray: { +		jttBeginObject: true, +		jttBeginArray:  true, +		jttEndArray:    true, +		jttInt32:       true, +		jttInt64:       true, +		jttDouble:      true, +		jttString:      true, +		jttBool:        true, +		jttNull:        true, +	}, +	jpsSawEndArray: { +		jttEndObject: true, +		jttEndArray:  true, +		jttComma:     true, +		jttEOF:       true, +	}, +	jpsSawColon: { +		jttBeginObject: true, +		jttBeginArray:  true, +		jttInt32:       true, +		jttInt64:       true, +		jttDouble:      true, +		jttString:      true, +		jttBool:        true, +		jttNull:        true, +	}, +	jpsSawComma: { +		jttBeginObject: true, +		jttBeginArray:  true, +		jttInt32:       true, +		jttInt64:       true, +		jttDouble:      true, +		jttString:      true, +		jttBool:        true, +		jttNull:        true, +	}, +	jpsSawKey: { +		jttColon: true, +	}, +	jpsSawValue: { +		jttEndObject: true, +		jttEndArray:  true, +		jttComma:     true, +		jttEOF:       true, +	}, +	jpsDoneState:    {}, +	jpsInvalidState: {}, +} + +func (ejp *extJSONParser) validateToken(jtt jsonTokenType) bool { +	switch ejp.s { +	case jpsSawEndObject: +		// if we are at depth zero and the next token is a '{', +		// we can consider it valid only if we are not in array mode. +		if jtt == jttBeginObject && ejp.depth == 0 { +			return ejp.peekMode() != jpmArrayMode +		} +	case jpsSawComma: +		switch ejp.peekMode() { +		// the only valid next token after a comma inside a document is a string (a key) +		case jpmObjectMode: +			return jtt == jttString +		case jpmInvalidMode: +			return false +		} +	} + +	_, ok := jpsValidTransitionTokens[ejp.s][jtt] +	return ok +} + +// ensureExtValueType returns true if the current value has the expected +// value type for single-key extended JSON types. For example, +// {"$numberInt": v} v must be TypeString +func (ejp *extJSONParser) ensureExtValueType(t bsontype.Type) bool { +	switch t { +	case bsontype.MinKey, bsontype.MaxKey: +		return ejp.v.t == bsontype.Int32 +	case bsontype.Undefined: +		return ejp.v.t == bsontype.Boolean +	case bsontype.Int32, bsontype.Int64, bsontype.Double, bsontype.Decimal128, bsontype.Symbol, bsontype.ObjectID: +		return ejp.v.t == bsontype.String +	default: +		return false +	} +} + +func (ejp *extJSONParser) pushMode(m jsonParseMode) { +	ejp.m = append(ejp.m, m) +} + +func (ejp *extJSONParser) popMode() jsonParseMode { +	l := len(ejp.m) +	if l == 0 { +		return jpmInvalidMode +	} + +	m := ejp.m[l-1] +	ejp.m = ejp.m[:l-1] + +	return m +} + +func (ejp *extJSONParser) peekMode() jsonParseMode { +	l := len(ejp.m) +	if l == 0 { +		return jpmInvalidMode +	} + +	return ejp.m[l-1] +} + +func extendJSONToken(jt *jsonToken) *extJSONValue { +	var t bsontype.Type + +	switch jt.t { +	case jttInt32: +		t = bsontype.Int32 +	case jttInt64: +		t = bsontype.Int64 +	case jttDouble: +		t = bsontype.Double +	case jttString: +		t = bsontype.String +	case jttBool: +		t = bsontype.Boolean +	case jttNull: +		t = bsontype.Null +	default: +		return nil +	} + +	return &extJSONValue{t: t, v: jt.v} +} + +func ensureColon(s jsonParseState, key string) error { +	if s != jpsSawColon { +		return fmt.Errorf("invalid JSON input: missing colon after key \"%s\"", key) +	} + +	return nil +} + +func invalidRequestError(s string) error { +	return fmt.Errorf("invalid request to read %s", s) +} + +func invalidJSONError(expected string) error { +	return fmt.Errorf("invalid JSON input; expected %s", expected) +} + +func invalidJSONErrorForType(expected string, t bsontype.Type) error { +	return fmt.Errorf("invalid JSON input; expected %s for %s", expected, t) +} + +func unexpectedTokenError(jt *jsonToken) error { +	switch jt.t { +	case jttInt32, jttInt64, jttDouble: +		return fmt.Errorf("invalid JSON input; unexpected number (%v) at position %d", jt.v, jt.p) +	case jttString: +		return fmt.Errorf("invalid JSON input; unexpected string (\"%v\") at position %d", jt.v, jt.p) +	case jttBool: +		return fmt.Errorf("invalid JSON input; unexpected boolean literal (%v) at position %d", jt.v, jt.p) +	case jttNull: +		return fmt.Errorf("invalid JSON input; unexpected null literal at position %d", jt.p) +	case jttEOF: +		return fmt.Errorf("invalid JSON input; unexpected end of input at position %d", jt.p) +	default: +		return fmt.Errorf("invalid JSON input; unexpected %c at position %d", jt.v.(byte), jt.p) +	} +} + +func nestingDepthError(p, depth int) error { +	return fmt.Errorf("invalid JSON input; nesting too deep (%d levels) at position %d", depth, p) +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_reader.go b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_reader.go new file mode 100644 index 000000000..35832d73a --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_reader.go @@ -0,0 +1,644 @@ +// 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 bsonrw + +import ( +	"fmt" +	"io" +	"sync" + +	"go.mongodb.org/mongo-driver/bson/bsontype" +	"go.mongodb.org/mongo-driver/bson/primitive" +) + +// ExtJSONValueReaderPool is a pool for ValueReaders that read ExtJSON. +type ExtJSONValueReaderPool struct { +	pool sync.Pool +} + +// NewExtJSONValueReaderPool instantiates a new ExtJSONValueReaderPool. +func NewExtJSONValueReaderPool() *ExtJSONValueReaderPool { +	return &ExtJSONValueReaderPool{ +		pool: sync.Pool{ +			New: func() interface{} { +				return new(extJSONValueReader) +			}, +		}, +	} +} + +// Get retrieves a ValueReader from the pool and uses src as the underlying ExtJSON. +func (bvrp *ExtJSONValueReaderPool) Get(r io.Reader, canonical bool) (ValueReader, error) { +	vr := bvrp.pool.Get().(*extJSONValueReader) +	return vr.reset(r, canonical) +} + +// Put inserts a ValueReader into the pool. If the ValueReader is not a ExtJSON ValueReader nothing +// is inserted into the pool and ok will be false. +func (bvrp *ExtJSONValueReaderPool) Put(vr ValueReader) (ok bool) { +	bvr, ok := vr.(*extJSONValueReader) +	if !ok { +		return false +	} + +	bvr, _ = bvr.reset(nil, false) +	bvrp.pool.Put(bvr) +	return true +} + +type ejvrState struct { +	mode  mode +	vType bsontype.Type +	depth int +} + +// extJSONValueReader is for reading extended JSON. +type extJSONValueReader struct { +	p *extJSONParser + +	stack []ejvrState +	frame int +} + +// NewExtJSONValueReader creates a new ValueReader from a given io.Reader +// It will interpret the JSON of r as canonical or relaxed according to the +// given canonical flag +func NewExtJSONValueReader(r io.Reader, canonical bool) (ValueReader, error) { +	return newExtJSONValueReader(r, canonical) +} + +func newExtJSONValueReader(r io.Reader, canonical bool) (*extJSONValueReader, error) { +	ejvr := new(extJSONValueReader) +	return ejvr.reset(r, canonical) +} + +func (ejvr *extJSONValueReader) reset(r io.Reader, canonical bool) (*extJSONValueReader, error) { +	p := newExtJSONParser(r, canonical) +	typ, err := p.peekType() + +	if err != nil { +		return nil, ErrInvalidJSON +	} + +	var m mode +	switch typ { +	case bsontype.EmbeddedDocument: +		m = mTopLevel +	case bsontype.Array: +		m = mArray +	default: +		m = mValue +	} + +	stack := make([]ejvrState, 1, 5) +	stack[0] = ejvrState{ +		mode:  m, +		vType: typ, +	} +	return &extJSONValueReader{ +		p:     p, +		stack: stack, +	}, nil +} + +func (ejvr *extJSONValueReader) advanceFrame() { +	if ejvr.frame+1 >= len(ejvr.stack) { // We need to grow the stack +		length := len(ejvr.stack) +		if length+1 >= cap(ejvr.stack) { +			// double it +			buf := make([]ejvrState, 2*cap(ejvr.stack)+1) +			copy(buf, ejvr.stack) +			ejvr.stack = buf +		} +		ejvr.stack = ejvr.stack[:length+1] +	} +	ejvr.frame++ + +	// Clean the stack +	ejvr.stack[ejvr.frame].mode = 0 +	ejvr.stack[ejvr.frame].vType = 0 +	ejvr.stack[ejvr.frame].depth = 0 +} + +func (ejvr *extJSONValueReader) pushDocument() { +	ejvr.advanceFrame() + +	ejvr.stack[ejvr.frame].mode = mDocument +	ejvr.stack[ejvr.frame].depth = ejvr.p.depth +} + +func (ejvr *extJSONValueReader) pushCodeWithScope() { +	ejvr.advanceFrame() + +	ejvr.stack[ejvr.frame].mode = mCodeWithScope +} + +func (ejvr *extJSONValueReader) pushArray() { +	ejvr.advanceFrame() + +	ejvr.stack[ejvr.frame].mode = mArray +} + +func (ejvr *extJSONValueReader) push(m mode, t bsontype.Type) { +	ejvr.advanceFrame() + +	ejvr.stack[ejvr.frame].mode = m +	ejvr.stack[ejvr.frame].vType = t +} + +func (ejvr *extJSONValueReader) pop() { +	switch ejvr.stack[ejvr.frame].mode { +	case mElement, mValue: +		ejvr.frame-- +	case mDocument, mArray, mCodeWithScope: +		ejvr.frame -= 2 // we pop twice to jump over the vrElement: vrDocument -> vrElement -> vrDocument/TopLevel/etc... +	} +} + +func (ejvr *extJSONValueReader) skipObject() { +	// read entire object until depth returns to 0 (last ending } or ] seen) +	depth := 1 +	for depth > 0 { +		ejvr.p.advanceState() + +		// If object is empty, raise depth and continue. When emptyObject is true, the +		// parser has already read both the opening and closing brackets of an empty +		// object ("{}"), so the next valid token will be part of the parent document, +		// not part of the nested document. +		// +		// If there is a comma, there are remaining fields, emptyObject must be set back +		// to false, and comma must be skipped with advanceState(). +		if ejvr.p.emptyObject { +			if ejvr.p.s == jpsSawComma { +				ejvr.p.emptyObject = false +				ejvr.p.advanceState() +			} +			depth-- +			continue +		} + +		switch ejvr.p.s { +		case jpsSawBeginObject, jpsSawBeginArray: +			depth++ +		case jpsSawEndObject, jpsSawEndArray: +			depth-- +		} +	} +} + +func (ejvr *extJSONValueReader) invalidTransitionErr(destination mode, name string, modes []mode) error { +	te := TransitionError{ +		name:        name, +		current:     ejvr.stack[ejvr.frame].mode, +		destination: destination, +		modes:       modes, +		action:      "read", +	} +	if ejvr.frame != 0 { +		te.parent = ejvr.stack[ejvr.frame-1].mode +	} +	return te +} + +func (ejvr *extJSONValueReader) typeError(t bsontype.Type) error { +	return fmt.Errorf("positioned on %s, but attempted to read %s", ejvr.stack[ejvr.frame].vType, t) +} + +func (ejvr *extJSONValueReader) ensureElementValue(t bsontype.Type, destination mode, callerName string, addModes ...mode) error { +	switch ejvr.stack[ejvr.frame].mode { +	case mElement, mValue: +		if ejvr.stack[ejvr.frame].vType != t { +			return ejvr.typeError(t) +		} +	default: +		modes := []mode{mElement, mValue} +		if addModes != nil { +			modes = append(modes, addModes...) +		} +		return ejvr.invalidTransitionErr(destination, callerName, modes) +	} + +	return nil +} + +func (ejvr *extJSONValueReader) Type() bsontype.Type { +	return ejvr.stack[ejvr.frame].vType +} + +func (ejvr *extJSONValueReader) Skip() error { +	switch ejvr.stack[ejvr.frame].mode { +	case mElement, mValue: +	default: +		return ejvr.invalidTransitionErr(0, "Skip", []mode{mElement, mValue}) +	} + +	defer ejvr.pop() + +	t := ejvr.stack[ejvr.frame].vType +	switch t { +	case bsontype.Array, bsontype.EmbeddedDocument, bsontype.CodeWithScope: +		// read entire array, doc or CodeWithScope +		ejvr.skipObject() +	default: +		_, err := ejvr.p.readValue(t) +		if err != nil { +			return err +		} +	} + +	return nil +} + +func (ejvr *extJSONValueReader) ReadArray() (ArrayReader, error) { +	switch ejvr.stack[ejvr.frame].mode { +	case mTopLevel: // allow reading array from top level +	case mArray: +		return ejvr, nil +	default: +		if err := ejvr.ensureElementValue(bsontype.Array, mArray, "ReadArray", mTopLevel, mArray); err != nil { +			return nil, err +		} +	} + +	ejvr.pushArray() + +	return ejvr, nil +} + +func (ejvr *extJSONValueReader) ReadBinary() (b []byte, btype byte, err error) { +	if err := ejvr.ensureElementValue(bsontype.Binary, 0, "ReadBinary"); err != nil { +		return nil, 0, err +	} + +	v, err := ejvr.p.readValue(bsontype.Binary) +	if err != nil { +		return nil, 0, err +	} + +	b, btype, err = v.parseBinary() + +	ejvr.pop() +	return b, btype, err +} + +func (ejvr *extJSONValueReader) ReadBoolean() (bool, error) { +	if err := ejvr.ensureElementValue(bsontype.Boolean, 0, "ReadBoolean"); err != nil { +		return false, err +	} + +	v, err := ejvr.p.readValue(bsontype.Boolean) +	if err != nil { +		return false, err +	} + +	if v.t != bsontype.Boolean { +		return false, fmt.Errorf("expected type bool, but got type %s", v.t) +	} + +	ejvr.pop() +	return v.v.(bool), nil +} + +func (ejvr *extJSONValueReader) ReadDocument() (DocumentReader, error) { +	switch ejvr.stack[ejvr.frame].mode { +	case mTopLevel: +		return ejvr, nil +	case mElement, mValue: +		if ejvr.stack[ejvr.frame].vType != bsontype.EmbeddedDocument { +			return nil, ejvr.typeError(bsontype.EmbeddedDocument) +		} + +		ejvr.pushDocument() +		return ejvr, nil +	default: +		return nil, ejvr.invalidTransitionErr(mDocument, "ReadDocument", []mode{mTopLevel, mElement, mValue}) +	} +} + +func (ejvr *extJSONValueReader) ReadCodeWithScope() (code string, dr DocumentReader, err error) { +	if err = ejvr.ensureElementValue(bsontype.CodeWithScope, 0, "ReadCodeWithScope"); err != nil { +		return "", nil, err +	} + +	v, err := ejvr.p.readValue(bsontype.CodeWithScope) +	if err != nil { +		return "", nil, err +	} + +	code, err = v.parseJavascript() + +	ejvr.pushCodeWithScope() +	return code, ejvr, err +} + +func (ejvr *extJSONValueReader) ReadDBPointer() (ns string, oid primitive.ObjectID, err error) { +	if err = ejvr.ensureElementValue(bsontype.DBPointer, 0, "ReadDBPointer"); err != nil { +		return "", primitive.NilObjectID, err +	} + +	v, err := ejvr.p.readValue(bsontype.DBPointer) +	if err != nil { +		return "", primitive.NilObjectID, err +	} + +	ns, oid, err = v.parseDBPointer() + +	ejvr.pop() +	return ns, oid, err +} + +func (ejvr *extJSONValueReader) ReadDateTime() (int64, error) { +	if err := ejvr.ensureElementValue(bsontype.DateTime, 0, "ReadDateTime"); err != nil { +		return 0, err +	} + +	v, err := ejvr.p.readValue(bsontype.DateTime) +	if err != nil { +		return 0, err +	} + +	d, err := v.parseDateTime() + +	ejvr.pop() +	return d, err +} + +func (ejvr *extJSONValueReader) ReadDecimal128() (primitive.Decimal128, error) { +	if err := ejvr.ensureElementValue(bsontype.Decimal128, 0, "ReadDecimal128"); err != nil { +		return primitive.Decimal128{}, err +	} + +	v, err := ejvr.p.readValue(bsontype.Decimal128) +	if err != nil { +		return primitive.Decimal128{}, err +	} + +	d, err := v.parseDecimal128() + +	ejvr.pop() +	return d, err +} + +func (ejvr *extJSONValueReader) ReadDouble() (float64, error) { +	if err := ejvr.ensureElementValue(bsontype.Double, 0, "ReadDouble"); err != nil { +		return 0, err +	} + +	v, err := ejvr.p.readValue(bsontype.Double) +	if err != nil { +		return 0, err +	} + +	d, err := v.parseDouble() + +	ejvr.pop() +	return d, err +} + +func (ejvr *extJSONValueReader) ReadInt32() (int32, error) { +	if err := ejvr.ensureElementValue(bsontype.Int32, 0, "ReadInt32"); err != nil { +		return 0, err +	} + +	v, err := ejvr.p.readValue(bsontype.Int32) +	if err != nil { +		return 0, err +	} + +	i, err := v.parseInt32() + +	ejvr.pop() +	return i, err +} + +func (ejvr *extJSONValueReader) ReadInt64() (int64, error) { +	if err := ejvr.ensureElementValue(bsontype.Int64, 0, "ReadInt64"); err != nil { +		return 0, err +	} + +	v, err := ejvr.p.readValue(bsontype.Int64) +	if err != nil { +		return 0, err +	} + +	i, err := v.parseInt64() + +	ejvr.pop() +	return i, err +} + +func (ejvr *extJSONValueReader) ReadJavascript() (code string, err error) { +	if err = ejvr.ensureElementValue(bsontype.JavaScript, 0, "ReadJavascript"); err != nil { +		return "", err +	} + +	v, err := ejvr.p.readValue(bsontype.JavaScript) +	if err != nil { +		return "", err +	} + +	code, err = v.parseJavascript() + +	ejvr.pop() +	return code, err +} + +func (ejvr *extJSONValueReader) ReadMaxKey() error { +	if err := ejvr.ensureElementValue(bsontype.MaxKey, 0, "ReadMaxKey"); err != nil { +		return err +	} + +	v, err := ejvr.p.readValue(bsontype.MaxKey) +	if err != nil { +		return err +	} + +	err = v.parseMinMaxKey("max") + +	ejvr.pop() +	return err +} + +func (ejvr *extJSONValueReader) ReadMinKey() error { +	if err := ejvr.ensureElementValue(bsontype.MinKey, 0, "ReadMinKey"); err != nil { +		return err +	} + +	v, err := ejvr.p.readValue(bsontype.MinKey) +	if err != nil { +		return err +	} + +	err = v.parseMinMaxKey("min") + +	ejvr.pop() +	return err +} + +func (ejvr *extJSONValueReader) ReadNull() error { +	if err := ejvr.ensureElementValue(bsontype.Null, 0, "ReadNull"); err != nil { +		return err +	} + +	v, err := ejvr.p.readValue(bsontype.Null) +	if err != nil { +		return err +	} + +	if v.t != bsontype.Null { +		return fmt.Errorf("expected type null but got type %s", v.t) +	} + +	ejvr.pop() +	return nil +} + +func (ejvr *extJSONValueReader) ReadObjectID() (primitive.ObjectID, error) { +	if err := ejvr.ensureElementValue(bsontype.ObjectID, 0, "ReadObjectID"); err != nil { +		return primitive.ObjectID{}, err +	} + +	v, err := ejvr.p.readValue(bsontype.ObjectID) +	if err != nil { +		return primitive.ObjectID{}, err +	} + +	oid, err := v.parseObjectID() + +	ejvr.pop() +	return oid, err +} + +func (ejvr *extJSONValueReader) ReadRegex() (pattern string, options string, err error) { +	if err = ejvr.ensureElementValue(bsontype.Regex, 0, "ReadRegex"); err != nil { +		return "", "", err +	} + +	v, err := ejvr.p.readValue(bsontype.Regex) +	if err != nil { +		return "", "", err +	} + +	pattern, options, err = v.parseRegex() + +	ejvr.pop() +	return pattern, options, err +} + +func (ejvr *extJSONValueReader) ReadString() (string, error) { +	if err := ejvr.ensureElementValue(bsontype.String, 0, "ReadString"); err != nil { +		return "", err +	} + +	v, err := ejvr.p.readValue(bsontype.String) +	if err != nil { +		return "", err +	} + +	if v.t != bsontype.String { +		return "", fmt.Errorf("expected type string but got type %s", v.t) +	} + +	ejvr.pop() +	return v.v.(string), nil +} + +func (ejvr *extJSONValueReader) ReadSymbol() (symbol string, err error) { +	if err = ejvr.ensureElementValue(bsontype.Symbol, 0, "ReadSymbol"); err != nil { +		return "", err +	} + +	v, err := ejvr.p.readValue(bsontype.Symbol) +	if err != nil { +		return "", err +	} + +	symbol, err = v.parseSymbol() + +	ejvr.pop() +	return symbol, err +} + +func (ejvr *extJSONValueReader) ReadTimestamp() (t uint32, i uint32, err error) { +	if err = ejvr.ensureElementValue(bsontype.Timestamp, 0, "ReadTimestamp"); err != nil { +		return 0, 0, err +	} + +	v, err := ejvr.p.readValue(bsontype.Timestamp) +	if err != nil { +		return 0, 0, err +	} + +	t, i, err = v.parseTimestamp() + +	ejvr.pop() +	return t, i, err +} + +func (ejvr *extJSONValueReader) ReadUndefined() error { +	if err := ejvr.ensureElementValue(bsontype.Undefined, 0, "ReadUndefined"); err != nil { +		return err +	} + +	v, err := ejvr.p.readValue(bsontype.Undefined) +	if err != nil { +		return err +	} + +	err = v.parseUndefined() + +	ejvr.pop() +	return err +} + +func (ejvr *extJSONValueReader) ReadElement() (string, ValueReader, error) { +	switch ejvr.stack[ejvr.frame].mode { +	case mTopLevel, mDocument, mCodeWithScope: +	default: +		return "", nil, ejvr.invalidTransitionErr(mElement, "ReadElement", []mode{mTopLevel, mDocument, mCodeWithScope}) +	} + +	name, t, err := ejvr.p.readKey() + +	if err != nil { +		if err == ErrEOD { +			if ejvr.stack[ejvr.frame].mode == mCodeWithScope { +				_, err := ejvr.p.peekType() +				if err != nil { +					return "", nil, err +				} +			} + +			ejvr.pop() +		} + +		return "", nil, err +	} + +	ejvr.push(mElement, t) +	return name, ejvr, nil +} + +func (ejvr *extJSONValueReader) ReadValue() (ValueReader, error) { +	switch ejvr.stack[ejvr.frame].mode { +	case mArray: +	default: +		return nil, ejvr.invalidTransitionErr(mValue, "ReadValue", []mode{mArray}) +	} + +	t, err := ejvr.p.peekType() +	if err != nil { +		if err == ErrEOA { +			ejvr.pop() +		} + +		return nil, err +	} + +	ejvr.push(mValue, t) +	return ejvr, nil +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_tables.go b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_tables.go new file mode 100644 index 000000000..ba39c9601 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_tables.go @@ -0,0 +1,223 @@ +// 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 +// +// Based on github.com/golang/go by The Go Authors +// See THIRD-PARTY-NOTICES for original license terms. + +package bsonrw + +import "unicode/utf8" + +// safeSet holds the value true if the ASCII character with the given array +// position can be represented inside a JSON string without any further +// escaping. +// +// All values are true except for the ASCII control characters (0-31), the +// double quote ("), and the backslash character ("\"). +var safeSet = [utf8.RuneSelf]bool{ +	' ':      true, +	'!':      true, +	'"':      false, +	'#':      true, +	'$':      true, +	'%':      true, +	'&':      true, +	'\'':     true, +	'(':      true, +	')':      true, +	'*':      true, +	'+':      true, +	',':      true, +	'-':      true, +	'.':      true, +	'/':      true, +	'0':      true, +	'1':      true, +	'2':      true, +	'3':      true, +	'4':      true, +	'5':      true, +	'6':      true, +	'7':      true, +	'8':      true, +	'9':      true, +	':':      true, +	';':      true, +	'<':      true, +	'=':      true, +	'>':      true, +	'?':      true, +	'@':      true, +	'A':      true, +	'B':      true, +	'C':      true, +	'D':      true, +	'E':      true, +	'F':      true, +	'G':      true, +	'H':      true, +	'I':      true, +	'J':      true, +	'K':      true, +	'L':      true, +	'M':      true, +	'N':      true, +	'O':      true, +	'P':      true, +	'Q':      true, +	'R':      true, +	'S':      true, +	'T':      true, +	'U':      true, +	'V':      true, +	'W':      true, +	'X':      true, +	'Y':      true, +	'Z':      true, +	'[':      true, +	'\\':     false, +	']':      true, +	'^':      true, +	'_':      true, +	'`':      true, +	'a':      true, +	'b':      true, +	'c':      true, +	'd':      true, +	'e':      true, +	'f':      true, +	'g':      true, +	'h':      true, +	'i':      true, +	'j':      true, +	'k':      true, +	'l':      true, +	'm':      true, +	'n':      true, +	'o':      true, +	'p':      true, +	'q':      true, +	'r':      true, +	's':      true, +	't':      true, +	'u':      true, +	'v':      true, +	'w':      true, +	'x':      true, +	'y':      true, +	'z':      true, +	'{':      true, +	'|':      true, +	'}':      true, +	'~':      true, +	'\u007f': true, +} + +// htmlSafeSet holds the value true if the ASCII character with the given +// array position can be safely represented inside a JSON string, embedded +// inside of HTML <script> tags, without any additional escaping. +// +// All values are true except for the ASCII control characters (0-31), the +// double quote ("), the backslash character ("\"), HTML opening and closing +// tags ("<" and ">"), and the ampersand ("&"). +var htmlSafeSet = [utf8.RuneSelf]bool{ +	' ':      true, +	'!':      true, +	'"':      false, +	'#':      true, +	'$':      true, +	'%':      true, +	'&':      false, +	'\'':     true, +	'(':      true, +	')':      true, +	'*':      true, +	'+':      true, +	',':      true, +	'-':      true, +	'.':      true, +	'/':      true, +	'0':      true, +	'1':      true, +	'2':      true, +	'3':      true, +	'4':      true, +	'5':      true, +	'6':      true, +	'7':      true, +	'8':      true, +	'9':      true, +	':':      true, +	';':      true, +	'<':      false, +	'=':      true, +	'>':      false, +	'?':      true, +	'@':      true, +	'A':      true, +	'B':      true, +	'C':      true, +	'D':      true, +	'E':      true, +	'F':      true, +	'G':      true, +	'H':      true, +	'I':      true, +	'J':      true, +	'K':      true, +	'L':      true, +	'M':      true, +	'N':      true, +	'O':      true, +	'P':      true, +	'Q':      true, +	'R':      true, +	'S':      true, +	'T':      true, +	'U':      true, +	'V':      true, +	'W':      true, +	'X':      true, +	'Y':      true, +	'Z':      true, +	'[':      true, +	'\\':     false, +	']':      true, +	'^':      true, +	'_':      true, +	'`':      true, +	'a':      true, +	'b':      true, +	'c':      true, +	'd':      true, +	'e':      true, +	'f':      true, +	'g':      true, +	'h':      true, +	'i':      true, +	'j':      true, +	'k':      true, +	'l':      true, +	'm':      true, +	'n':      true, +	'o':      true, +	'p':      true, +	'q':      true, +	'r':      true, +	's':      true, +	't':      true, +	'u':      true, +	'v':      true, +	'w':      true, +	'x':      true, +	'y':      true, +	'z':      true, +	'{':      true, +	'|':      true, +	'}':      true, +	'~':      true, +	'\u007f': true, +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_wrappers.go b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_wrappers.go new file mode 100644 index 000000000..969570424 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_wrappers.go @@ -0,0 +1,492 @@ +// 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 bsonrw + +import ( +	"encoding/base64" +	"errors" +	"fmt" +	"math" +	"strconv" +	"time" + +	"go.mongodb.org/mongo-driver/bson/bsontype" +	"go.mongodb.org/mongo-driver/bson/primitive" +) + +func wrapperKeyBSONType(key string) bsontype.Type { +	switch key { +	case "$numberInt": +		return bsontype.Int32 +	case "$numberLong": +		return bsontype.Int64 +	case "$oid": +		return bsontype.ObjectID +	case "$symbol": +		return bsontype.Symbol +	case "$numberDouble": +		return bsontype.Double +	case "$numberDecimal": +		return bsontype.Decimal128 +	case "$binary": +		return bsontype.Binary +	case "$code": +		return bsontype.JavaScript +	case "$scope": +		return bsontype.CodeWithScope +	case "$timestamp": +		return bsontype.Timestamp +	case "$regularExpression": +		return bsontype.Regex +	case "$dbPointer": +		return bsontype.DBPointer +	case "$date": +		return bsontype.DateTime +	case "$minKey": +		return bsontype.MinKey +	case "$maxKey": +		return bsontype.MaxKey +	case "$undefined": +		return bsontype.Undefined +	} + +	return bsontype.EmbeddedDocument +} + +func (ejv *extJSONValue) parseBinary() (b []byte, subType byte, err error) { +	if ejv.t != bsontype.EmbeddedDocument { +		return nil, 0, fmt.Errorf("$binary value should be object, but instead is %s", ejv.t) +	} + +	binObj := ejv.v.(*extJSONObject) +	bFound := false +	stFound := false + +	for i, key := range binObj.keys { +		val := binObj.values[i] + +		switch key { +		case "base64": +			if bFound { +				return nil, 0, errors.New("duplicate base64 key in $binary") +			} + +			if val.t != bsontype.String { +				return nil, 0, fmt.Errorf("$binary base64 value should be string, but instead is %s", val.t) +			} + +			base64Bytes, err := base64.StdEncoding.DecodeString(val.v.(string)) +			if err != nil { +				return nil, 0, fmt.Errorf("invalid $binary base64 string: %s", val.v.(string)) +			} + +			b = base64Bytes +			bFound = true +		case "subType": +			if stFound { +				return nil, 0, errors.New("duplicate subType key in $binary") +			} + +			if val.t != bsontype.String { +				return nil, 0, fmt.Errorf("$binary subType value should be string, but instead is %s", val.t) +			} + +			i, err := strconv.ParseInt(val.v.(string), 16, 64) +			if err != nil { +				return nil, 0, fmt.Errorf("invalid $binary subType string: %s", val.v.(string)) +			} + +			subType = byte(i) +			stFound = true +		default: +			return nil, 0, fmt.Errorf("invalid key in $binary object: %s", key) +		} +	} + +	if !bFound { +		return nil, 0, errors.New("missing base64 field in $binary object") +	} + +	if !stFound { +		return nil, 0, errors.New("missing subType field in $binary object") + +	} + +	return b, subType, nil +} + +func (ejv *extJSONValue) parseDBPointer() (ns string, oid primitive.ObjectID, err error) { +	if ejv.t != bsontype.EmbeddedDocument { +		return "", primitive.NilObjectID, fmt.Errorf("$dbPointer value should be object, but instead is %s", ejv.t) +	} + +	dbpObj := ejv.v.(*extJSONObject) +	oidFound := false +	nsFound := false + +	for i, key := range dbpObj.keys { +		val := dbpObj.values[i] + +		switch key { +		case "$ref": +			if nsFound { +				return "", primitive.NilObjectID, errors.New("duplicate $ref key in $dbPointer") +			} + +			if val.t != bsontype.String { +				return "", primitive.NilObjectID, fmt.Errorf("$dbPointer $ref value should be string, but instead is %s", val.t) +			} + +			ns = val.v.(string) +			nsFound = true +		case "$id": +			if oidFound { +				return "", primitive.NilObjectID, errors.New("duplicate $id key in $dbPointer") +			} + +			if val.t != bsontype.String { +				return "", primitive.NilObjectID, fmt.Errorf("$dbPointer $id value should be string, but instead is %s", val.t) +			} + +			oid, err = primitive.ObjectIDFromHex(val.v.(string)) +			if err != nil { +				return "", primitive.NilObjectID, err +			} + +			oidFound = true +		default: +			return "", primitive.NilObjectID, fmt.Errorf("invalid key in $dbPointer object: %s", key) +		} +	} + +	if !nsFound { +		return "", oid, errors.New("missing $ref field in $dbPointer object") +	} + +	if !oidFound { +		return "", oid, errors.New("missing $id field in $dbPointer object") +	} + +	return ns, oid, nil +} + +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 { +	case bsontype.Int32: +		return int64(ejv.v.(int32)), nil +	case bsontype.Int64: +		return ejv.v.(int64), nil +	case bsontype.String: +		return parseDatetimeString(ejv.v.(string)) +	case bsontype.EmbeddedDocument: +		return parseDatetimeObject(ejv.v.(*extJSONObject)) +	default: +		return 0, fmt.Errorf("$date value should be string or object, but instead is %s", ejv.t) +	} +} + +func parseDatetimeString(data string) (int64, error) { +	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) +	} + +	return int64(primitive.NewDateTimeFromTime(t)), nil +} + +func parseDatetimeObject(data *extJSONObject) (d int64, err error) { +	dFound := false + +	for i, key := range data.keys { +		val := data.values[i] + +		switch key { +		case "$numberLong": +			if dFound { +				return 0, errors.New("duplicate $numberLong key in $date") +			} + +			if val.t != bsontype.String { +				return 0, fmt.Errorf("$date $numberLong field should be string, but instead is %s", val.t) +			} + +			d, err = val.parseInt64() +			if err != nil { +				return 0, err +			} +			dFound = true +		default: +			return 0, fmt.Errorf("invalid key in $date object: %s", key) +		} +	} + +	if !dFound { +		return 0, errors.New("missing $numberLong field in $date object") +	} + +	return d, nil +} + +func (ejv *extJSONValue) parseDecimal128() (primitive.Decimal128, error) { +	if ejv.t != bsontype.String { +		return primitive.Decimal128{}, fmt.Errorf("$numberDecimal value should be string, but instead is %s", ejv.t) +	} + +	d, err := primitive.ParseDecimal128(ejv.v.(string)) +	if err != nil { +		return primitive.Decimal128{}, fmt.Errorf("$invalid $numberDecimal string: %s", ejv.v.(string)) +	} + +	return d, nil +} + +func (ejv *extJSONValue) parseDouble() (float64, error) { +	if ejv.t == bsontype.Double { +		return ejv.v.(float64), nil +	} + +	if ejv.t != bsontype.String { +		return 0, fmt.Errorf("$numberDouble value should be string, but instead is %s", ejv.t) +	} + +	switch ejv.v.(string) { +	case "Infinity": +		return math.Inf(1), nil +	case "-Infinity": +		return math.Inf(-1), nil +	case "NaN": +		return math.NaN(), nil +	} + +	f, err := strconv.ParseFloat(ejv.v.(string), 64) +	if err != nil { +		return 0, err +	} + +	return f, nil +} + +func (ejv *extJSONValue) parseInt32() (int32, error) { +	if ejv.t == bsontype.Int32 { +		return ejv.v.(int32), nil +	} + +	if ejv.t != bsontype.String { +		return 0, fmt.Errorf("$numberInt value should be string, but instead is %s", ejv.t) +	} + +	i, err := strconv.ParseInt(ejv.v.(string), 10, 64) +	if err != nil { +		return 0, err +	} + +	if i < math.MinInt32 || i > math.MaxInt32 { +		return 0, fmt.Errorf("$numberInt value should be int32 but instead is int64: %d", i) +	} + +	return int32(i), nil +} + +func (ejv *extJSONValue) parseInt64() (int64, error) { +	if ejv.t == bsontype.Int64 { +		return ejv.v.(int64), nil +	} + +	if ejv.t != bsontype.String { +		return 0, fmt.Errorf("$numberLong value should be string, but instead is %s", ejv.t) +	} + +	i, err := strconv.ParseInt(ejv.v.(string), 10, 64) +	if err != nil { +		return 0, err +	} + +	return i, nil +} + +func (ejv *extJSONValue) parseJavascript() (code string, err error) { +	if ejv.t != bsontype.String { +		return "", fmt.Errorf("$code value should be string, but instead is %s", ejv.t) +	} + +	return ejv.v.(string), nil +} + +func (ejv *extJSONValue) parseMinMaxKey(minmax string) error { +	if ejv.t != bsontype.Int32 { +		return fmt.Errorf("$%sKey value should be int32, but instead is %s", minmax, ejv.t) +	} + +	if ejv.v.(int32) != 1 { +		return fmt.Errorf("$%sKey value must be 1, but instead is %d", minmax, ejv.v.(int32)) +	} + +	return nil +} + +func (ejv *extJSONValue) parseObjectID() (primitive.ObjectID, error) { +	if ejv.t != bsontype.String { +		return primitive.NilObjectID, fmt.Errorf("$oid value should be string, but instead is %s", ejv.t) +	} + +	return primitive.ObjectIDFromHex(ejv.v.(string)) +} + +func (ejv *extJSONValue) parseRegex() (pattern, options string, err error) { +	if ejv.t != bsontype.EmbeddedDocument { +		return "", "", fmt.Errorf("$regularExpression value should be object, but instead is %s", ejv.t) +	} + +	regexObj := ejv.v.(*extJSONObject) +	patFound := false +	optFound := false + +	for i, key := range regexObj.keys { +		val := regexObj.values[i] + +		switch key { +		case "pattern": +			if patFound { +				return "", "", errors.New("duplicate pattern key in $regularExpression") +			} + +			if val.t != bsontype.String { +				return "", "", fmt.Errorf("$regularExpression pattern value should be string, but instead is %s", val.t) +			} + +			pattern = val.v.(string) +			patFound = true +		case "options": +			if optFound { +				return "", "", errors.New("duplicate options key in $regularExpression") +			} + +			if val.t != bsontype.String { +				return "", "", fmt.Errorf("$regularExpression options value should be string, but instead is %s", val.t) +			} + +			options = val.v.(string) +			optFound = true +		default: +			return "", "", fmt.Errorf("invalid key in $regularExpression object: %s", key) +		} +	} + +	if !patFound { +		return "", "", errors.New("missing pattern field in $regularExpression object") +	} + +	if !optFound { +		return "", "", errors.New("missing options field in $regularExpression object") + +	} + +	return pattern, options, nil +} + +func (ejv *extJSONValue) parseSymbol() (string, error) { +	if ejv.t != bsontype.String { +		return "", fmt.Errorf("$symbol value should be string, but instead is %s", ejv.t) +	} + +	return ejv.v.(string), nil +} + +func (ejv *extJSONValue) parseTimestamp() (t, i uint32, err error) { +	if ejv.t != bsontype.EmbeddedDocument { +		return 0, 0, fmt.Errorf("$timestamp value should be object, but instead is %s", ejv.t) +	} + +	handleKey := func(key string, val *extJSONValue, flag bool) (uint32, error) { +		if flag { +			return 0, fmt.Errorf("duplicate %s key in $timestamp", key) +		} + +		switch val.t { +		case bsontype.Int32: +			value := val.v.(int32) + +			if value < 0 { +				return 0, fmt.Errorf("$timestamp %s number should be uint32: %d", key, value) +			} + +			return uint32(value), nil +		case bsontype.Int64: +			value := val.v.(int64) +			if value < 0 || value > int64(math.MaxUint32) { +				return 0, fmt.Errorf("$timestamp %s number should be uint32: %d", key, value) +			} + +			return uint32(value), nil +		default: +			return 0, fmt.Errorf("$timestamp %s value should be uint32, but instead is %s", key, val.t) +		} +	} + +	tsObj := ejv.v.(*extJSONObject) +	tFound := false +	iFound := false + +	for j, key := range tsObj.keys { +		val := tsObj.values[j] + +		switch key { +		case "t": +			if t, err = handleKey(key, val, tFound); err != nil { +				return 0, 0, err +			} + +			tFound = true +		case "i": +			if i, err = handleKey(key, val, iFound); err != nil { +				return 0, 0, err +			} + +			iFound = true +		default: +			return 0, 0, fmt.Errorf("invalid key in $timestamp object: %s", key) +		} +	} + +	if !tFound { +		return 0, 0, errors.New("missing t field in $timestamp object") +	} + +	if !iFound { +		return 0, 0, errors.New("missing i field in $timestamp object") +	} + +	return t, i, nil +} + +func (ejv *extJSONValue) parseUndefined() error { +	if ejv.t != bsontype.Boolean { +		return fmt.Errorf("undefined value should be boolean, but instead is %s", ejv.t) +	} + +	if !ejv.v.(bool) { +		return fmt.Errorf("$undefined balue boolean should be true, but instead is %v", ejv.v.(bool)) +	} + +	return nil +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_writer.go b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_writer.go new file mode 100644 index 000000000..99ed524b7 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_writer.go @@ -0,0 +1,732 @@ +// 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 bsonrw + +import ( +	"bytes" +	"encoding/base64" +	"fmt" +	"io" +	"math" +	"sort" +	"strconv" +	"strings" +	"sync" +	"time" +	"unicode/utf8" + +	"go.mongodb.org/mongo-driver/bson/primitive" +) + +// ExtJSONValueWriterPool is a pool for ExtJSON ValueWriters. +type ExtJSONValueWriterPool struct { +	pool sync.Pool +} + +// NewExtJSONValueWriterPool creates a new pool for ValueWriter instances that write to ExtJSON. +func NewExtJSONValueWriterPool() *ExtJSONValueWriterPool { +	return &ExtJSONValueWriterPool{ +		pool: sync.Pool{ +			New: func() interface{} { +				return new(extJSONValueWriter) +			}, +		}, +	} +} + +// Get retrieves a ExtJSON ValueWriter from the pool and resets it to use w as the destination. +func (bvwp *ExtJSONValueWriterPool) Get(w io.Writer, canonical, escapeHTML bool) ValueWriter { +	vw := bvwp.pool.Get().(*extJSONValueWriter) +	if writer, ok := w.(*SliceWriter); ok { +		vw.reset(*writer, canonical, escapeHTML) +		vw.w = writer +		return vw +	} +	vw.buf = vw.buf[:0] +	vw.w = w +	return vw +} + +// Put inserts a ValueWriter into the pool. If the ValueWriter is not a ExtJSON ValueWriter, nothing +// happens and ok will be false. +func (bvwp *ExtJSONValueWriterPool) Put(vw ValueWriter) (ok bool) { +	bvw, ok := vw.(*extJSONValueWriter) +	if !ok { +		return false +	} + +	if _, ok := bvw.w.(*SliceWriter); ok { +		bvw.buf = nil +	} +	bvw.w = nil + +	bvwp.pool.Put(bvw) +	return true +} + +type ejvwState struct { +	mode mode +} + +type extJSONValueWriter struct { +	w   io.Writer +	buf []byte + +	stack      []ejvwState +	frame      int64 +	canonical  bool +	escapeHTML bool +} + +// NewExtJSONValueWriter creates a ValueWriter that writes Extended JSON to w. +func NewExtJSONValueWriter(w io.Writer, canonical, escapeHTML bool) (ValueWriter, error) { +	if w == nil { +		return nil, errNilWriter +	} + +	return newExtJSONWriter(w, canonical, escapeHTML), nil +} + +func newExtJSONWriter(w io.Writer, canonical, escapeHTML bool) *extJSONValueWriter { +	stack := make([]ejvwState, 1, 5) +	stack[0] = ejvwState{mode: mTopLevel} + +	return &extJSONValueWriter{ +		w:          w, +		buf:        []byte{}, +		stack:      stack, +		canonical:  canonical, +		escapeHTML: escapeHTML, +	} +} + +func newExtJSONWriterFromSlice(buf []byte, canonical, escapeHTML bool) *extJSONValueWriter { +	stack := make([]ejvwState, 1, 5) +	stack[0] = ejvwState{mode: mTopLevel} + +	return &extJSONValueWriter{ +		buf:        buf, +		stack:      stack, +		canonical:  canonical, +		escapeHTML: escapeHTML, +	} +} + +func (ejvw *extJSONValueWriter) reset(buf []byte, canonical, escapeHTML bool) { +	if ejvw.stack == nil { +		ejvw.stack = make([]ejvwState, 1, 5) +	} + +	ejvw.stack = ejvw.stack[:1] +	ejvw.stack[0] = ejvwState{mode: mTopLevel} +	ejvw.canonical = canonical +	ejvw.escapeHTML = escapeHTML +	ejvw.frame = 0 +	ejvw.buf = buf +	ejvw.w = nil +} + +func (ejvw *extJSONValueWriter) advanceFrame() { +	if ejvw.frame+1 >= int64(len(ejvw.stack)) { // We need to grow the stack +		length := len(ejvw.stack) +		if length+1 >= cap(ejvw.stack) { +			// double it +			buf := make([]ejvwState, 2*cap(ejvw.stack)+1) +			copy(buf, ejvw.stack) +			ejvw.stack = buf +		} +		ejvw.stack = ejvw.stack[:length+1] +	} +	ejvw.frame++ +} + +func (ejvw *extJSONValueWriter) push(m mode) { +	ejvw.advanceFrame() + +	ejvw.stack[ejvw.frame].mode = m +} + +func (ejvw *extJSONValueWriter) pop() { +	switch ejvw.stack[ejvw.frame].mode { +	case mElement, mValue: +		ejvw.frame-- +	case mDocument, mArray, mCodeWithScope: +		ejvw.frame -= 2 // we pop twice to jump over the mElement: mDocument -> mElement -> mDocument/mTopLevel/etc... +	} +} + +func (ejvw *extJSONValueWriter) invalidTransitionErr(destination mode, name string, modes []mode) error { +	te := TransitionError{ +		name:        name, +		current:     ejvw.stack[ejvw.frame].mode, +		destination: destination, +		modes:       modes, +		action:      "write", +	} +	if ejvw.frame != 0 { +		te.parent = ejvw.stack[ejvw.frame-1].mode +	} +	return te +} + +func (ejvw *extJSONValueWriter) ensureElementValue(destination mode, callerName string, addmodes ...mode) error { +	switch ejvw.stack[ejvw.frame].mode { +	case mElement, mValue: +	default: +		modes := []mode{mElement, mValue} +		if addmodes != nil { +			modes = append(modes, addmodes...) +		} +		return ejvw.invalidTransitionErr(destination, callerName, modes) +	} + +	return nil +} + +func (ejvw *extJSONValueWriter) writeExtendedSingleValue(key string, value string, quotes bool) { +	var s string +	if quotes { +		s = fmt.Sprintf(`{"$%s":"%s"}`, key, value) +	} else { +		s = fmt.Sprintf(`{"$%s":%s}`, key, value) +	} + +	ejvw.buf = append(ejvw.buf, []byte(s)...) +} + +func (ejvw *extJSONValueWriter) WriteArray() (ArrayWriter, error) { +	if err := ejvw.ensureElementValue(mArray, "WriteArray"); err != nil { +		return nil, err +	} + +	ejvw.buf = append(ejvw.buf, '[') + +	ejvw.push(mArray) +	return ejvw, nil +} + +func (ejvw *extJSONValueWriter) WriteBinary(b []byte) error { +	return ejvw.WriteBinaryWithSubtype(b, 0x00) +} + +func (ejvw *extJSONValueWriter) WriteBinaryWithSubtype(b []byte, btype byte) error { +	if err := ejvw.ensureElementValue(mode(0), "WriteBinaryWithSubtype"); err != nil { +		return err +	} + +	var buf bytes.Buffer +	buf.WriteString(`{"$binary":{"base64":"`) +	buf.WriteString(base64.StdEncoding.EncodeToString(b)) +	buf.WriteString(fmt.Sprintf(`","subType":"%02x"}},`, btype)) + +	ejvw.buf = append(ejvw.buf, buf.Bytes()...) + +	ejvw.pop() +	return nil +} + +func (ejvw *extJSONValueWriter) WriteBoolean(b bool) error { +	if err := ejvw.ensureElementValue(mode(0), "WriteBoolean"); err != nil { +		return err +	} + +	ejvw.buf = append(ejvw.buf, []byte(strconv.FormatBool(b))...) +	ejvw.buf = append(ejvw.buf, ',') + +	ejvw.pop() +	return nil +} + +func (ejvw *extJSONValueWriter) WriteCodeWithScope(code string) (DocumentWriter, error) { +	if err := ejvw.ensureElementValue(mCodeWithScope, "WriteCodeWithScope"); err != nil { +		return nil, err +	} + +	var buf bytes.Buffer +	buf.WriteString(`{"$code":`) +	writeStringWithEscapes(code, &buf, ejvw.escapeHTML) +	buf.WriteString(`,"$scope":{`) + +	ejvw.buf = append(ejvw.buf, buf.Bytes()...) + +	ejvw.push(mCodeWithScope) +	return ejvw, nil +} + +func (ejvw *extJSONValueWriter) WriteDBPointer(ns string, oid primitive.ObjectID) error { +	if err := ejvw.ensureElementValue(mode(0), "WriteDBPointer"); err != nil { +		return err +	} + +	var buf bytes.Buffer +	buf.WriteString(`{"$dbPointer":{"$ref":"`) +	buf.WriteString(ns) +	buf.WriteString(`","$id":{"$oid":"`) +	buf.WriteString(oid.Hex()) +	buf.WriteString(`"}}},`) + +	ejvw.buf = append(ejvw.buf, buf.Bytes()...) + +	ejvw.pop() +	return nil +} + +func (ejvw *extJSONValueWriter) WriteDateTime(dt int64) error { +	if err := ejvw.ensureElementValue(mode(0), "WriteDateTime"); err != nil { +		return err +	} + +	t := time.Unix(dt/1e3, dt%1e3*1e6).UTC() + +	if ejvw.canonical || t.Year() < 1970 || t.Year() > 9999 { +		s := fmt.Sprintf(`{"$numberLong":"%d"}`, dt) +		ejvw.writeExtendedSingleValue("date", s, false) +	} else { +		ejvw.writeExtendedSingleValue("date", t.Format(rfc3339Milli), true) +	} + +	ejvw.buf = append(ejvw.buf, ',') + +	ejvw.pop() +	return nil +} + +func (ejvw *extJSONValueWriter) WriteDecimal128(d primitive.Decimal128) error { +	if err := ejvw.ensureElementValue(mode(0), "WriteDecimal128"); err != nil { +		return err +	} + +	ejvw.writeExtendedSingleValue("numberDecimal", d.String(), true) +	ejvw.buf = append(ejvw.buf, ',') + +	ejvw.pop() +	return nil +} + +func (ejvw *extJSONValueWriter) WriteDocument() (DocumentWriter, error) { +	if ejvw.stack[ejvw.frame].mode == mTopLevel { +		ejvw.buf = append(ejvw.buf, '{') +		return ejvw, nil +	} + +	if err := ejvw.ensureElementValue(mDocument, "WriteDocument", mTopLevel); err != nil { +		return nil, err +	} + +	ejvw.buf = append(ejvw.buf, '{') +	ejvw.push(mDocument) +	return ejvw, nil +} + +func (ejvw *extJSONValueWriter) WriteDouble(f float64) error { +	if err := ejvw.ensureElementValue(mode(0), "WriteDouble"); err != nil { +		return err +	} + +	s := formatDouble(f) + +	if ejvw.canonical { +		ejvw.writeExtendedSingleValue("numberDouble", s, true) +	} else { +		switch s { +		case "Infinity": +			fallthrough +		case "-Infinity": +			fallthrough +		case "NaN": +			s = fmt.Sprintf(`{"$numberDouble":"%s"}`, s) +		} +		ejvw.buf = append(ejvw.buf, []byte(s)...) +	} + +	ejvw.buf = append(ejvw.buf, ',') + +	ejvw.pop() +	return nil +} + +func (ejvw *extJSONValueWriter) WriteInt32(i int32) error { +	if err := ejvw.ensureElementValue(mode(0), "WriteInt32"); err != nil { +		return err +	} + +	s := strconv.FormatInt(int64(i), 10) + +	if ejvw.canonical { +		ejvw.writeExtendedSingleValue("numberInt", s, true) +	} else { +		ejvw.buf = append(ejvw.buf, []byte(s)...) +	} + +	ejvw.buf = append(ejvw.buf, ',') + +	ejvw.pop() +	return nil +} + +func (ejvw *extJSONValueWriter) WriteInt64(i int64) error { +	if err := ejvw.ensureElementValue(mode(0), "WriteInt64"); err != nil { +		return err +	} + +	s := strconv.FormatInt(i, 10) + +	if ejvw.canonical { +		ejvw.writeExtendedSingleValue("numberLong", s, true) +	} else { +		ejvw.buf = append(ejvw.buf, []byte(s)...) +	} + +	ejvw.buf = append(ejvw.buf, ',') + +	ejvw.pop() +	return nil +} + +func (ejvw *extJSONValueWriter) WriteJavascript(code string) error { +	if err := ejvw.ensureElementValue(mode(0), "WriteJavascript"); err != nil { +		return err +	} + +	var buf bytes.Buffer +	writeStringWithEscapes(code, &buf, ejvw.escapeHTML) + +	ejvw.writeExtendedSingleValue("code", buf.String(), false) +	ejvw.buf = append(ejvw.buf, ',') + +	ejvw.pop() +	return nil +} + +func (ejvw *extJSONValueWriter) WriteMaxKey() error { +	if err := ejvw.ensureElementValue(mode(0), "WriteMaxKey"); err != nil { +		return err +	} + +	ejvw.writeExtendedSingleValue("maxKey", "1", false) +	ejvw.buf = append(ejvw.buf, ',') + +	ejvw.pop() +	return nil +} + +func (ejvw *extJSONValueWriter) WriteMinKey() error { +	if err := ejvw.ensureElementValue(mode(0), "WriteMinKey"); err != nil { +		return err +	} + +	ejvw.writeExtendedSingleValue("minKey", "1", false) +	ejvw.buf = append(ejvw.buf, ',') + +	ejvw.pop() +	return nil +} + +func (ejvw *extJSONValueWriter) WriteNull() error { +	if err := ejvw.ensureElementValue(mode(0), "WriteNull"); err != nil { +		return err +	} + +	ejvw.buf = append(ejvw.buf, []byte("null")...) +	ejvw.buf = append(ejvw.buf, ',') + +	ejvw.pop() +	return nil +} + +func (ejvw *extJSONValueWriter) WriteObjectID(oid primitive.ObjectID) error { +	if err := ejvw.ensureElementValue(mode(0), "WriteObjectID"); err != nil { +		return err +	} + +	ejvw.writeExtendedSingleValue("oid", oid.Hex(), true) +	ejvw.buf = append(ejvw.buf, ',') + +	ejvw.pop() +	return nil +} + +func (ejvw *extJSONValueWriter) WriteRegex(pattern string, options string) error { +	if err := ejvw.ensureElementValue(mode(0), "WriteRegex"); err != nil { +		return err +	} + +	var buf bytes.Buffer +	buf.WriteString(`{"$regularExpression":{"pattern":`) +	writeStringWithEscapes(pattern, &buf, ejvw.escapeHTML) +	buf.WriteString(`,"options":"`) +	buf.WriteString(sortStringAlphebeticAscending(options)) +	buf.WriteString(`"}},`) + +	ejvw.buf = append(ejvw.buf, buf.Bytes()...) + +	ejvw.pop() +	return nil +} + +func (ejvw *extJSONValueWriter) WriteString(s string) error { +	if err := ejvw.ensureElementValue(mode(0), "WriteString"); err != nil { +		return err +	} + +	var buf bytes.Buffer +	writeStringWithEscapes(s, &buf, ejvw.escapeHTML) + +	ejvw.buf = append(ejvw.buf, buf.Bytes()...) +	ejvw.buf = append(ejvw.buf, ',') + +	ejvw.pop() +	return nil +} + +func (ejvw *extJSONValueWriter) WriteSymbol(symbol string) error { +	if err := ejvw.ensureElementValue(mode(0), "WriteSymbol"); err != nil { +		return err +	} + +	var buf bytes.Buffer +	writeStringWithEscapes(symbol, &buf, ejvw.escapeHTML) + +	ejvw.writeExtendedSingleValue("symbol", buf.String(), false) +	ejvw.buf = append(ejvw.buf, ',') + +	ejvw.pop() +	return nil +} + +func (ejvw *extJSONValueWriter) WriteTimestamp(t uint32, i uint32) error { +	if err := ejvw.ensureElementValue(mode(0), "WriteTimestamp"); err != nil { +		return err +	} + +	var buf bytes.Buffer +	buf.WriteString(`{"$timestamp":{"t":`) +	buf.WriteString(strconv.FormatUint(uint64(t), 10)) +	buf.WriteString(`,"i":`) +	buf.WriteString(strconv.FormatUint(uint64(i), 10)) +	buf.WriteString(`}},`) + +	ejvw.buf = append(ejvw.buf, buf.Bytes()...) + +	ejvw.pop() +	return nil +} + +func (ejvw *extJSONValueWriter) WriteUndefined() error { +	if err := ejvw.ensureElementValue(mode(0), "WriteUndefined"); err != nil { +		return err +	} + +	ejvw.writeExtendedSingleValue("undefined", "true", false) +	ejvw.buf = append(ejvw.buf, ',') + +	ejvw.pop() +	return nil +} + +func (ejvw *extJSONValueWriter) WriteDocumentElement(key string) (ValueWriter, error) { +	switch ejvw.stack[ejvw.frame].mode { +	case mDocument, mTopLevel, mCodeWithScope: +		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}) +	} + +	return ejvw, nil +} + +func (ejvw *extJSONValueWriter) WriteDocumentEnd() error { +	switch ejvw.stack[ejvw.frame].mode { +	case mDocument, mTopLevel, mCodeWithScope: +	default: +		return fmt.Errorf("incorrect mode to end document: %s", ejvw.stack[ejvw.frame].mode) +	} + +	// close the document +	if ejvw.buf[len(ejvw.buf)-1] == ',' { +		ejvw.buf[len(ejvw.buf)-1] = '}' +	} else { +		ejvw.buf = append(ejvw.buf, '}') +	} + +	switch ejvw.stack[ejvw.frame].mode { +	case mCodeWithScope: +		ejvw.buf = append(ejvw.buf, '}') +		fallthrough +	case mDocument: +		ejvw.buf = append(ejvw.buf, ',') +	case mTopLevel: +		if ejvw.w != nil { +			if _, err := ejvw.w.Write(ejvw.buf); err != nil { +				return err +			} +			ejvw.buf = ejvw.buf[:0] +		} +	} + +	ejvw.pop() +	return nil +} + +func (ejvw *extJSONValueWriter) WriteArrayElement() (ValueWriter, error) { +	switch ejvw.stack[ejvw.frame].mode { +	case mArray: +		ejvw.push(mValue) +	default: +		return nil, ejvw.invalidTransitionErr(mValue, "WriteArrayElement", []mode{mArray}) +	} + +	return ejvw, nil +} + +func (ejvw *extJSONValueWriter) WriteArrayEnd() error { +	switch ejvw.stack[ejvw.frame].mode { +	case mArray: +		// close the array +		if ejvw.buf[len(ejvw.buf)-1] == ',' { +			ejvw.buf[len(ejvw.buf)-1] = ']' +		} else { +			ejvw.buf = append(ejvw.buf, ']') +		} + +		ejvw.buf = append(ejvw.buf, ',') + +		ejvw.pop() +	default: +		return fmt.Errorf("incorrect mode to end array: %s", ejvw.stack[ejvw.frame].mode) +	} + +	return nil +} + +func formatDouble(f float64) string { +	var s string +	if math.IsInf(f, 1) { +		s = "Infinity" +	} else if math.IsInf(f, -1) { +		s = "-Infinity" +	} else if math.IsNaN(f) { +		s = "NaN" +	} else { +		// Print exactly one decimalType place for integers; otherwise, print as many are necessary to +		// perfectly represent it. +		s = strconv.FormatFloat(f, 'G', -1, 64) +		if !strings.ContainsRune(s, 'E') && !strings.ContainsRune(s, '.') { +			s += ".0" +		} +	} + +	return s +} + +var hexChars = "0123456789abcdef" + +func writeStringWithEscapes(s string, buf *bytes.Buffer, escapeHTML bool) { +	buf.WriteByte('"') +	start := 0 +	for i := 0; i < len(s); { +		if b := s[i]; b < utf8.RuneSelf { +			if htmlSafeSet[b] || (!escapeHTML && safeSet[b]) { +				i++ +				continue +			} +			if start < i { +				buf.WriteString(s[start:i]) +			} +			switch b { +			case '\\', '"': +				buf.WriteByte('\\') +				buf.WriteByte(b) +			case '\n': +				buf.WriteByte('\\') +				buf.WriteByte('n') +			case '\r': +				buf.WriteByte('\\') +				buf.WriteByte('r') +			case '\t': +				buf.WriteByte('\\') +				buf.WriteByte('t') +			case '\b': +				buf.WriteByte('\\') +				buf.WriteByte('b') +			case '\f': +				buf.WriteByte('\\') +				buf.WriteByte('f') +			default: +				// This encodes bytes < 0x20 except for \t, \n and \r. +				// If escapeHTML is set, it also escapes <, >, and & +				// because they can lead to security holes when +				// user-controlled strings are rendered into JSON +				// and served to some browsers. +				buf.WriteString(`\u00`) +				buf.WriteByte(hexChars[b>>4]) +				buf.WriteByte(hexChars[b&0xF]) +			} +			i++ +			start = i +			continue +		} +		c, size := utf8.DecodeRuneInString(s[i:]) +		if c == utf8.RuneError && size == 1 { +			if start < i { +				buf.WriteString(s[start:i]) +			} +			buf.WriteString(`\ufffd`) +			i += size +			start = i +			continue +		} +		// U+2028 is LINE SEPARATOR. +		// U+2029 is PARAGRAPH SEPARATOR. +		// They are both technically valid characters in JSON strings, +		// but don't work in JSONP, which has to be evaluated as JavaScript, +		// and can lead to security holes there. It is valid JSON to +		// escape them, so we do so unconditionally. +		// See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion. +		if c == '\u2028' || c == '\u2029' { +			if start < i { +				buf.WriteString(s[start:i]) +			} +			buf.WriteString(`\u202`) +			buf.WriteByte(hexChars[c&0xF]) +			i += size +			start = i +			continue +		} +		i += size +	} +	if start < len(s) { +		buf.WriteString(s[start:]) +	} +	buf.WriteByte('"') +} + +type sortableString []rune + +func (ss sortableString) Len() int { +	return len(ss) +} + +func (ss sortableString) Less(i, j int) bool { +	return ss[i] < ss[j] +} + +func (ss sortableString) Swap(i, j int) { +	oldI := ss[i] +	ss[i] = ss[j] +	ss[j] = oldI +} + +func sortStringAlphebeticAscending(s string) string { +	ss := sortableString([]rune(s)) +	sort.Sort(ss) +	return string([]rune(ss)) +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/json_scanner.go b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/json_scanner.go new file mode 100644 index 000000000..cd4843a3a --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/json_scanner.go @@ -0,0 +1,528 @@ +// 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 bsonrw + +import ( +	"bytes" +	"errors" +	"fmt" +	"io" +	"math" +	"strconv" +	"unicode" +	"unicode/utf16" +) + +type jsonTokenType byte + +const ( +	jttBeginObject jsonTokenType = iota +	jttEndObject +	jttBeginArray +	jttEndArray +	jttColon +	jttComma +	jttInt32 +	jttInt64 +	jttDouble +	jttString +	jttBool +	jttNull +	jttEOF +) + +type jsonToken struct { +	t jsonTokenType +	v interface{} +	p int +} + +type jsonScanner struct { +	r           io.Reader +	buf         []byte +	pos         int +	lastReadErr error +} + +// nextToken returns the next JSON token if one exists. A token is a character +// of the JSON grammar, a number, a string, or a literal. +func (js *jsonScanner) nextToken() (*jsonToken, error) { +	c, err := js.readNextByte() + +	// keep reading until a non-space is encountered (break on read error or EOF) +	for isWhiteSpace(c) && err == nil { +		c, err = js.readNextByte() +	} + +	if err == io.EOF { +		return &jsonToken{t: jttEOF}, nil +	} else if err != nil { +		return nil, err +	} + +	// switch on the character +	switch c { +	case '{': +		return &jsonToken{t: jttBeginObject, v: byte('{'), p: js.pos - 1}, nil +	case '}': +		return &jsonToken{t: jttEndObject, v: byte('}'), p: js.pos - 1}, nil +	case '[': +		return &jsonToken{t: jttBeginArray, v: byte('['), p: js.pos - 1}, nil +	case ']': +		return &jsonToken{t: jttEndArray, v: byte(']'), p: js.pos - 1}, nil +	case ':': +		return &jsonToken{t: jttColon, v: byte(':'), p: js.pos - 1}, nil +	case ',': +		return &jsonToken{t: jttComma, v: byte(','), p: js.pos - 1}, nil +	case '"': // RFC-8259 only allows for double quotes (") not single (') +		return js.scanString() +	default: +		// check if it's a number +		if c == '-' || isDigit(c) { +			return js.scanNumber(c) +		} else if c == 't' || c == 'f' || c == 'n' { +			// maybe a literal +			return js.scanLiteral(c) +		} else { +			return nil, fmt.Errorf("invalid JSON input. Position: %d. Character: %c", js.pos-1, c) +		} +	} +} + +// readNextByte attempts to read the next byte from the buffer. If the buffer +// has been exhausted, this function calls readIntoBuf, thus refilling the +// buffer and resetting the read position to 0 +func (js *jsonScanner) readNextByte() (byte, error) { +	if js.pos >= len(js.buf) { +		err := js.readIntoBuf() + +		if err != nil { +			return 0, err +		} +	} + +	b := js.buf[js.pos] +	js.pos++ + +	return b, nil +} + +// readNNextBytes reads n bytes into dst, starting at offset +func (js *jsonScanner) readNNextBytes(dst []byte, n, offset int) error { +	var err error + +	for i := 0; i < n; i++ { +		dst[i+offset], err = js.readNextByte() +		if err != nil { +			return err +		} +	} + +	return nil +} + +// readIntoBuf reads up to 512 bytes from the scanner's io.Reader into the buffer +func (js *jsonScanner) readIntoBuf() error { +	if js.lastReadErr != nil { +		js.buf = js.buf[:0] +		js.pos = 0 +		return js.lastReadErr +	} + +	if cap(js.buf) == 0 { +		js.buf = make([]byte, 0, 512) +	} + +	n, err := js.r.Read(js.buf[:cap(js.buf)]) +	if err != nil { +		js.lastReadErr = err +		if n > 0 { +			err = nil +		} +	} +	js.buf = js.buf[:n] +	js.pos = 0 + +	return err +} + +func isWhiteSpace(c byte) bool { +	return c == ' ' || c == '\t' || c == '\r' || c == '\n' +} + +func isDigit(c byte) bool { +	return unicode.IsDigit(rune(c)) +} + +func isValueTerminator(c byte) bool { +	return c == ',' || c == '}' || c == ']' || isWhiteSpace(c) +} + +// getu4 decodes the 4-byte hex sequence from the beginning of s, returning the hex value as a rune, +// or it returns -1. Note that the "\u" from the unicode escape sequence should not be present. +// It is copied and lightly modified from the Go JSON decode function at +// https://github.com/golang/go/blob/1b0a0316802b8048d69da49dc23c5a5ab08e8ae8/src/encoding/json/decode.go#L1169-L1188 +func getu4(s []byte) rune { +	if len(s) < 4 { +		return -1 +	} +	var r rune +	for _, c := range s[:4] { +		switch { +		case '0' <= c && c <= '9': +			c = c - '0' +		case 'a' <= c && c <= 'f': +			c = c - 'a' + 10 +		case 'A' <= c && c <= 'F': +			c = c - 'A' + 10 +		default: +			return -1 +		} +		r = r*16 + rune(c) +	} +	return r +} + +// scanString reads from an opening '"' to a closing '"' and handles escaped characters +func (js *jsonScanner) scanString() (*jsonToken, error) { +	var b bytes.Buffer +	var c byte +	var err error + +	p := js.pos - 1 + +	for { +		c, err = js.readNextByte() +		if err != nil { +			if err == io.EOF { +				return nil, errors.New("end of input in JSON string") +			} +			return nil, err +		} + +	evalNextChar: +		switch c { +		case '\\': +			c, err = js.readNextByte() +			if err != nil { +				if err == io.EOF { +					return nil, errors.New("end of input in JSON string") +				} +				return nil, err +			} + +		evalNextEscapeChar: +			switch c { +			case '"', '\\', '/': +				b.WriteByte(c) +			case 'b': +				b.WriteByte('\b') +			case 'f': +				b.WriteByte('\f') +			case 'n': +				b.WriteByte('\n') +			case 'r': +				b.WriteByte('\r') +			case 't': +				b.WriteByte('\t') +			case 'u': +				us := make([]byte, 4) +				err = js.readNNextBytes(us, 4, 0) +				if err != nil { +					return nil, fmt.Errorf("invalid unicode sequence in JSON string: %s", us) +				} + +				rn := getu4(us) + +				// If the rune we just decoded is the high or low value of a possible surrogate pair, +				// try to decode the next sequence as the low value of a surrogate pair. We're +				// expecting the next sequence to be another Unicode escape sequence (e.g. "\uDD1E"), +				// but need to handle cases where the input is not a valid surrogate pair. +				// For more context on unicode surrogate pairs, see: +				// https://www.christianfscott.com/rust-chars-vs-go-runes/ +				// https://www.unicode.org/glossary/#high_surrogate_code_point +				if utf16.IsSurrogate(rn) { +					c, err = js.readNextByte() +					if err != nil { +						if err == io.EOF { +							return nil, errors.New("end of input in JSON string") +						} +						return nil, err +					} + +					// If the next value isn't the beginning of a backslash escape sequence, write +					// the Unicode replacement character for the surrogate value and goto the +					// beginning of the next char eval block. +					if c != '\\' { +						b.WriteRune(unicode.ReplacementChar) +						goto evalNextChar +					} + +					c, err = js.readNextByte() +					if err != nil { +						if err == io.EOF { +							return nil, errors.New("end of input in JSON string") +						} +						return nil, err +					} + +					// If the next value isn't the beginning of a unicode escape sequence, write the +					// Unicode replacement character for the surrogate value and goto the beginning +					// of the next escape char eval block. +					if c != 'u' { +						b.WriteRune(unicode.ReplacementChar) +						goto evalNextEscapeChar +					} + +					err = js.readNNextBytes(us, 4, 0) +					if err != nil { +						return nil, fmt.Errorf("invalid unicode sequence in JSON string: %s", us) +					} + +					rn2 := getu4(us) + +					// Try to decode the pair of runes as a utf16 surrogate pair. If that fails, write +					// the Unicode replacement character for the surrogate value and the 2nd decoded rune. +					if rnPair := utf16.DecodeRune(rn, rn2); rnPair != unicode.ReplacementChar { +						b.WriteRune(rnPair) +					} else { +						b.WriteRune(unicode.ReplacementChar) +						b.WriteRune(rn2) +					} + +					break +				} + +				b.WriteRune(rn) +			default: +				return nil, fmt.Errorf("invalid escape sequence in JSON string '\\%c'", c) +			} +		case '"': +			return &jsonToken{t: jttString, v: b.String(), p: p}, nil +		default: +			b.WriteByte(c) +		} +	} +} + +// scanLiteral reads an unquoted sequence of characters and determines if it is one of +// three valid JSON literals (true, false, null); if so, it returns the appropriate +// jsonToken; otherwise, it returns an error +func (js *jsonScanner) scanLiteral(first byte) (*jsonToken, error) { +	p := js.pos - 1 + +	lit := make([]byte, 4) +	lit[0] = first + +	err := js.readNNextBytes(lit, 3, 1) +	if err != nil { +		return nil, err +	} + +	c5, err := js.readNextByte() + +	if bytes.Equal([]byte("true"), lit) && (isValueTerminator(c5) || err == io.EOF) { +		js.pos = int(math.Max(0, float64(js.pos-1))) +		return &jsonToken{t: jttBool, v: true, p: p}, nil +	} else if bytes.Equal([]byte("null"), lit) && (isValueTerminator(c5) || err == io.EOF) { +		js.pos = int(math.Max(0, float64(js.pos-1))) +		return &jsonToken{t: jttNull, v: nil, p: p}, nil +	} else if bytes.Equal([]byte("fals"), lit) { +		if c5 == 'e' { +			c5, err = js.readNextByte() + +			if isValueTerminator(c5) || err == io.EOF { +				js.pos = int(math.Max(0, float64(js.pos-1))) +				return &jsonToken{t: jttBool, v: false, p: p}, nil +			} +		} +	} + +	return nil, fmt.Errorf("invalid JSON literal. Position: %d, literal: %s", p, lit) +} + +type numberScanState byte + +const ( +	nssSawLeadingMinus numberScanState = iota +	nssSawLeadingZero +	nssSawIntegerDigits +	nssSawDecimalPoint +	nssSawFractionDigits +	nssSawExponentLetter +	nssSawExponentSign +	nssSawExponentDigits +	nssDone +	nssInvalid +) + +// scanNumber reads a JSON number (according to RFC-8259) +func (js *jsonScanner) scanNumber(first byte) (*jsonToken, error) { +	var b bytes.Buffer +	var s numberScanState +	var c byte +	var err error + +	t := jttInt64 // assume it's an int64 until the type can be determined +	start := js.pos - 1 + +	b.WriteByte(first) + +	switch first { +	case '-': +		s = nssSawLeadingMinus +	case '0': +		s = nssSawLeadingZero +	default: +		s = nssSawIntegerDigits +	} + +	for { +		c, err = js.readNextByte() + +		if err != nil && err != io.EOF { +			return nil, err +		} + +		switch s { +		case nssSawLeadingMinus: +			switch c { +			case '0': +				s = nssSawLeadingZero +				b.WriteByte(c) +			default: +				if isDigit(c) { +					s = nssSawIntegerDigits +					b.WriteByte(c) +				} else { +					s = nssInvalid +				} +			} +		case nssSawLeadingZero: +			switch c { +			case '.': +				s = nssSawDecimalPoint +				b.WriteByte(c) +			case 'e', 'E': +				s = nssSawExponentLetter +				b.WriteByte(c) +			case '}', ']', ',': +				s = nssDone +			default: +				if isWhiteSpace(c) || err == io.EOF { +					s = nssDone +				} else { +					s = nssInvalid +				} +			} +		case nssSawIntegerDigits: +			switch c { +			case '.': +				s = nssSawDecimalPoint +				b.WriteByte(c) +			case 'e', 'E': +				s = nssSawExponentLetter +				b.WriteByte(c) +			case '}', ']', ',': +				s = nssDone +			default: +				if isWhiteSpace(c) || err == io.EOF { +					s = nssDone +				} else if isDigit(c) { +					s = nssSawIntegerDigits +					b.WriteByte(c) +				} else { +					s = nssInvalid +				} +			} +		case nssSawDecimalPoint: +			t = jttDouble +			if isDigit(c) { +				s = nssSawFractionDigits +				b.WriteByte(c) +			} else { +				s = nssInvalid +			} +		case nssSawFractionDigits: +			switch c { +			case 'e', 'E': +				s = nssSawExponentLetter +				b.WriteByte(c) +			case '}', ']', ',': +				s = nssDone +			default: +				if isWhiteSpace(c) || err == io.EOF { +					s = nssDone +				} else if isDigit(c) { +					s = nssSawFractionDigits +					b.WriteByte(c) +				} else { +					s = nssInvalid +				} +			} +		case nssSawExponentLetter: +			t = jttDouble +			switch c { +			case '+', '-': +				s = nssSawExponentSign +				b.WriteByte(c) +			default: +				if isDigit(c) { +					s = nssSawExponentDigits +					b.WriteByte(c) +				} else { +					s = nssInvalid +				} +			} +		case nssSawExponentSign: +			if isDigit(c) { +				s = nssSawExponentDigits +				b.WriteByte(c) +			} else { +				s = nssInvalid +			} +		case nssSawExponentDigits: +			switch c { +			case '}', ']', ',': +				s = nssDone +			default: +				if isWhiteSpace(c) || err == io.EOF { +					s = nssDone +				} else if isDigit(c) { +					s = nssSawExponentDigits +					b.WriteByte(c) +				} else { +					s = nssInvalid +				} +			} +		} + +		switch s { +		case nssInvalid: +			return nil, fmt.Errorf("invalid JSON number. Position: %d", start) +		case nssDone: +			js.pos = int(math.Max(0, float64(js.pos-1))) +			if t != jttDouble { +				v, err := strconv.ParseInt(b.String(), 10, 64) +				if err == nil { +					if v < math.MinInt32 || v > math.MaxInt32 { +						return &jsonToken{t: jttInt64, v: v, p: start}, nil +					} + +					return &jsonToken{t: jttInt32, v: int32(v), p: start}, nil +				} +			} + +			v, err := strconv.ParseFloat(b.String(), 64) +			if err != nil { +				return nil, err +			} + +			return &jsonToken{t: jttDouble, v: v, p: start}, nil +		} +	} +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/mode.go b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/mode.go new file mode 100644 index 000000000..617b5e221 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/mode.go @@ -0,0 +1,108 @@ +// 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 bsonrw + +import ( +	"fmt" +) + +type mode int + +const ( +	_ mode = iota +	mTopLevel +	mDocument +	mArray +	mValue +	mElement +	mCodeWithScope +	mSpacer +) + +func (m mode) String() string { +	var str string + +	switch m { +	case mTopLevel: +		str = "TopLevel" +	case mDocument: +		str = "DocumentMode" +	case mArray: +		str = "ArrayMode" +	case mValue: +		str = "ValueMode" +	case mElement: +		str = "ElementMode" +	case mCodeWithScope: +		str = "CodeWithScopeMode" +	case mSpacer: +		str = "CodeWithScopeSpacerFrame" +	default: +		str = "UnknownMode" +	} + +	return str +} + +func (m mode) TypeString() string { +	var str string + +	switch m { +	case mTopLevel: +		str = "TopLevel" +	case mDocument: +		str = "Document" +	case mArray: +		str = "Array" +	case mValue: +		str = "Value" +	case mElement: +		str = "Element" +	case mCodeWithScope: +		str = "CodeWithScope" +	case mSpacer: +		str = "CodeWithScopeSpacer" +	default: +		str = "Unknown" +	} + +	return str +} + +// TransitionError is an error returned when an invalid progressing a +// ValueReader or ValueWriter state machine occurs. +// If read is false, the error is for writing +type TransitionError struct { +	name        string +	parent      mode +	current     mode +	destination mode +	modes       []mode +	action      string +} + +func (te TransitionError) Error() string { +	errString := fmt.Sprintf("%s can only %s", te.name, te.action) +	if te.destination != mode(0) { +		errString = fmt.Sprintf("%s a %s", errString, te.destination.TypeString()) +	} +	errString = fmt.Sprintf("%s while positioned on a", errString) +	for ind, m := range te.modes { +		if ind != 0 && len(te.modes) > 2 { +			errString = fmt.Sprintf("%s,", errString) +		} +		if ind == len(te.modes)-1 && len(te.modes) > 1 { +			errString = fmt.Sprintf("%s or", errString) +		} +		errString = fmt.Sprintf("%s %s", errString, m.TypeString()) +	} +	errString = fmt.Sprintf("%s but is positioned on a %s", errString, te.current.TypeString()) +	if te.parent != mode(0) { +		errString = fmt.Sprintf("%s with parent %s", errString, te.parent.TypeString()) +	} +	return errString +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/reader.go b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/reader.go new file mode 100644 index 000000000..0b8fa28d5 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/reader.go @@ -0,0 +1,63 @@ +// 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 bsonrw + +import ( +	"go.mongodb.org/mongo-driver/bson/bsontype" +	"go.mongodb.org/mongo-driver/bson/primitive" +) + +// ArrayReader is implemented by types that allow reading values from a BSON +// array. +type ArrayReader interface { +	ReadValue() (ValueReader, error) +} + +// DocumentReader is implemented by types that allow reading elements from a +// BSON document. +type DocumentReader interface { +	ReadElement() (string, ValueReader, error) +} + +// ValueReader is a generic interface used to read values from BSON. This type +// is implemented by several types with different underlying representations of +// BSON, such as a bson.Document, raw BSON bytes, or extended JSON. +type ValueReader interface { +	Type() bsontype.Type +	Skip() error + +	ReadArray() (ArrayReader, error) +	ReadBinary() (b []byte, btype byte, err error) +	ReadBoolean() (bool, error) +	ReadDocument() (DocumentReader, error) +	ReadCodeWithScope() (code string, dr DocumentReader, err error) +	ReadDBPointer() (ns string, oid primitive.ObjectID, err error) +	ReadDateTime() (int64, error) +	ReadDecimal128() (primitive.Decimal128, error) +	ReadDouble() (float64, error) +	ReadInt32() (int32, error) +	ReadInt64() (int64, error) +	ReadJavascript() (code string, err error) +	ReadMaxKey() error +	ReadMinKey() error +	ReadNull() error +	ReadObjectID() (primitive.ObjectID, error) +	ReadRegex() (pattern, options string, err error) +	ReadString() (string, error) +	ReadSymbol() (symbol string, err error) +	ReadTimestamp() (t, i uint32, err error) +	ReadUndefined() error +} + +// BytesReader is a generic interface used to read BSON bytes from a +// ValueReader. This imterface is meant to be a superset of ValueReader, so that +// types that implement ValueReader may also implement this interface. +// +// The bytes of the value will be appended to dst. +type BytesReader interface { +	ReadValueBytes(dst []byte) (bsontype.Type, []byte, error) +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/value_reader.go b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/value_reader.go new file mode 100644 index 000000000..ef5d837c2 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/value_reader.go @@ -0,0 +1,874 @@ +// 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 bsonrw + +import ( +	"bytes" +	"encoding/binary" +	"errors" +	"fmt" +	"io" +	"math" +	"sync" + +	"go.mongodb.org/mongo-driver/bson/bsontype" +	"go.mongodb.org/mongo-driver/bson/primitive" +) + +var _ ValueReader = (*valueReader)(nil) + +var vrPool = sync.Pool{ +	New: func() interface{} { +		return new(valueReader) +	}, +} + +// BSONValueReaderPool is a pool for ValueReaders that read BSON. +type BSONValueReaderPool struct { +	pool sync.Pool +} + +// NewBSONValueReaderPool instantiates a new BSONValueReaderPool. +func NewBSONValueReaderPool() *BSONValueReaderPool { +	return &BSONValueReaderPool{ +		pool: sync.Pool{ +			New: func() interface{} { +				return new(valueReader) +			}, +		}, +	} +} + +// Get retrieves a ValueReader from the pool and uses src as the underlying BSON. +func (bvrp *BSONValueReaderPool) Get(src []byte) ValueReader { +	vr := bvrp.pool.Get().(*valueReader) +	vr.reset(src) +	return vr +} + +// Put inserts a ValueReader into the pool. If the ValueReader is not a BSON ValueReader nothing +// is inserted into the pool and ok will be false. +func (bvrp *BSONValueReaderPool) Put(vr ValueReader) (ok bool) { +	bvr, ok := vr.(*valueReader) +	if !ok { +		return false +	} + +	bvr.reset(nil) +	bvrp.pool.Put(bvr) +	return true +} + +// ErrEOA is the error returned when the end of a BSON array has been reached. +var ErrEOA = errors.New("end of array") + +// ErrEOD is the error returned when the end of a BSON document has been reached. +var ErrEOD = errors.New("end of document") + +type vrState struct { +	mode  mode +	vType bsontype.Type +	end   int64 +} + +// valueReader is for reading BSON values. +type valueReader struct { +	offset int64 +	d      []byte + +	stack []vrState +	frame int64 +} + +// NewBSONDocumentReader returns a ValueReader using b for the underlying BSON +// representation. Parameter b must be a BSON Document. +func NewBSONDocumentReader(b []byte) ValueReader { +	// TODO(skriptble): There's a lack of symmetry between the reader and writer, since the reader takes a []byte while the +	// TODO writer takes an io.Writer. We should have two versions of each, one that takes a []byte and one that takes an +	// TODO io.Reader or io.Writer. The []byte version will need to return a thing that can return the finished []byte since +	// TODO it might be reallocated when appended to. +	return newValueReader(b) +} + +// NewBSONValueReader returns a ValueReader that starts in the Value mode instead of in top +// level document mode. This enables the creation of a ValueReader for a single BSON value. +func NewBSONValueReader(t bsontype.Type, val []byte) ValueReader { +	stack := make([]vrState, 1, 5) +	stack[0] = vrState{ +		mode:  mValue, +		vType: t, +	} +	return &valueReader{ +		d:     val, +		stack: stack, +	} +} + +func newValueReader(b []byte) *valueReader { +	stack := make([]vrState, 1, 5) +	stack[0] = vrState{ +		mode: mTopLevel, +	} +	return &valueReader{ +		d:     b, +		stack: stack, +	} +} + +func (vr *valueReader) reset(b []byte) { +	if vr.stack == nil { +		vr.stack = make([]vrState, 1, 5) +	} +	vr.stack = vr.stack[:1] +	vr.stack[0] = vrState{mode: mTopLevel} +	vr.d = b +	vr.offset = 0 +	vr.frame = 0 +} + +func (vr *valueReader) advanceFrame() { +	if vr.frame+1 >= int64(len(vr.stack)) { // We need to grow the stack +		length := len(vr.stack) +		if length+1 >= cap(vr.stack) { +			// double it +			buf := make([]vrState, 2*cap(vr.stack)+1) +			copy(buf, vr.stack) +			vr.stack = buf +		} +		vr.stack = vr.stack[:length+1] +	} +	vr.frame++ + +	// Clean the stack +	vr.stack[vr.frame].mode = 0 +	vr.stack[vr.frame].vType = 0 +	vr.stack[vr.frame].end = 0 +} + +func (vr *valueReader) pushDocument() error { +	vr.advanceFrame() + +	vr.stack[vr.frame].mode = mDocument + +	size, err := vr.readLength() +	if err != nil { +		return err +	} +	vr.stack[vr.frame].end = int64(size) + vr.offset - 4 + +	return nil +} + +func (vr *valueReader) pushArray() error { +	vr.advanceFrame() + +	vr.stack[vr.frame].mode = mArray + +	size, err := vr.readLength() +	if err != nil { +		return err +	} +	vr.stack[vr.frame].end = int64(size) + vr.offset - 4 + +	return nil +} + +func (vr *valueReader) pushElement(t bsontype.Type) { +	vr.advanceFrame() + +	vr.stack[vr.frame].mode = mElement +	vr.stack[vr.frame].vType = t +} + +func (vr *valueReader) pushValue(t bsontype.Type) { +	vr.advanceFrame() + +	vr.stack[vr.frame].mode = mValue +	vr.stack[vr.frame].vType = t +} + +func (vr *valueReader) pushCodeWithScope() (int64, error) { +	vr.advanceFrame() + +	vr.stack[vr.frame].mode = mCodeWithScope + +	size, err := vr.readLength() +	if err != nil { +		return 0, err +	} +	vr.stack[vr.frame].end = int64(size) + vr.offset - 4 + +	return int64(size), nil +} + +func (vr *valueReader) pop() { +	switch vr.stack[vr.frame].mode { +	case mElement, mValue: +		vr.frame-- +	case mDocument, mArray, mCodeWithScope: +		vr.frame -= 2 // we pop twice to jump over the vrElement: vrDocument -> vrElement -> vrDocument/TopLevel/etc... +	} +} + +func (vr *valueReader) invalidTransitionErr(destination mode, name string, modes []mode) error { +	te := TransitionError{ +		name:        name, +		current:     vr.stack[vr.frame].mode, +		destination: destination, +		modes:       modes, +		action:      "read", +	} +	if vr.frame != 0 { +		te.parent = vr.stack[vr.frame-1].mode +	} +	return te +} + +func (vr *valueReader) typeError(t bsontype.Type) error { +	return fmt.Errorf("positioned on %s, but attempted to read %s", vr.stack[vr.frame].vType, t) +} + +func (vr *valueReader) invalidDocumentLengthError() error { +	return fmt.Errorf("document is invalid, end byte is at %d, but null byte found at %d", vr.stack[vr.frame].end, vr.offset) +} + +func (vr *valueReader) ensureElementValue(t bsontype.Type, destination mode, callerName string) error { +	switch vr.stack[vr.frame].mode { +	case mElement, mValue: +		if vr.stack[vr.frame].vType != t { +			return vr.typeError(t) +		} +	default: +		return vr.invalidTransitionErr(destination, callerName, []mode{mElement, mValue}) +	} + +	return nil +} + +func (vr *valueReader) Type() bsontype.Type { +	return vr.stack[vr.frame].vType +} + +func (vr *valueReader) nextElementLength() (int32, error) { +	var length int32 +	var err error +	switch vr.stack[vr.frame].vType { +	case bsontype.Array, bsontype.EmbeddedDocument, bsontype.CodeWithScope: +		length, err = vr.peekLength() +	case bsontype.Binary: +		length, err = vr.peekLength() +		length += 4 + 1 // binary length + subtype byte +	case bsontype.Boolean: +		length = 1 +	case bsontype.DBPointer: +		length, err = vr.peekLength() +		length += 4 + 12 // string length + ObjectID length +	case bsontype.DateTime, bsontype.Double, bsontype.Int64, bsontype.Timestamp: +		length = 8 +	case bsontype.Decimal128: +		length = 16 +	case bsontype.Int32: +		length = 4 +	case bsontype.JavaScript, bsontype.String, bsontype.Symbol: +		length, err = vr.peekLength() +		length += 4 +	case bsontype.MaxKey, bsontype.MinKey, bsontype.Null, bsontype.Undefined: +		length = 0 +	case bsontype.ObjectID: +		length = 12 +	case bsontype.Regex: +		regex := bytes.IndexByte(vr.d[vr.offset:], 0x00) +		if regex < 0 { +			err = io.EOF +			break +		} +		pattern := bytes.IndexByte(vr.d[vr.offset+int64(regex)+1:], 0x00) +		if pattern < 0 { +			err = io.EOF +			break +		} +		length = int32(int64(regex) + 1 + int64(pattern) + 1) +	default: +		return 0, fmt.Errorf("attempted to read bytes of unknown BSON type %v", vr.stack[vr.frame].vType) +	} + +	return length, err +} + +func (vr *valueReader) ReadValueBytes(dst []byte) (bsontype.Type, []byte, error) { +	switch vr.stack[vr.frame].mode { +	case mTopLevel: +		length, err := vr.peekLength() +		if err != nil { +			return bsontype.Type(0), nil, err +		} +		dst, err = vr.appendBytes(dst, length) +		if err != nil { +			return bsontype.Type(0), nil, err +		} +		return bsontype.Type(0), dst, nil +	case mElement, mValue: +		length, err := vr.nextElementLength() +		if err != nil { +			return bsontype.Type(0), dst, err +		} + +		dst, err = vr.appendBytes(dst, length) +		t := vr.stack[vr.frame].vType +		vr.pop() +		return t, dst, err +	default: +		return bsontype.Type(0), nil, vr.invalidTransitionErr(0, "ReadValueBytes", []mode{mElement, mValue}) +	} +} + +func (vr *valueReader) Skip() error { +	switch vr.stack[vr.frame].mode { +	case mElement, mValue: +	default: +		return vr.invalidTransitionErr(0, "Skip", []mode{mElement, mValue}) +	} + +	length, err := vr.nextElementLength() +	if err != nil { +		return err +	} + +	err = vr.skipBytes(length) +	vr.pop() +	return err +} + +func (vr *valueReader) ReadArray() (ArrayReader, error) { +	if err := vr.ensureElementValue(bsontype.Array, mArray, "ReadArray"); err != nil { +		return nil, err +	} + +	err := vr.pushArray() +	if err != nil { +		return nil, err +	} + +	return vr, nil +} + +func (vr *valueReader) ReadBinary() (b []byte, btype byte, err error) { +	if err := vr.ensureElementValue(bsontype.Binary, 0, "ReadBinary"); err != nil { +		return nil, 0, err +	} + +	length, err := vr.readLength() +	if err != nil { +		return nil, 0, err +	} + +	btype, err = vr.readByte() +	if err != nil { +		return nil, 0, err +	} + +	// Check length in case it is an old binary without a length. +	if btype == 0x02 && length > 4 { +		length, err = vr.readLength() +		if err != nil { +			return nil, 0, err +		} +	} + +	b, err = vr.readBytes(length) +	if err != nil { +		return nil, 0, err +	} +	// Make a copy of the returned byte slice because it's just a subslice from the valueReader's +	// buffer and is not safe to return in the unmarshaled value. +	cp := make([]byte, len(b)) +	copy(cp, b) + +	vr.pop() +	return cp, btype, nil +} + +func (vr *valueReader) ReadBoolean() (bool, error) { +	if err := vr.ensureElementValue(bsontype.Boolean, 0, "ReadBoolean"); err != nil { +		return false, err +	} + +	b, err := vr.readByte() +	if err != nil { +		return false, err +	} + +	if b > 1 { +		return false, fmt.Errorf("invalid byte for boolean, %b", b) +	} + +	vr.pop() +	return b == 1, nil +} + +func (vr *valueReader) ReadDocument() (DocumentReader, error) { +	switch vr.stack[vr.frame].mode { +	case mTopLevel: +		// read size +		size, err := vr.readLength() +		if err != nil { +			return nil, err +		} +		if int(size) != len(vr.d) { +			return nil, fmt.Errorf("invalid document length") +		} +		vr.stack[vr.frame].end = int64(size) + vr.offset - 4 +		return vr, nil +	case mElement, mValue: +		if vr.stack[vr.frame].vType != bsontype.EmbeddedDocument { +			return nil, vr.typeError(bsontype.EmbeddedDocument) +		} +	default: +		return nil, vr.invalidTransitionErr(mDocument, "ReadDocument", []mode{mTopLevel, mElement, mValue}) +	} + +	err := vr.pushDocument() +	if err != nil { +		return nil, err +	} + +	return vr, nil +} + +func (vr *valueReader) ReadCodeWithScope() (code string, dr DocumentReader, err error) { +	if err := vr.ensureElementValue(bsontype.CodeWithScope, 0, "ReadCodeWithScope"); err != nil { +		return "", nil, err +	} + +	totalLength, err := vr.readLength() +	if err != nil { +		return "", nil, err +	} +	strLength, err := vr.readLength() +	if err != nil { +		return "", nil, err +	} +	if strLength <= 0 { +		return "", nil, fmt.Errorf("invalid string length: %d", strLength) +	} +	strBytes, err := vr.readBytes(strLength) +	if err != nil { +		return "", nil, err +	} +	code = string(strBytes[:len(strBytes)-1]) + +	size, err := vr.pushCodeWithScope() +	if err != nil { +		return "", nil, err +	} + +	// The total length should equal: +	// 4 (total length) + strLength + 4 (the length of str itself) + (document length) +	componentsLength := int64(4+strLength+4) + size +	if int64(totalLength) != componentsLength { +		return "", nil, fmt.Errorf( +			"length of CodeWithScope does not match lengths of components; total: %d; components: %d", +			totalLength, componentsLength, +		) +	} +	return code, vr, nil +} + +func (vr *valueReader) ReadDBPointer() (ns string, oid primitive.ObjectID, err error) { +	if err := vr.ensureElementValue(bsontype.DBPointer, 0, "ReadDBPointer"); err != nil { +		return "", oid, err +	} + +	ns, err = vr.readString() +	if err != nil { +		return "", oid, err +	} + +	oidbytes, err := vr.readBytes(12) +	if err != nil { +		return "", oid, err +	} + +	copy(oid[:], oidbytes) + +	vr.pop() +	return ns, oid, nil +} + +func (vr *valueReader) ReadDateTime() (int64, error) { +	if err := vr.ensureElementValue(bsontype.DateTime, 0, "ReadDateTime"); err != nil { +		return 0, err +	} + +	i, err := vr.readi64() +	if err != nil { +		return 0, err +	} + +	vr.pop() +	return i, nil +} + +func (vr *valueReader) ReadDecimal128() (primitive.Decimal128, error) { +	if err := vr.ensureElementValue(bsontype.Decimal128, 0, "ReadDecimal128"); err != nil { +		return primitive.Decimal128{}, err +	} + +	b, err := vr.readBytes(16) +	if err != nil { +		return primitive.Decimal128{}, err +	} + +	l := binary.LittleEndian.Uint64(b[0:8]) +	h := binary.LittleEndian.Uint64(b[8:16]) + +	vr.pop() +	return primitive.NewDecimal128(h, l), nil +} + +func (vr *valueReader) ReadDouble() (float64, error) { +	if err := vr.ensureElementValue(bsontype.Double, 0, "ReadDouble"); err != nil { +		return 0, err +	} + +	u, err := vr.readu64() +	if err != nil { +		return 0, err +	} + +	vr.pop() +	return math.Float64frombits(u), nil +} + +func (vr *valueReader) ReadInt32() (int32, error) { +	if err := vr.ensureElementValue(bsontype.Int32, 0, "ReadInt32"); err != nil { +		return 0, err +	} + +	vr.pop() +	return vr.readi32() +} + +func (vr *valueReader) ReadInt64() (int64, error) { +	if err := vr.ensureElementValue(bsontype.Int64, 0, "ReadInt64"); err != nil { +		return 0, err +	} + +	vr.pop() +	return vr.readi64() +} + +func (vr *valueReader) ReadJavascript() (code string, err error) { +	if err := vr.ensureElementValue(bsontype.JavaScript, 0, "ReadJavascript"); err != nil { +		return "", err +	} + +	vr.pop() +	return vr.readString() +} + +func (vr *valueReader) ReadMaxKey() error { +	if err := vr.ensureElementValue(bsontype.MaxKey, 0, "ReadMaxKey"); err != nil { +		return err +	} + +	vr.pop() +	return nil +} + +func (vr *valueReader) ReadMinKey() error { +	if err := vr.ensureElementValue(bsontype.MinKey, 0, "ReadMinKey"); err != nil { +		return err +	} + +	vr.pop() +	return nil +} + +func (vr *valueReader) ReadNull() error { +	if err := vr.ensureElementValue(bsontype.Null, 0, "ReadNull"); err != nil { +		return err +	} + +	vr.pop() +	return nil +} + +func (vr *valueReader) ReadObjectID() (primitive.ObjectID, error) { +	if err := vr.ensureElementValue(bsontype.ObjectID, 0, "ReadObjectID"); err != nil { +		return primitive.ObjectID{}, err +	} + +	oidbytes, err := vr.readBytes(12) +	if err != nil { +		return primitive.ObjectID{}, err +	} + +	var oid primitive.ObjectID +	copy(oid[:], oidbytes) + +	vr.pop() +	return oid, nil +} + +func (vr *valueReader) ReadRegex() (string, string, error) { +	if err := vr.ensureElementValue(bsontype.Regex, 0, "ReadRegex"); err != nil { +		return "", "", err +	} + +	pattern, err := vr.readCString() +	if err != nil { +		return "", "", err +	} + +	options, err := vr.readCString() +	if err != nil { +		return "", "", err +	} + +	vr.pop() +	return pattern, options, nil +} + +func (vr *valueReader) ReadString() (string, error) { +	if err := vr.ensureElementValue(bsontype.String, 0, "ReadString"); err != nil { +		return "", err +	} + +	vr.pop() +	return vr.readString() +} + +func (vr *valueReader) ReadSymbol() (symbol string, err error) { +	if err := vr.ensureElementValue(bsontype.Symbol, 0, "ReadSymbol"); err != nil { +		return "", err +	} + +	vr.pop() +	return vr.readString() +} + +func (vr *valueReader) ReadTimestamp() (t uint32, i uint32, err error) { +	if err := vr.ensureElementValue(bsontype.Timestamp, 0, "ReadTimestamp"); err != nil { +		return 0, 0, err +	} + +	i, err = vr.readu32() +	if err != nil { +		return 0, 0, err +	} + +	t, err = vr.readu32() +	if err != nil { +		return 0, 0, err +	} + +	vr.pop() +	return t, i, nil +} + +func (vr *valueReader) ReadUndefined() error { +	if err := vr.ensureElementValue(bsontype.Undefined, 0, "ReadUndefined"); err != nil { +		return err +	} + +	vr.pop() +	return nil +} + +func (vr *valueReader) ReadElement() (string, ValueReader, error) { +	switch vr.stack[vr.frame].mode { +	case mTopLevel, mDocument, mCodeWithScope: +	default: +		return "", nil, vr.invalidTransitionErr(mElement, "ReadElement", []mode{mTopLevel, mDocument, mCodeWithScope}) +	} + +	t, err := vr.readByte() +	if err != nil { +		return "", nil, err +	} + +	if t == 0 { +		if vr.offset != vr.stack[vr.frame].end { +			return "", nil, vr.invalidDocumentLengthError() +		} + +		vr.pop() +		return "", nil, ErrEOD +	} + +	name, err := vr.readCString() +	if err != nil { +		return "", nil, err +	} + +	vr.pushElement(bsontype.Type(t)) +	return name, vr, nil +} + +func (vr *valueReader) ReadValue() (ValueReader, error) { +	switch vr.stack[vr.frame].mode { +	case mArray: +	default: +		return nil, vr.invalidTransitionErr(mValue, "ReadValue", []mode{mArray}) +	} + +	t, err := vr.readByte() +	if err != nil { +		return nil, err +	} + +	if t == 0 { +		if vr.offset != vr.stack[vr.frame].end { +			return nil, vr.invalidDocumentLengthError() +		} + +		vr.pop() +		return nil, ErrEOA +	} + +	_, err = vr.readCString() +	if err != nil { +		return nil, err +	} + +	vr.pushValue(bsontype.Type(t)) +	return vr, nil +} + +// readBytes reads length bytes from the valueReader starting at the current offset. Note that the +// returned byte slice is a subslice from the valueReader buffer and must be converted or copied +// before returning in an unmarshaled value. +func (vr *valueReader) readBytes(length int32) ([]byte, error) { +	if length < 0 { +		return nil, fmt.Errorf("invalid length: %d", length) +	} + +	if vr.offset+int64(length) > int64(len(vr.d)) { +		return nil, io.EOF +	} + +	start := vr.offset +	vr.offset += int64(length) + +	return vr.d[start : start+int64(length)], nil +} + +func (vr *valueReader) appendBytes(dst []byte, length int32) ([]byte, error) { +	if vr.offset+int64(length) > int64(len(vr.d)) { +		return nil, io.EOF +	} + +	start := vr.offset +	vr.offset += int64(length) +	return append(dst, vr.d[start:start+int64(length)]...), nil +} + +func (vr *valueReader) skipBytes(length int32) error { +	if vr.offset+int64(length) > int64(len(vr.d)) { +		return io.EOF +	} + +	vr.offset += int64(length) +	return nil +} + +func (vr *valueReader) readByte() (byte, error) { +	if vr.offset+1 > int64(len(vr.d)) { +		return 0x0, io.EOF +	} + +	vr.offset++ +	return vr.d[vr.offset-1], nil +} + +func (vr *valueReader) readCString() (string, error) { +	idx := bytes.IndexByte(vr.d[vr.offset:], 0x00) +	if idx < 0 { +		return "", io.EOF +	} +	start := vr.offset +	// idx does not include the null byte +	vr.offset += int64(idx) + 1 +	return string(vr.d[start : start+int64(idx)]), nil +} + +func (vr *valueReader) readString() (string, error) { +	length, err := vr.readLength() +	if err != nil { +		return "", err +	} + +	if int64(length)+vr.offset > int64(len(vr.d)) { +		return "", io.EOF +	} + +	if length <= 0 { +		return "", fmt.Errorf("invalid string length: %d", length) +	} + +	if vr.d[vr.offset+int64(length)-1] != 0x00 { +		return "", fmt.Errorf("string does not end with null byte, but with %v", vr.d[vr.offset+int64(length)-1]) +	} + +	start := vr.offset +	vr.offset += int64(length) +	return string(vr.d[start : start+int64(length)-1]), nil +} + +func (vr *valueReader) peekLength() (int32, error) { +	if vr.offset+4 > int64(len(vr.d)) { +		return 0, io.EOF +	} + +	idx := vr.offset +	return (int32(vr.d[idx]) | int32(vr.d[idx+1])<<8 | int32(vr.d[idx+2])<<16 | int32(vr.d[idx+3])<<24), nil +} + +func (vr *valueReader) readLength() (int32, error) { return vr.readi32() } + +func (vr *valueReader) readi32() (int32, error) { +	if vr.offset+4 > int64(len(vr.d)) { +		return 0, io.EOF +	} + +	idx := vr.offset +	vr.offset += 4 +	return (int32(vr.d[idx]) | int32(vr.d[idx+1])<<8 | int32(vr.d[idx+2])<<16 | int32(vr.d[idx+3])<<24), nil +} + +func (vr *valueReader) readu32() (uint32, error) { +	if vr.offset+4 > int64(len(vr.d)) { +		return 0, io.EOF +	} + +	idx := vr.offset +	vr.offset += 4 +	return (uint32(vr.d[idx]) | uint32(vr.d[idx+1])<<8 | uint32(vr.d[idx+2])<<16 | uint32(vr.d[idx+3])<<24), nil +} + +func (vr *valueReader) readi64() (int64, error) { +	if vr.offset+8 > int64(len(vr.d)) { +		return 0, io.EOF +	} + +	idx := vr.offset +	vr.offset += 8 +	return int64(vr.d[idx]) | int64(vr.d[idx+1])<<8 | int64(vr.d[idx+2])<<16 | int64(vr.d[idx+3])<<24 | +		int64(vr.d[idx+4])<<32 | int64(vr.d[idx+5])<<40 | int64(vr.d[idx+6])<<48 | int64(vr.d[idx+7])<<56, nil +} + +func (vr *valueReader) readu64() (uint64, error) { +	if vr.offset+8 > int64(len(vr.d)) { +		return 0, io.EOF +	} + +	idx := vr.offset +	vr.offset += 8 +	return uint64(vr.d[idx]) | uint64(vr.d[idx+1])<<8 | uint64(vr.d[idx+2])<<16 | uint64(vr.d[idx+3])<<24 | +		uint64(vr.d[idx+4])<<32 | uint64(vr.d[idx+5])<<40 | uint64(vr.d[idx+6])<<48 | uint64(vr.d[idx+7])<<56, nil +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/value_writer.go b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/value_writer.go new file mode 100644 index 000000000..f95a08afd --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/value_writer.go @@ -0,0 +1,606 @@ +// 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 bsonrw + +import ( +	"errors" +	"fmt" +	"io" +	"math" +	"strconv" +	"strings" +	"sync" + +	"go.mongodb.org/mongo-driver/bson/bsontype" +	"go.mongodb.org/mongo-driver/bson/primitive" +	"go.mongodb.org/mongo-driver/x/bsonx/bsoncore" +) + +var _ ValueWriter = (*valueWriter)(nil) + +var vwPool = sync.Pool{ +	New: func() interface{} { +		return new(valueWriter) +	}, +} + +// BSONValueWriterPool is a pool for BSON ValueWriters. +type BSONValueWriterPool struct { +	pool sync.Pool +} + +// NewBSONValueWriterPool creates a new pool for ValueWriter instances that write to BSON. +func NewBSONValueWriterPool() *BSONValueWriterPool { +	return &BSONValueWriterPool{ +		pool: sync.Pool{ +			New: func() interface{} { +				return new(valueWriter) +			}, +		}, +	} +} + +// Get retrieves a BSON ValueWriter from the pool and resets it to use w as the destination. +func (bvwp *BSONValueWriterPool) Get(w io.Writer) ValueWriter { +	vw := bvwp.pool.Get().(*valueWriter) + +	// TODO: Having to call reset here with the same buffer doesn't really make sense. +	vw.reset(vw.buf) +	vw.buf = vw.buf[:0] +	vw.w = w +	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) { +	bvw, ok := vw.(*valueWriter) +	if !ok { +		return false +	} + +	bvwp.pool.Put(bvw) +	return true +} + +// This is here so that during testing we can change it and not require +// allocating a 4GB slice. +var maxSize = math.MaxInt32 + +var errNilWriter = errors.New("cannot create a ValueWriter from a nil io.Writer") + +type errMaxDocumentSizeExceeded struct { +	size int64 +} + +func (mdse errMaxDocumentSizeExceeded) Error() string { +	return fmt.Sprintf("document size (%d) is larger than the max int32", mdse.size) +} + +type vwMode int + +const ( +	_ vwMode = iota +	vwTopLevel +	vwDocument +	vwArray +	vwValue +	vwElement +	vwCodeWithScope +) + +func (vm vwMode) String() string { +	var str string + +	switch vm { +	case vwTopLevel: +		str = "TopLevel" +	case vwDocument: +		str = "DocumentMode" +	case vwArray: +		str = "ArrayMode" +	case vwValue: +		str = "ValueMode" +	case vwElement: +		str = "ElementMode" +	case vwCodeWithScope: +		str = "CodeWithScopeMode" +	default: +		str = "UnknownMode" +	} + +	return str +} + +type vwState struct { +	mode   mode +	key    string +	arrkey int +	start  int32 +} + +type valueWriter struct { +	w   io.Writer +	buf []byte + +	stack []vwState +	frame int64 +} + +func (vw *valueWriter) advanceFrame() { +	if vw.frame+1 >= int64(len(vw.stack)) { // We need to grow the stack +		length := len(vw.stack) +		if length+1 >= cap(vw.stack) { +			// double it +			buf := make([]vwState, 2*cap(vw.stack)+1) +			copy(buf, vw.stack) +			vw.stack = buf +		} +		vw.stack = vw.stack[:length+1] +	} +	vw.frame++ +} + +func (vw *valueWriter) push(m mode) { +	vw.advanceFrame() + +	// Clean the stack +	vw.stack[vw.frame].mode = m +	vw.stack[vw.frame].key = "" +	vw.stack[vw.frame].arrkey = 0 +	vw.stack[vw.frame].start = 0 + +	vw.stack[vw.frame].mode = m +	switch m { +	case mDocument, mArray, mCodeWithScope: +		vw.reserveLength() +	} +} + +func (vw *valueWriter) reserveLength() { +	vw.stack[vw.frame].start = int32(len(vw.buf)) +	vw.buf = append(vw.buf, 0x00, 0x00, 0x00, 0x00) +} + +func (vw *valueWriter) pop() { +	switch vw.stack[vw.frame].mode { +	case mElement, mValue: +		vw.frame-- +	case mDocument, mArray, mCodeWithScope: +		vw.frame -= 2 // we pop twice to jump over the mElement: mDocument -> mElement -> mDocument/mTopLevel/etc... +	} +} + +// NewBSONValueWriter creates a ValueWriter that writes BSON to w. +// +// This ValueWriter will only write entire documents to the io.Writer and it +// will buffer the document as it is built. +func NewBSONValueWriter(w io.Writer) (ValueWriter, error) { +	if w == nil { +		return nil, errNilWriter +	} +	return newValueWriter(w), nil +} + +func newValueWriter(w io.Writer) *valueWriter { +	vw := new(valueWriter) +	stack := make([]vwState, 1, 5) +	stack[0] = vwState{mode: mTopLevel} +	vw.w = w +	vw.stack = stack + +	return vw +} + +func newValueWriterFromSlice(buf []byte) *valueWriter { +	vw := new(valueWriter) +	stack := make([]vwState, 1, 5) +	stack[0] = vwState{mode: mTopLevel} +	vw.stack = stack +	vw.buf = buf + +	return vw +} + +func (vw *valueWriter) reset(buf []byte) { +	if vw.stack == nil { +		vw.stack = make([]vwState, 1, 5) +	} +	vw.stack = vw.stack[:1] +	vw.stack[0] = vwState{mode: mTopLevel} +	vw.buf = buf +	vw.frame = 0 +	vw.w = nil +} + +func (vw *valueWriter) invalidTransitionError(destination mode, name string, modes []mode) error { +	te := TransitionError{ +		name:        name, +		current:     vw.stack[vw.frame].mode, +		destination: destination, +		modes:       modes, +		action:      "write", +	} +	if vw.frame != 0 { +		te.parent = vw.stack[vw.frame-1].mode +	} +	return te +} + +func (vw *valueWriter) writeElementHeader(t bsontype.Type, destination mode, callerName string, addmodes ...mode) error { +	switch vw.stack[vw.frame].mode { +	case mElement: +		key := vw.stack[vw.frame].key +		if !isValidCString(key) { +			return errors.New("BSON element key cannot contain null bytes") +		} + +		vw.buf = bsoncore.AppendHeader(vw.buf, t, key) +	case mValue: +		// TODO: Do this with a cache of the first 1000 or so array keys. +		vw.buf = bsoncore.AppendHeader(vw.buf, t, strconv.Itoa(vw.stack[vw.frame].arrkey)) +	default: +		modes := []mode{mElement, mValue} +		if addmodes != nil { +			modes = append(modes, addmodes...) +		} +		return vw.invalidTransitionError(destination, callerName, modes) +	} + +	return nil +} + +func (vw *valueWriter) WriteValueBytes(t bsontype.Type, b []byte) error { +	if err := vw.writeElementHeader(t, mode(0), "WriteValueBytes"); err != nil { +		return err +	} +	vw.buf = append(vw.buf, b...) +	vw.pop() +	return nil +} + +func (vw *valueWriter) WriteArray() (ArrayWriter, error) { +	if err := vw.writeElementHeader(bsontype.Array, mArray, "WriteArray"); err != nil { +		return nil, err +	} + +	vw.push(mArray) + +	return vw, nil +} + +func (vw *valueWriter) WriteBinary(b []byte) error { +	return vw.WriteBinaryWithSubtype(b, 0x00) +} + +func (vw *valueWriter) WriteBinaryWithSubtype(b []byte, btype byte) error { +	if err := vw.writeElementHeader(bsontype.Binary, mode(0), "WriteBinaryWithSubtype"); err != nil { +		return err +	} + +	vw.buf = bsoncore.AppendBinary(vw.buf, btype, b) +	vw.pop() +	return nil +} + +func (vw *valueWriter) WriteBoolean(b bool) error { +	if err := vw.writeElementHeader(bsontype.Boolean, mode(0), "WriteBoolean"); err != nil { +		return err +	} + +	vw.buf = bsoncore.AppendBoolean(vw.buf, b) +	vw.pop() +	return nil +} + +func (vw *valueWriter) WriteCodeWithScope(code string) (DocumentWriter, error) { +	if err := vw.writeElementHeader(bsontype.CodeWithScope, mCodeWithScope, "WriteCodeWithScope"); err != nil { +		return nil, err +	} + +	// CodeWithScope is a different than other types because we need an extra +	// frame on the stack. In the EndDocument code, we write the document +	// length, pop, write the code with scope length, and pop. To simplify the +	// pop code, we push a spacer frame that we'll always jump over. +	vw.push(mCodeWithScope) +	vw.buf = bsoncore.AppendString(vw.buf, code) +	vw.push(mSpacer) +	vw.push(mDocument) + +	return vw, nil +} + +func (vw *valueWriter) WriteDBPointer(ns string, oid primitive.ObjectID) error { +	if err := vw.writeElementHeader(bsontype.DBPointer, mode(0), "WriteDBPointer"); err != nil { +		return err +	} + +	vw.buf = bsoncore.AppendDBPointer(vw.buf, ns, oid) +	vw.pop() +	return nil +} + +func (vw *valueWriter) WriteDateTime(dt int64) error { +	if err := vw.writeElementHeader(bsontype.DateTime, mode(0), "WriteDateTime"); err != nil { +		return err +	} + +	vw.buf = bsoncore.AppendDateTime(vw.buf, dt) +	vw.pop() +	return nil +} + +func (vw *valueWriter) WriteDecimal128(d128 primitive.Decimal128) error { +	if err := vw.writeElementHeader(bsontype.Decimal128, mode(0), "WriteDecimal128"); err != nil { +		return err +	} + +	vw.buf = bsoncore.AppendDecimal128(vw.buf, d128) +	vw.pop() +	return nil +} + +func (vw *valueWriter) WriteDouble(f float64) error { +	if err := vw.writeElementHeader(bsontype.Double, mode(0), "WriteDouble"); err != nil { +		return err +	} + +	vw.buf = bsoncore.AppendDouble(vw.buf, f) +	vw.pop() +	return nil +} + +func (vw *valueWriter) WriteInt32(i32 int32) error { +	if err := vw.writeElementHeader(bsontype.Int32, mode(0), "WriteInt32"); err != nil { +		return err +	} + +	vw.buf = bsoncore.AppendInt32(vw.buf, i32) +	vw.pop() +	return nil +} + +func (vw *valueWriter) WriteInt64(i64 int64) error { +	if err := vw.writeElementHeader(bsontype.Int64, mode(0), "WriteInt64"); err != nil { +		return err +	} + +	vw.buf = bsoncore.AppendInt64(vw.buf, i64) +	vw.pop() +	return nil +} + +func (vw *valueWriter) WriteJavascript(code string) error { +	if err := vw.writeElementHeader(bsontype.JavaScript, mode(0), "WriteJavascript"); err != nil { +		return err +	} + +	vw.buf = bsoncore.AppendJavaScript(vw.buf, code) +	vw.pop() +	return nil +} + +func (vw *valueWriter) WriteMaxKey() error { +	if err := vw.writeElementHeader(bsontype.MaxKey, mode(0), "WriteMaxKey"); err != nil { +		return err +	} + +	vw.pop() +	return nil +} + +func (vw *valueWriter) WriteMinKey() error { +	if err := vw.writeElementHeader(bsontype.MinKey, mode(0), "WriteMinKey"); err != nil { +		return err +	} + +	vw.pop() +	return nil +} + +func (vw *valueWriter) WriteNull() error { +	if err := vw.writeElementHeader(bsontype.Null, mode(0), "WriteNull"); err != nil { +		return err +	} + +	vw.pop() +	return nil +} + +func (vw *valueWriter) WriteObjectID(oid primitive.ObjectID) error { +	if err := vw.writeElementHeader(bsontype.ObjectID, mode(0), "WriteObjectID"); err != nil { +		return err +	} + +	vw.buf = bsoncore.AppendObjectID(vw.buf, oid) +	vw.pop() +	return nil +} + +func (vw *valueWriter) WriteRegex(pattern string, options string) error { +	if !isValidCString(pattern) || !isValidCString(options) { +		return errors.New("BSON regex values cannot contain null bytes") +	} +	if err := vw.writeElementHeader(bsontype.Regex, mode(0), "WriteRegex"); err != nil { +		return err +	} + +	vw.buf = bsoncore.AppendRegex(vw.buf, pattern, sortStringAlphebeticAscending(options)) +	vw.pop() +	return nil +} + +func (vw *valueWriter) WriteString(s string) error { +	if err := vw.writeElementHeader(bsontype.String, mode(0), "WriteString"); err != nil { +		return err +	} + +	vw.buf = bsoncore.AppendString(vw.buf, s) +	vw.pop() +	return nil +} + +func (vw *valueWriter) WriteDocument() (DocumentWriter, error) { +	if vw.stack[vw.frame].mode == mTopLevel { +		vw.reserveLength() +		return vw, nil +	} +	if err := vw.writeElementHeader(bsontype.EmbeddedDocument, mDocument, "WriteDocument", mTopLevel); err != nil { +		return nil, err +	} + +	vw.push(mDocument) +	return vw, nil +} + +func (vw *valueWriter) WriteSymbol(symbol string) error { +	if err := vw.writeElementHeader(bsontype.Symbol, mode(0), "WriteSymbol"); err != nil { +		return err +	} + +	vw.buf = bsoncore.AppendSymbol(vw.buf, symbol) +	vw.pop() +	return nil +} + +func (vw *valueWriter) WriteTimestamp(t uint32, i uint32) error { +	if err := vw.writeElementHeader(bsontype.Timestamp, mode(0), "WriteTimestamp"); err != nil { +		return err +	} + +	vw.buf = bsoncore.AppendTimestamp(vw.buf, t, i) +	vw.pop() +	return nil +} + +func (vw *valueWriter) WriteUndefined() error { +	if err := vw.writeElementHeader(bsontype.Undefined, mode(0), "WriteUndefined"); err != nil { +		return err +	} + +	vw.pop() +	return nil +} + +func (vw *valueWriter) WriteDocumentElement(key string) (ValueWriter, error) { +	switch vw.stack[vw.frame].mode { +	case mTopLevel, mDocument: +	default: +		return nil, vw.invalidTransitionError(mElement, "WriteDocumentElement", []mode{mTopLevel, mDocument}) +	} + +	vw.push(mElement) +	vw.stack[vw.frame].key = key + +	return vw, nil +} + +func (vw *valueWriter) WriteDocumentEnd() error { +	switch vw.stack[vw.frame].mode { +	case mTopLevel, mDocument: +	default: +		return fmt.Errorf("incorrect mode to end document: %s", vw.stack[vw.frame].mode) +	} + +	vw.buf = append(vw.buf, 0x00) + +	err := vw.writeLength() +	if err != nil { +		return err +	} + +	if vw.stack[vw.frame].mode == mTopLevel { +		if err = vw.Flush(); err != nil { +			return err +		} +	} + +	vw.pop() + +	if vw.stack[vw.frame].mode == mCodeWithScope { +		// We ignore the error here because of the guarantee of writeLength. +		// See the docs for writeLength for more info. +		_ = vw.writeLength() +		vw.pop() +	} +	return nil +} + +func (vw *valueWriter) Flush() error { +	if vw.w == nil { +		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}) +	} + +	arrkey := vw.stack[vw.frame].arrkey +	vw.stack[vw.frame].arrkey++ + +	vw.push(mValue) +	vw.stack[vw.frame].arrkey = arrkey + +	return vw, nil +} + +func (vw *valueWriter) WriteArrayEnd() error { +	if vw.stack[vw.frame].mode != mArray { +		return fmt.Errorf("incorrect mode to end array: %s", vw.stack[vw.frame].mode) +	} + +	vw.buf = append(vw.buf, 0x00) + +	err := vw.writeLength() +	if err != nil { +		return err +	} + +	vw.pop() +	return nil +} + +// NOTE: We assume that if we call writeLength more than once the same function +// within the same function without altering the vw.buf that this method will +// not return an error. If this changes ensure that the following methods are +// updated: +// +// - WriteDocumentEnd +func (vw *valueWriter) writeLength() error { +	length := len(vw.buf) +	if length > maxSize { +		return errMaxDocumentSizeExceeded{size: int64(len(vw.buf))} +	} +	length = length - int(vw.stack[vw.frame].start) +	start := vw.stack[vw.frame].start + +	vw.buf[start+0] = byte(length) +	vw.buf[start+1] = byte(length >> 8) +	vw.buf[start+2] = byte(length >> 16) +	vw.buf[start+3] = byte(length >> 24) +	return nil +} + +func isValidCString(cs string) bool { +	return !strings.ContainsRune(cs, '\x00') +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/writer.go b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/writer.go new file mode 100644 index 000000000..dff65f87f --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/writer.go @@ -0,0 +1,78 @@ +// 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 bsonrw + +import ( +	"go.mongodb.org/mongo-driver/bson/bsontype" +	"go.mongodb.org/mongo-driver/bson/primitive" +) + +// ArrayWriter is the interface used to create a BSON or BSON adjacent array. +// Callers must ensure they call WriteArrayEnd when they have finished creating +// the array. +type ArrayWriter interface { +	WriteArrayElement() (ValueWriter, error) +	WriteArrayEnd() error +} + +// DocumentWriter is the interface used to create a BSON or BSON adjacent +// document. Callers must ensure they call WriteDocumentEnd when they have +// finished creating the document. +type DocumentWriter interface { +	WriteDocumentElement(string) (ValueWriter, error) +	WriteDocumentEnd() error +} + +// ValueWriter is the interface used to write BSON values. Implementations of +// this interface handle creating BSON or BSON adjacent representations of the +// values. +type ValueWriter interface { +	WriteArray() (ArrayWriter, error) +	WriteBinary(b []byte) error +	WriteBinaryWithSubtype(b []byte, btype byte) error +	WriteBoolean(bool) error +	WriteCodeWithScope(code string) (DocumentWriter, error) +	WriteDBPointer(ns string, oid primitive.ObjectID) error +	WriteDateTime(dt int64) error +	WriteDecimal128(primitive.Decimal128) error +	WriteDouble(float64) error +	WriteInt32(int32) error +	WriteInt64(int64) error +	WriteJavascript(code string) error +	WriteMaxKey() error +	WriteMinKey() error +	WriteNull() error +	WriteObjectID(primitive.ObjectID) error +	WriteRegex(pattern, options string) error +	WriteString(string) error +	WriteDocument() (DocumentWriter, error) +	WriteSymbol(symbol string) error +	WriteTimestamp(t, i uint32) error +	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. +type BytesWriter interface { +	WriteValueBytes(t bsontype.Type, b []byte) error +} + +// SliceWriter allows a pointer to a slice of bytes to be used as an io.Writer. +type SliceWriter []byte + +func (sw *SliceWriter) Write(p []byte) (int, error) { +	written := len(p) +	*sw = append(*sw, p...) +	return written, nil +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsontype/bsontype.go b/vendor/go.mongodb.org/mongo-driver/bson/bsontype/bsontype.go new file mode 100644 index 000000000..7c91ae518 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsontype/bsontype.go @@ -0,0 +1,97 @@ +// 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 bsontype is a utility package that contains types for each BSON type and the +// a stringifier for the Type to enable easier debugging when working with BSON. +package bsontype // import "go.mongodb.org/mongo-driver/bson/bsontype" + +// These constants uniquely refer to each BSON type. +const ( +	Double           Type = 0x01 +	String           Type = 0x02 +	EmbeddedDocument Type = 0x03 +	Array            Type = 0x04 +	Binary           Type = 0x05 +	Undefined        Type = 0x06 +	ObjectID         Type = 0x07 +	Boolean          Type = 0x08 +	DateTime         Type = 0x09 +	Null             Type = 0x0A +	Regex            Type = 0x0B +	DBPointer        Type = 0x0C +	JavaScript       Type = 0x0D +	Symbol           Type = 0x0E +	CodeWithScope    Type = 0x0F +	Int32            Type = 0x10 +	Timestamp        Type = 0x11 +	Int64            Type = 0x12 +	Decimal128       Type = 0x13 +	MinKey           Type = 0xFF +	MaxKey           Type = 0x7F + +	BinaryGeneric     byte = 0x00 +	BinaryFunction    byte = 0x01 +	BinaryBinaryOld   byte = 0x02 +	BinaryUUIDOld     byte = 0x03 +	BinaryUUID        byte = 0x04 +	BinaryMD5         byte = 0x05 +	BinaryEncrypted   byte = 0x06 +	BinaryColumn      byte = 0x07 +	BinaryUserDefined byte = 0x80 +) + +// Type represents a BSON type. +type Type byte + +// String returns the string representation of the BSON type's name. +func (bt Type) String() string { +	switch bt { +	case '\x01': +		return "double" +	case '\x02': +		return "string" +	case '\x03': +		return "embedded document" +	case '\x04': +		return "array" +	case '\x05': +		return "binary" +	case '\x06': +		return "undefined" +	case '\x07': +		return "objectID" +	case '\x08': +		return "boolean" +	case '\x09': +		return "UTC datetime" +	case '\x0A': +		return "null" +	case '\x0B': +		return "regex" +	case '\x0C': +		return "dbPointer" +	case '\x0D': +		return "javascript" +	case '\x0E': +		return "symbol" +	case '\x0F': +		return "code with scope" +	case '\x10': +		return "32-bit integer" +	case '\x11': +		return "timestamp" +	case '\x12': +		return "64-bit integer" +	case '\x13': +		return "128-bit decimal" +	case '\xFF': +		return "min key" +	case '\x7F': +		return "max key" +	default: +		return "invalid" +	} +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/decoder.go b/vendor/go.mongodb.org/mongo-driver/bson/decoder.go new file mode 100644 index 000000000..6e189fa58 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/decoder.go @@ -0,0 +1,141 @@ +// 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 bson + +import ( +	"errors" +	"fmt" +	"reflect" +	"sync" + +	"go.mongodb.org/mongo-driver/bson/bsoncodec" +	"go.mongodb.org/mongo-driver/bson/bsonrw" +) + +// ErrDecodeToNil is the error returned when trying to decode to a nil value +var ErrDecodeToNil = errors.New("cannot Decode to nil value") + +// This pool is used to keep the allocations of Decoders down. This is only used for the Marshal* +// methods and is not consumable from outside of this package. The Decoders retrieved from this pool +// must have both Reset and SetRegistry called on them. +var decPool = sync.Pool{ +	New: func() interface{} { +		return new(Decoder) +	}, +} + +// A Decoder reads and decodes BSON documents from a stream. It reads from a bsonrw.ValueReader as +// the source of BSON data. +type Decoder struct { +	dc bsoncodec.DecodeContext +	vr bsonrw.ValueReader + +	// We persist defaultDocumentM and defaultDocumentD on the Decoder to prevent overwriting from +	// (*Decoder).SetContext. +	defaultDocumentM bool +	defaultDocumentD bool +} + +// NewDecoder returns a new decoder that uses the DefaultRegistry to read from vr. +func NewDecoder(vr bsonrw.ValueReader) (*Decoder, error) { +	if vr == nil { +		return nil, errors.New("cannot create a new Decoder with a nil ValueReader") +	} + +	return &Decoder{ +		dc: bsoncodec.DecodeContext{Registry: DefaultRegistry}, +		vr: vr, +	}, nil +} + +// NewDecoderWithContext returns a new decoder that uses DecodeContext dc to read from vr. +func NewDecoderWithContext(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader) (*Decoder, error) { +	if dc.Registry == nil { +		dc.Registry = DefaultRegistry +	} +	if vr == nil { +		return nil, errors.New("cannot create a new Decoder with a nil ValueReader") +	} + +	return &Decoder{ +		dc: dc, +		vr: vr, +	}, nil +} + +// Decode reads the next BSON document from the stream and decodes it into the +// value pointed to by val. +// +// The documentation for Unmarshal contains details about of BSON into a Go +// value. +func (d *Decoder) Decode(val interface{}) error { +	if unmarshaler, ok := val.(Unmarshaler); ok { +		// TODO(skriptble): Reuse a []byte here and use the AppendDocumentBytes method. +		buf, err := bsonrw.Copier{}.CopyDocumentToBytes(d.vr) +		if err != nil { +			return err +		} +		return unmarshaler.UnmarshalBSON(buf) +	} + +	rval := reflect.ValueOf(val) +	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) +	} +	decoder, err := d.dc.LookupDecoder(rval.Type()) +	if err != nil { +		return err +	} +	if d.defaultDocumentM { +		d.dc.DefaultDocumentM() +	} +	if d.defaultDocumentD { +		d.dc.DefaultDocumentD() +	} +	return decoder.DecodeValue(d.dc, d.vr, rval) +} + +// Reset will reset the state of the decoder, using the same *DecodeContext used in +// the original construction but using vr for reading. +func (d *Decoder) Reset(vr bsonrw.ValueReader) error { +	d.vr = vr +	return nil +} + +// SetRegistry replaces the current registry of the decoder with r. +func (d *Decoder) SetRegistry(r *bsoncodec.Registry) error { +	d.dc.Registry = r +	return nil +} + +// SetContext replaces the current registry of the decoder with dc. +func (d *Decoder) SetContext(dc bsoncodec.DecodeContext) error { +	d.dc = dc +	return nil +} + +// DefaultDocumentM will decode empty documents using the primitive.M type. This behavior is restricted to data typed as +// "interface{}" or "map[string]interface{}". +func (d *Decoder) DefaultDocumentM() { +	d.defaultDocumentM = true +} + +// DefaultDocumentD will decode empty documents using the primitive.D type. This behavior is restricted to data typed as +// "interface{}" or "map[string]interface{}". +func (d *Decoder) DefaultDocumentD() { +	d.defaultDocumentD = true +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/doc.go b/vendor/go.mongodb.org/mongo-driver/bson/doc.go new file mode 100644 index 000000000..0134006d8 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/doc.go @@ -0,0 +1,141 @@ +// 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 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. +// The BSON library handles marshalling and unmarshalling of values through a configurable codec system. For a description +// of the codec system and examples of registering custom codecs, see the bsoncodec package. +// +// # 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 +// type. +// +// Example: +// +//	var raw bson.Raw = ... // bytes from somewhere +//	err := raw.Validate() +//	if err != nil { return err } +//	val := raw.Lookup("foo") +//	i32, ok := val.Int32OK() +//	// do something with i32... +// +// # 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. +// +// Note that a D should not be constructed with duplicate key names, as that can cause undefined server behavior. +// +// 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: +// +//  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 nil. +//  20. BSON DBPointer unmarshals to a primitive.DBPointer. +//  21. BSON symbol unmarshals to a primitive.Symbol. +// +// 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. +//  7. BSON null and undefined values will unmarshal into the zero value of a field (e.g. unmarshalling a BSON null or +//     undefined value into a string will yield the empty string.). +// +// # Structs +// +// Structs can be marshalled/unmarshalled to/from BSON or Extended JSON. When transforming structs to/from BSON or Extended +// JSON, 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 overridden 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 encoding of each struct field can be customized by the "bson" struct tag. +// +// This tag behavior is configurable, and different struct tag behavior can be configured by initializing a new +// bsoncodec.StructCodec with the desired tag parser and registering that StructCodec onto the Registry. By default, JSON tags +// are not honored, but that can be enabled by creating a StructCodec with JSONFallbackStructTagParser, like below: +// +// Example: +// +//	structcodec, _ := bsoncodec.NewStructCodec(bsoncodec.JSONFallbackStructTagParser) +// +// The bson tag gives the name of the field, possibly followed by a comma-separated list of options. +// The name may be empty in order to specify options without overriding the default field name. The following options 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. Fields with language primitive types such as integers, booleans, and strings are considered empty if +//     their value is equal to the zero value for the type (i.e. 0 for integers, false for booleans, and "" for strings). +//     Slices, maps, and arrays are considered empty if they are of length zero. Interfaces and pointers are considered +//     empty if their value is nil. By default, structs are only considered empty if the struct type implements the +//     bsoncodec.Zeroer interface and the IsZero method returns true. Struct fields whose types do not implement Zeroer are +//     never considered empty and will be marshalled as embedded documents. +//     NOTE: It is recommended that this tag be used for all slice and map fields. +// +//  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 truncated 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 struct is marshalled, the inlined field will be overwritten. +//     If there are duplicated fields in the resulting document when an inlined map 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/vendor/go.mongodb.org/mongo-driver/bson/encoder.go b/vendor/go.mongodb.org/mongo-driver/bson/encoder.go new file mode 100644 index 000000000..fe5125d08 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/encoder.go @@ -0,0 +1,99 @@ +// 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 bson + +import ( +	"errors" +	"reflect" +	"sync" + +	"go.mongodb.org/mongo-driver/bson/bsoncodec" +	"go.mongodb.org/mongo-driver/bson/bsonrw" +) + +// This pool is used to keep the allocations of Encoders down. This is only used for the Marshal* +// methods and is not consumable from outside of this package. The Encoders retrieved from this pool +// must have both Reset and SetRegistry called on them. +var encPool = sync.Pool{ +	New: func() interface{} { +		return new(Encoder) +	}, +} + +// An Encoder writes a serialization format to an output stream. It writes to a bsonrw.ValueWriter +// as the destination of BSON data. +type Encoder struct { +	ec bsoncodec.EncodeContext +	vw bsonrw.ValueWriter +} + +// NewEncoder returns a new encoder that uses the DefaultRegistry to write to vw. +func NewEncoder(vw bsonrw.ValueWriter) (*Encoder, error) { +	if vw == nil { +		return nil, errors.New("cannot create a new Encoder with a nil ValueWriter") +	} + +	return &Encoder{ +		ec: bsoncodec.EncodeContext{Registry: DefaultRegistry}, +		vw: vw, +	}, nil +} + +// NewEncoderWithContext returns a new encoder that uses EncodeContext ec to write to vw. +func NewEncoderWithContext(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter) (*Encoder, error) { +	if ec.Registry == nil { +		ec = bsoncodec.EncodeContext{Registry: DefaultRegistry} +	} +	if vw == nil { +		return nil, errors.New("cannot create a new Encoder with a nil ValueWriter") +	} + +	return &Encoder{ +		ec: ec, +		vw: vw, +	}, nil +} + +// Encode writes the BSON encoding of val to the stream. +// +// The documentation for Marshal contains details about the conversion of Go +// values to BSON. +func (e *Encoder) Encode(val interface{}) error { +	if marshaler, ok := val.(Marshaler); ok { +		// TODO(skriptble): Should we have a MarshalAppender interface so that we can have []byte reuse? +		buf, err := marshaler.MarshalBSON() +		if err != nil { +			return err +		} +		return bsonrw.Copier{}.CopyDocumentFromBytes(e.vw, buf) +	} + +	encoder, err := e.ec.LookupEncoder(reflect.TypeOf(val)) +	if err != nil { +		return err +	} +	return encoder.EncodeValue(e.ec, e.vw, reflect.ValueOf(val)) +} + +// Reset will reset the state of the encoder, using the same *EncodeContext used in +// the original construction but using vw. +func (e *Encoder) Reset(vw bsonrw.ValueWriter) error { +	e.vw = vw +	return nil +} + +// SetRegistry replaces the current registry of the encoder with r. +func (e *Encoder) SetRegistry(r *bsoncodec.Registry) error { +	e.ec.Registry = r +	return nil +} + +// SetContext replaces the current EncodeContext of the encoder with er. +func (e *Encoder) SetContext(ec bsoncodec.EncodeContext) error { +	e.ec = ec +	return nil +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/marshal.go b/vendor/go.mongodb.org/mongo-driver/bson/marshal.go new file mode 100644 index 000000000..db8d8ee92 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/marshal.go @@ -0,0 +1,248 @@ +// 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 bson + +import ( +	"bytes" +	"encoding/json" + +	"go.mongodb.org/mongo-driver/bson/bsoncodec" +	"go.mongodb.org/mongo-driver/bson/bsonrw" +	"go.mongodb.org/mongo-driver/bson/bsontype" +) + +const defaultDstCap = 256 + +var bvwPool = bsonrw.NewBSONValueWriterPool() +var extjPool = bsonrw.NewExtJSONValueWriterPool() + +// Marshaler is an interface implemented by types that can marshal themselves +// into a BSON document represented as bytes. The bytes returned must be a valid +// BSON document if the error is nil. +type Marshaler interface { +	MarshalBSON() ([]byte, error) +} + +// ValueMarshaler is an interface implemented by types that can marshal +// themselves into a BSON value as bytes. The type must be the valid type for +// the bytes returned. The bytes and byte type together must be valid if the +// error is nil. +type ValueMarshaler interface { +	MarshalBSONValue() (bsontype.Type, []byte, error) +} + +// 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 +// marshaling process accordingly. +func Marshal(val interface{}) ([]byte, error) { +	return MarshalWithRegistry(DefaultRegistry, val) +} + +// 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 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) +	return MarshalAppendWithRegistry(r, dst, val) +} + +// 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) +	return MarshalAppendWithContext(ec, dst, val) +} + +// 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 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 +	vw := bvwPool.Get(sw) +	defer bvwPool.Put(vw) + +	enc := encPool.Get().(*Encoder) +	defer encPool.Put(enc) + +	err := enc.Reset(vw) +	if err != nil { +		return nil, err +	} +	err = enc.SetContext(ec) +	if err != nil { +		return nil, err +	} + +	err = enc.Encode(val) +	if err != nil { +		return nil, err +	} + +	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) +	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) +	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) +} + +// MarshalExtJSONAppend will append the extended JSON encoding of val to dst. +// If dst is not large enough to hold the extended JSON encoding of val, dst +// will be grown. +func MarshalExtJSONAppend(dst []byte, val interface{}, canonical, escapeHTML bool) ([]byte, error) { +	return MarshalExtJSONAppendWithRegistry(DefaultRegistry, dst, val, canonical, escapeHTML) +} + +// MarshalExtJSONWithRegistry returns the extended JSON encoding of val using Registry r. +func MarshalExtJSONWithRegistry(r *bsoncodec.Registry, val interface{}, canonical, escapeHTML bool) ([]byte, error) { +	dst := make([]byte, 0, defaultDstCap) +	return MarshalExtJSONAppendWithContext(bsoncodec.EncodeContext{Registry: r}, dst, val, canonical, escapeHTML) +} + +// MarshalExtJSONWithContext returns the extended JSON encoding of val using Registry r. +func MarshalExtJSONWithContext(ec bsoncodec.EncodeContext, val interface{}, canonical, escapeHTML bool) ([]byte, error) { +	dst := make([]byte, 0, defaultDstCap) +	return MarshalExtJSONAppendWithContext(ec, dst, val, canonical, escapeHTML) +} + +// MarshalExtJSONAppendWithRegistry will append the extended JSON 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 MarshalExtJSONAppendWithRegistry(r *bsoncodec.Registry, dst []byte, val interface{}, canonical, escapeHTML bool) ([]byte, error) { +	return MarshalExtJSONAppendWithContext(bsoncodec.EncodeContext{Registry: r}, dst, val, canonical, escapeHTML) +} + +// MarshalExtJSONAppendWithContext will append the extended JSON 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 MarshalExtJSONAppendWithContext(ec bsoncodec.EncodeContext, dst []byte, val interface{}, canonical, escapeHTML bool) ([]byte, error) { +	sw := new(bsonrw.SliceWriter) +	*sw = dst +	ejvw := extjPool.Get(sw, canonical, escapeHTML) +	defer extjPool.Put(ejvw) + +	enc := encPool.Get().(*Encoder) +	defer encPool.Put(enc) + +	err := enc.Reset(ejvw) +	if err != nil { +		return nil, err +	} +	err = enc.SetContext(ec) +	if err != nil { +		return nil, err +	} + +	err = enc.Encode(val) +	if err != nil { +		return nil, err +	} + +	return *sw, nil +} + +// IndentExtJSON will prefix and indent the provided extended JSON src and append it to dst. +func IndentExtJSON(dst *bytes.Buffer, src []byte, prefix, indent string) error { +	return json.Indent(dst, src, prefix, indent) +} + +// MarshalExtJSONIndent returns the extended JSON encoding of val with each line with prefixed +// and indented. +func MarshalExtJSONIndent(val interface{}, canonical, escapeHTML bool, prefix, indent string) ([]byte, error) { +	marshaled, err := MarshalExtJSON(val, canonical, escapeHTML) +	if err != nil { +		return nil, err +	} + +	var buf bytes.Buffer +	err = IndentExtJSON(&buf, marshaled, prefix, indent) +	if err != nil { +		return nil, err +	} + +	return buf.Bytes(), nil +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/primitive/decimal.go b/vendor/go.mongodb.org/mongo-driver/bson/primitive/decimal.go new file mode 100644 index 000000000..ba7c9112e --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/primitive/decimal.go @@ -0,0 +1,423 @@ +// 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 +// +// Based on gopkg.in/mgo.v2/bson by Gustavo Niemeyer +// See THIRD-PARTY-NOTICES for original license terms. + +package primitive + +import ( +	"encoding/json" +	"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 +} + +// NewDecimal128 creates a Decimal128 using the provide high and low uint64s. +func NewDecimal128(h, l uint64) Decimal128 { +	return Decimal128{h: h, l: l} +} + +// 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 +} + +// String returns a string representation of the decimal value. +func (d Decimal128) String() string { +	var posSign int      // positive sign +	var exp int          // exponent +	var high, low uint64 // significand high/low + +	if d.h>>63&1 == 0 { +		posSign = 1 +	} + +	switch d.h >> 58 & (1<<5 - 1) { +	case 0x1F: +		return "NaN" +	case 0x1E: +		return "-Infinity"[posSign:] +	} + +	low = d.l +	if d.h>>61&3 == 3 { +		// Bits: 1*sign 2*ignored 14*exponent 111*significand. +		// Implicit 0b100 prefix in significand. +		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. +		high, low = 0, 0 +	} else { +		// Bits: 1*sign 14*exponent 113*significand +		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 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) + exp +	var rem uint32 +Loop: +	for d9 := 0; d9 < 5; d9++ { +		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 || low == 0 && high == 0 && rem > 0 && rem < 10 && (dot < i-6 || exp > 0)) { +				exp += len(repr) - i +				i-- +				repr[i] = '.' +				last = i - 1 +				dot = len(repr) // Unmark. +			} +			c := '0' + byte(rem%10) +			rem /= 10 +			i-- +			repr[i] = c +			// Handle "0E+3", "1E+3", etc. +			if low == 0 && high == 0 && rem == 0 && i == len(repr)-1 && (dot < i-5 || exp > 0) { +				last = i +				break Loop +			} +			if c != '0' { +				last = i +			} +			// Break early. Works without it, but why. +			if dot > i && low == 0 && high == 0 && rem == 0 { +				break Loop +			} +		} +	} +	repr[last-1] = '-' +	last-- + +	if exp > 0 { +		return string(repr[last+posSign:]) + "E+" + strconv.Itoa(exp) +	} +	if exp < 0 { +		return string(repr[last+posSign:]) + "E" + strconv.Itoa(exp) +	} +	return string(repr[last+posSign:]) +} + +// BigInt returns significand as big.Int and exponent, bi * 10 ^ exp. +func (d Decimal128) BigInt() (*big.Int, int, error) { +	high, low := d.GetBytes() +	posSign := high>>63&1 == 0 // positive sign + +	switch high >> 58 & (1<<5 - 1) { +	case 0x1F: +		return nil, 0, ErrParseNaN +	case 0x1E: +		if posSign { +			return nil, 0, ErrParseInf +		} +		return nil, 0, ErrParseNegInf +	} + +	var exp int +	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 bi, exp, nil +} + +// 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 +} + +// IsZero returns true if d is the empty Decimal128. +func (d Decimal128) IsZero() bool { +	return d.h == 0 && d.l == 0 +} + +// MarshalJSON returns Decimal128 as a string. +func (d Decimal128) MarshalJSON() ([]byte, error) { +	return json.Marshal(d.String()) +} + +// UnmarshalJSON creates a primitive.Decimal128 from a JSON string, an extended JSON $numberDecimal value, or the string +// "null". If b is a JSON string or extended JSON value, d will have the value of that string, and if b is "null", d will +// be unchanged. +func (d *Decimal128) UnmarshalJSON(b []byte) error { +	// Ignore "null" to keep parity with the standard library. Decoding a JSON null into a non-pointer Decimal128 field +	// will leave the field unchanged. For pointer values, encoding/json will set the pointer to nil and will not +	// enter the UnmarshalJSON hook. +	if string(b) == "null" { +		return nil +	} + +	var res interface{} +	err := json.Unmarshal(b, &res) +	if err != nil { +		return err +	} +	str, ok := res.(string) + +	// Extended JSON +	if !ok { +		m, ok := res.(map[string]interface{}) +		if !ok { +			return errors.New("not an extended JSON Decimal128: expected document") +		} +		d128, ok := m["$numberDecimal"] +		if !ok { +			return errors.New("not an extended JSON Decimal128: expected key $numberDecimal") +		} +		str, ok = d128.(string) +		if !ok { +			return errors.New("not an extended JSON Decimal128: expected decimal to be string") +		} +	} + +	*d, err = ParseDecimal128(str) +	return err +} + +func divmod(h, l uint64, div uint32) (qh, ql uint64, rem uint32) { +	div64 := uint64(div) +	a := h >> 32 +	aq := a / div64 +	ar := a % div64 +	b := ar<<32 + h&(1<<32-1) +	bq := b / div64 +	br := b % div64 +	c := br<<32 + l>>32 +	cq := c / div64 +	cr := c % div64 +	d := cr<<32 + l&(1<<32-1) +	dq := d / div64 +	dr := d % div64 +	return (aq<<32 | bq), (cq<<32 | dq), uint32(dr) +} + +var dNaN = Decimal128{0x1F << 58, 0} +var dPosInf = Decimal128{0x1E << 58, 0} +var dNegInf = Decimal128{0x3E << 58, 0} + +func dErr(s string) (Decimal128, error) { +	return dNaN, fmt.Errorf("cannot parse %q as a decimal128", s) +} + +// 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) { +	if s == "" { +		return dErr(s) +	} + +	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 +		} +		if s == "Inf" || s == "inf" || strings.EqualFold(s, "inf") || strings.EqualFold(s, "infinity") { +			if neg { +				return dNegInf, nil +			} +			return dPosInf, nil +		} +		return dErr(orig) +	} + +	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) +		} +	} +	if decPart != "" { +		exp -= len(decPart) +	} + +	if len(strings.Trim(intPart+decPart, "-0")) > 35 { +		return dErr(s) +	} + +	bi, ok := new(big.Int).SetString(intPart+decPart, 10) +	if !ok { +		return dErr(s) +	} + +	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 +		} +		exp++ +		if exp > MaxDecimal128Exp { +			return Decimal128{}, false +		} +	} + +	for exp < MinDecimal128Exp { +		// Subnormal. +		bi, _ = q.QuoRem(bi, ten, r) +		if r.Cmp(zero) != 0 { +			return Decimal128{}, false +		} +		exp++ +	} +	for exp > MaxDecimal128Exp { +		// Clamped. +		bi.Mul(bi, ten) +		if bigIntCmpAbs(bi, maxS) == 1 { +			return Decimal128{}, false +		} +		exp-- +	} + +	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(exp-MinDecimal128Exp) & uint64(1<<14-1) << 49 +	if bi.Sign() == -1 { +		h |= 1 << 63 +	} + +	return Decimal128{h: h, l: l}, true +} + +// 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) +} + +// 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/vendor/go.mongodb.org/mongo-driver/bson/primitive/objectid.go b/vendor/go.mongodb.org/mongo-driver/bson/primitive/objectid.go new file mode 100644 index 000000000..ded367316 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/primitive/objectid.go @@ -0,0 +1,206 @@ +// 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 +// +// Based on gopkg.in/mgo.v2/bson by Gustavo Niemeyer +// See THIRD-PARTY-NOTICES for original license terms. + +package primitive + +import ( +	"crypto/rand" +	"encoding" +	"encoding/binary" +	"encoding/hex" +	"encoding/json" +	"errors" +	"fmt" +	"io" +	"sync/atomic" +	"time" +) + +// ErrInvalidHex indicates that a hex string cannot be converted to an ObjectID. +var ErrInvalidHex = errors.New("the provided hex string is not a valid ObjectID") + +// ObjectID is the BSON ObjectID type. +type ObjectID [12]byte + +// NilObjectID is the zero value for ObjectID. +var NilObjectID ObjectID + +var objectIDCounter = readRandomUint32() +var processUnique = processUniqueBytes() + +var _ encoding.TextMarshaler = ObjectID{} +var _ encoding.TextUnmarshaler = &ObjectID{} + +// NewObjectID generates a new ObjectID. +func NewObjectID() ObjectID { +	return NewObjectIDFromTimestamp(time.Now()) +} + +// NewObjectIDFromTimestamp generates a new ObjectID based on the given time. +func NewObjectIDFromTimestamp(timestamp time.Time) ObjectID { +	var b [12]byte + +	binary.BigEndian.PutUint32(b[0:4], uint32(timestamp.Unix())) +	copy(b[4:9], processUnique[:]) +	putUint24(b[9:12], atomic.AddUint32(&objectIDCounter, 1)) + +	return b +} + +// Timestamp extracts the time part of the ObjectId. +func (id ObjectID) Timestamp() time.Time { +	unixSecs := binary.BigEndian.Uint32(id[0:4]) +	return time.Unix(int64(unixSecs), 0).UTC() +} + +// Hex returns the hex encoding of the ObjectID as a string. +func (id ObjectID) Hex() string { +	var buf [24]byte +	hex.Encode(buf[:], id[:]) +	return string(buf[:]) +} + +func (id ObjectID) String() string { +	return fmt.Sprintf("ObjectID(%q)", id.Hex()) +} + +// IsZero returns true if id is the empty ObjectID. +func (id ObjectID) IsZero() bool { +	return id == NilObjectID +} + +// ObjectIDFromHex creates a new ObjectID from a hex string. It returns an error if the hex string is not a +// valid ObjectID. +func ObjectIDFromHex(s string) (ObjectID, error) { +	if len(s) != 24 { +		return NilObjectID, ErrInvalidHex +	} + +	b, err := hex.DecodeString(s) +	if err != nil { +		return NilObjectID, err +	} + +	var oid [12]byte +	copy(oid[:], b) + +	return oid, nil +} + +// IsValidObjectID returns true if the provided hex string represents a valid ObjectID and false if not. +func IsValidObjectID(s string) bool { +	_, err := ObjectIDFromHex(s) +	return err == nil +} + +// MarshalText returns the ObjectID as UTF-8-encoded text. Implementing this allows us to use ObjectID +// as a map key when marshalling JSON. See https://pkg.go.dev/encoding#TextMarshaler +func (id ObjectID) MarshalText() ([]byte, error) { +	return []byte(id.Hex()), nil +} + +// UnmarshalText populates the byte slice with the ObjectID. Implementing this allows us to use ObjectID +// as a map key when unmarshalling JSON. See https://pkg.go.dev/encoding#TextUnmarshaler +func (id *ObjectID) UnmarshalText(b []byte) error { +	oid, err := ObjectIDFromHex(string(b)) +	if err != nil { +		return err +	} +	*id = oid +	return nil +} + +// MarshalJSON returns the ObjectID as a string +func (id ObjectID) MarshalJSON() ([]byte, error) { +	return json.Marshal(id.Hex()) +} + +// UnmarshalJSON populates the byte slice with the ObjectID. If the byte slice is 24 bytes long, it +// will be populated with the hex representation of the ObjectID. If the byte slice is twelve bytes +// long, it will be populated with the BSON representation of the ObjectID. This method also accepts empty strings and +// decodes them as NilObjectID. For any other inputs, an error will be returned. +func (id *ObjectID) UnmarshalJSON(b []byte) error { +	// Ignore "null" to keep parity with the standard library. Decoding a JSON null into a non-pointer ObjectID field +	// will leave the field unchanged. For pointer values, encoding/json will set the pointer to nil and will not +	// enter the UnmarshalJSON hook. +	if string(b) == "null" { +		return nil +	} + +	var err error +	switch len(b) { +	case 12: +		copy(id[:], b) +	default: +		// Extended JSON +		var res interface{} +		err := json.Unmarshal(b, &res) +		if err != nil { +			return err +		} +		str, ok := res.(string) +		if !ok { +			m, ok := res.(map[string]interface{}) +			if !ok { +				return errors.New("not an extended JSON ObjectID") +			} +			oid, ok := m["$oid"] +			if !ok { +				return errors.New("not an extended JSON ObjectID") +			} +			str, ok = oid.(string) +			if !ok { +				return errors.New("not an extended JSON ObjectID") +			} +		} + +		// An empty string is not a valid ObjectID, but we treat it as a special value that decodes as NilObjectID. +		if len(str) == 0 { +			copy(id[:], NilObjectID[:]) +			return nil +		} + +		if len(str) != 24 { +			return fmt.Errorf("cannot unmarshal into an ObjectID, the length must be 24 but it is %d", len(str)) +		} + +		_, err = hex.Decode(id[:], []byte(str)) +		if err != nil { +			return err +		} +	} + +	return err +} + +func processUniqueBytes() [5]byte { +	var b [5]byte +	_, err := io.ReadFull(rand.Reader, b[:]) +	if err != nil { +		panic(fmt.Errorf("cannot initialize objectid package with crypto.rand.Reader: %v", err)) +	} + +	return b +} + +func readRandomUint32() uint32 { +	var b [4]byte +	_, err := io.ReadFull(rand.Reader, b[:]) +	if err != nil { +		panic(fmt.Errorf("cannot initialize objectid package with crypto.rand.Reader: %v", err)) +	} + +	return (uint32(b[0]) << 0) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24) +} + +func putUint24(b []byte, v uint32) { +	b[0] = byte(v >> 16) +	b[1] = byte(v >> 8) +	b[2] = byte(v) +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/primitive/primitive.go b/vendor/go.mongodb.org/mongo-driver/bson/primitive/primitive.go new file mode 100644 index 000000000..c72ccc1c4 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/primitive/primitive.go @@ -0,0 +1,217 @@ +// 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 primitive contains types similar to Go primitives for BSON types that do not have direct +// Go primitive representations. +package primitive // import "go.mongodb.org/mongo-driver/bson/primitive" + +import ( +	"bytes" +	"encoding/json" +	"fmt" +	"time" +) + +// Binary represents a BSON binary value. +type Binary struct { +	Subtype byte +	Data    []byte +} + +// Equal compares bp to bp2 and returns true if they are equal. +func (bp Binary) Equal(bp2 Binary) bool { +	if bp.Subtype != bp2.Subtype { +		return false +	} +	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{} + +// DateTime represents the BSON datetime value. +type DateTime int64 + +var _ json.Marshaler = DateTime(0) +var _ json.Unmarshaler = (*DateTime)(nil) + +// MarshalJSON marshal to time type. +func (d DateTime) MarshalJSON() ([]byte, error) { +	return json.Marshal(d.Time()) +} + +// UnmarshalJSON creates a primitive.DateTime from a JSON string. +func (d *DateTime) UnmarshalJSON(data []byte) error { +	// Ignore "null" to keep parity with the time.Time type and the standard library. Decoding "null" into a non-pointer +	// DateTime field will leave the field unchanged. For pointer values, the encoding/json will set the pointer to nil +	// and will not defer to the UnmarshalJSON hook. +	if string(data) == "null" { +		return nil +	} + +	var tempTime time.Time +	if err := json.Unmarshal(data, &tempTime); err != nil { +		return err +	} + +	*d = NewDateTimeFromTime(tempTime) +	return nil +} + +// Time returns the date as a time type. +func (d DateTime) Time() time.Time { +	return time.Unix(int64(d)/1000, int64(d)%1000*1000000) +} + +// NewDateTimeFromTime creates a new DateTime from a Time. +func NewDateTimeFromTime(t time.Time) DateTime { +	return DateTime(t.Unix()*1e3 + int64(t.Nanosecond())/1e6) +} + +// Null represents the BSON null value. +type Null struct{} + +// Regex represents a BSON regex value. +type Regex struct { +	Pattern string +	Options string +} + +func (rp Regex) String() string { +	return fmt.Sprintf(`{"pattern": "%s", "options": "%s"}`, rp.Pattern, rp.Options) +} + +// Equal compares rp to rp2 and returns true if they are equal. +func (rp Regex) Equal(rp2 Regex) bool { +	return rp.Pattern == rp2.Pattern && rp.Options == rp2.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 +	Pointer ObjectID +} + +func (d DBPointer) String() string { +	return fmt.Sprintf(`{"db": "%s", "pointer": "%s"}`, d.DB, d.Pointer) +} + +// Equal compares d to d2 and returns true if they are equal. +func (d DBPointer) Equal(d2 DBPointer) bool { +	return d == d2 +} + +// 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 + +// Symbol represents a BSON symbol value. +type Symbol string + +// CodeWithScope represents a BSON JavaScript code with scope value. +type CodeWithScope struct { +	Code  JavaScript +	Scope interface{} +} + +func (cws CodeWithScope) String() string { +	return fmt.Sprintf(`{"code": "%s", "scope": %v}`, cws.Code, cws.Scope) +} + +// Timestamp represents a BSON timestamp value. +type Timestamp struct { +	T uint32 +	I uint32 +} + +// Equal compares tp to tp2 and returns true if they 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 { +	if tp.Equal(tp2) { +		return 0 +	} + +	if tp.T > tp2.T { +		return 1 +	} +	if tp.T < tp2.T { +		return -1 +	} +	// Compare I values because T values are equal +	if tp.I > tp2.I { +		return 1 +	} +	return -1 +} + +// MinKey represents the BSON minkey value. +type MinKey struct{} + +// MaxKey represents the BSON maxkey value. +type MaxKey struct{} + +// 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}} +type D []E + +// Map creates a map from the elements of the D. +func (d D) Map() M { +	m := make(M, len(d)) +	for _, e := range d { +		m[e.Key] = e.Value +	} +	return m +} + +// E represents a BSON element for a D. It is usually used inside a D. +type E struct { +	Key   string +	Value interface{} +} + +// 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} +type M map[string]interface{} + +// An A is an ordered representation of a BSON array. +// +// Example usage: +// +//	bson.A{"bar", "world", 3.14159, bson.D{{"qux", 12345}}} +type A []interface{} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/primitive_codecs.go b/vendor/go.mongodb.org/mongo-driver/bson/primitive_codecs.go new file mode 100644 index 000000000..1cbe3884d --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/primitive_codecs.go @@ -0,0 +1,92 @@ +// 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 bson + +import ( +	"errors" +	"reflect" + +	"go.mongodb.org/mongo-driver/bson/bsoncodec" +	"go.mongodb.org/mongo-driver/bson/bsonrw" +) + +var tRawValue = reflect.TypeOf(RawValue{}) +var tRaw = reflect.TypeOf(Raw(nil)) + +var primitiveCodecs PrimitiveCodecs + +// PrimitiveCodecs is a namespace for all of the default bsoncodec.Codecs for the primitive types +// defined in this package. +type PrimitiveCodecs struct{} + +// RegisterPrimitiveCodecs will register the encode and decode methods attached to PrimitiveCodecs +// with the provided RegistryBuilder. if rb is nil, a new empty RegistryBuilder will be created. +func (pc PrimitiveCodecs) RegisterPrimitiveCodecs(rb *bsoncodec.RegistryBuilder) { +	if rb == nil { +		panic(errors.New("argument to RegisterPrimitiveCodecs must not be nil")) +	} + +	rb. +		RegisterTypeEncoder(tRawValue, bsoncodec.ValueEncoderFunc(pc.RawValueEncodeValue)). +		RegisterTypeEncoder(tRaw, bsoncodec.ValueEncoderFunc(pc.RawEncodeValue)). +		RegisterTypeDecoder(tRawValue, bsoncodec.ValueDecoderFunc(pc.RawValueDecodeValue)). +		RegisterTypeDecoder(tRaw, bsoncodec.ValueDecoderFunc(pc.RawDecodeValue)) +} + +// RawValueEncodeValue is the ValueEncoderFunc for RawValue. +func (PrimitiveCodecs) RawValueEncodeValue(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Type() != tRawValue { +		return bsoncodec.ValueEncoderError{Name: "RawValueEncodeValue", Types: []reflect.Type{tRawValue}, Received: val} +	} + +	rawvalue := val.Interface().(RawValue) + +	return bsonrw.Copier{}.CopyValueFromBytes(vw, rawvalue.Type, rawvalue.Value) +} + +// RawValueDecodeValue is the ValueDecoderFunc for RawValue. +func (PrimitiveCodecs) RawValueDecodeValue(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Type() != tRawValue { +		return bsoncodec.ValueDecoderError{Name: "RawValueDecodeValue", Types: []reflect.Type{tRawValue}, Received: val} +	} + +	t, value, err := bsonrw.Copier{}.CopyValueToBytes(vr) +	if err != nil { +		return err +	} + +	val.Set(reflect.ValueOf(RawValue{Type: t, Value: value})) +	return nil +} + +// RawEncodeValue is the ValueEncoderFunc for Reader. +func (PrimitiveCodecs) RawEncodeValue(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { +	if !val.IsValid() || val.Type() != tRaw { +		return bsoncodec.ValueEncoderError{Name: "RawEncodeValue", Types: []reflect.Type{tRaw}, Received: val} +	} + +	rdr := val.Interface().(Raw) + +	return bsonrw.Copier{}.CopyDocumentFromBytes(vw, rdr) +} + +// RawDecodeValue is the ValueDecoderFunc for Reader. +func (PrimitiveCodecs) RawDecodeValue(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { +	if !val.CanSet() || val.Type() != tRaw { +		return bsoncodec.ValueDecoderError{Name: "RawDecodeValue", Types: []reflect.Type{tRaw}, Received: val} +	} + +	if val.IsNil() { +		val.Set(reflect.MakeSlice(val.Type(), 0, 0)) +	} + +	val.SetLen(0) + +	rdr, err := bsonrw.Copier{}.AppendDocumentBytes(val.Interface().(Raw), vr) +	val.Set(reflect.ValueOf(rdr)) +	return err +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/raw.go b/vendor/go.mongodb.org/mongo-driver/bson/raw.go new file mode 100644 index 000000000..efd705daa --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/raw.go @@ -0,0 +1,85 @@ +// 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 bson + +import ( +	"errors" +	"io" + +	"go.mongodb.org/mongo-driver/x/bsonx/bsoncore" +) + +// ErrNilReader indicates that an operation was attempted on a nil bson.Reader. +var ErrNilReader = errors.New("nil reader") + +// Raw is a wrapper around a byte slice. It will interpret the slice as a +// BSON document. This type is a wrapper around a bsoncore.Document. Errors returned from the +// methods on this type and associated types come from the bsoncore package. +type Raw []byte + +// NewFromIOReader reads in a document from the given io.Reader and constructs a Raw from +// it. +func NewFromIOReader(r io.Reader) (Raw, error) { +	doc, err := bsoncore.NewDocumentFromReader(r) +	return Raw(doc), err +} + +// Validate validates the document. This method only validates the first document in +// the slice, to validate other documents, the slice must be resliced. +func (r Raw) Validate() (err error) { return bsoncore.Document(r).Validate() } + +// Lookup search the document, potentially recursively, for the given key. If +// there are multiple keys provided, this method will recurse down, as long as +// the top and intermediate nodes are either documents or arrays.If an error +// occurs or if the value doesn't exist, an empty RawValue is returned. +func (r Raw) Lookup(key ...string) RawValue { +	return convertFromCoreValue(bsoncore.Document(r).Lookup(key...)) +} + +// LookupErr searches the document and potentially subdocuments or arrays for the +// provided key. Each key provided to this method represents a layer of depth. +func (r Raw) LookupErr(key ...string) (RawValue, error) { +	val, err := bsoncore.Document(r).LookupErr(key...) +	return convertFromCoreValue(val), err +} + +// Elements returns this document as a slice of elements. The returned slice will contain valid +// elements. If the document is not valid, the elements up to the invalid point will be returned +// along with an error. +func (r Raw) Elements() ([]RawElement, error) { +	elems, err := bsoncore.Document(r).Elements() +	relems := make([]RawElement, 0, len(elems)) +	for _, elem := range elems { +		relems = append(relems, RawElement(elem)) +	} +	return relems, err +} + +// Values returns this document as a slice of values. The returned slice will contain valid values. +// If the document is not valid, the values up to the invalid point will be returned along with an +// error. +func (r Raw) Values() ([]RawValue, error) { +	vals, err := bsoncore.Document(r).Values() +	rvals := make([]RawValue, 0, len(vals)) +	for _, val := range vals { +		rvals = append(rvals, convertFromCoreValue(val)) +	} +	return rvals, err +} + +// Index searches for and retrieves the element at the given index. This method will panic if +// the document is invalid or if the index is out of bounds. +func (r Raw) Index(index uint) RawElement { return RawElement(bsoncore.Document(r).Index(index)) } + +// IndexErr searches for and retrieves the element at the given index. +func (r Raw) IndexErr(index uint) (RawElement, error) { +	elem, err := bsoncore.Document(r).IndexErr(index) +	return RawElement(elem), err +} + +// String implements the fmt.Stringer interface. +func (r Raw) String() string { return bsoncore.Document(r).String() } diff --git a/vendor/go.mongodb.org/mongo-driver/bson/raw_element.go b/vendor/go.mongodb.org/mongo-driver/bson/raw_element.go new file mode 100644 index 000000000..006f503a3 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/raw_element.go @@ -0,0 +1,51 @@ +// 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 bson + +import ( +	"go.mongodb.org/mongo-driver/x/bsonx/bsoncore" +) + +// RawElement represents a BSON element in byte form. This type provides a simple way to +// transform a slice of bytes into a BSON element and extract information from it. +// +// RawElement is a thin wrapper around a bsoncore.Element. +type RawElement []byte + +// Key returns the key for this element. If the element is not valid, this method returns an empty +// string. If knowing if the element is valid is important, use KeyErr. +func (re RawElement) Key() string { return bsoncore.Element(re).Key() } + +// KeyErr returns the key for this element, returning an error if the element is not valid. +func (re RawElement) KeyErr() (string, error) { return bsoncore.Element(re).KeyErr() } + +// Value returns the value of this element. If the element is not valid, this method returns an +// empty Value. If knowing if the element is valid is important, use ValueErr. +func (re RawElement) Value() RawValue { return convertFromCoreValue(bsoncore.Element(re).Value()) } + +// ValueErr returns the value for this element, returning an error if the element is not valid. +func (re RawElement) ValueErr() (RawValue, error) { +	val, err := bsoncore.Element(re).ValueErr() +	return convertFromCoreValue(val), err +} + +// Validate ensures re is a valid BSON element. +func (re RawElement) Validate() error { return bsoncore.Element(re).Validate() } + +// String implements the fmt.Stringer interface. The output will be in extended JSON format. +func (re RawElement) String() string { +	doc := bsoncore.BuildDocument(nil, re) +	j, err := MarshalExtJSON(Raw(doc), true, false) +	if err != nil { +		return "<malformed>" +	} +	return string(j) +} + +// DebugString outputs a human readable version of RawElement. It will attempt to stringify the +// valid components of the element even if the entire element is not valid. +func (re RawElement) DebugString() string { return bsoncore.Element(re).DebugString() } diff --git a/vendor/go.mongodb.org/mongo-driver/bson/raw_value.go b/vendor/go.mongodb.org/mongo-driver/bson/raw_value.go new file mode 100644 index 000000000..75297f30f --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/raw_value.go @@ -0,0 +1,309 @@ +// 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 bson + +import ( +	"bytes" +	"errors" +	"fmt" +	"reflect" +	"time" + +	"go.mongodb.org/mongo-driver/bson/bsoncodec" +	"go.mongodb.org/mongo-driver/bson/bsonrw" +	"go.mongodb.org/mongo-driver/bson/bsontype" +	"go.mongodb.org/mongo-driver/bson/primitive" +	"go.mongodb.org/mongo-driver/x/bsonx/bsoncore" +) + +// ErrNilContext is returned when the provided DecodeContext is nil. +var ErrNilContext = errors.New("DecodeContext cannot be nil") + +// ErrNilRegistry is returned when the provided registry is nil. +var ErrNilRegistry = errors.New("Registry cannot be nil") + +// RawValue represents a BSON value in byte form. It can be used to hold unprocessed BSON or to +// defer processing of BSON. Type is the BSON type of the value and Value are the raw bytes that +// represent the element. +// +// This type wraps bsoncore.Value for most of it's functionality. +type RawValue struct { +	Type  bsontype.Type +	Value []byte + +	r *bsoncodec.Registry +} + +// Unmarshal deserializes BSON into the provided val. If RawValue cannot be unmarshaled into val, an +// error is returned. This method will use the registry used to create the RawValue, if the RawValue +// was created from partial BSON processing, or it will use the default registry. Users wishing to +// specify the registry to use should use UnmarshalWithRegistry. +func (rv RawValue) Unmarshal(val interface{}) error { +	reg := rv.r +	if reg == nil { +		reg = DefaultRegistry +	} +	return rv.UnmarshalWithRegistry(reg, val) +} + +// Equal compares rv and rv2 and returns true if they are equal. +func (rv RawValue) Equal(rv2 RawValue) bool { +	if rv.Type != rv2.Type { +		return false +	} + +	if !bytes.Equal(rv.Value, rv2.Value) { +		return false +	} + +	return true +} + +// UnmarshalWithRegistry performs the same unmarshalling as Unmarshal but uses the provided registry +// instead of the one attached or the default registry. +func (rv RawValue) UnmarshalWithRegistry(r *bsoncodec.Registry, val interface{}) error { +	if r == nil { +		return ErrNilRegistry +	} + +	vr := bsonrw.NewBSONValueReader(rv.Type, rv.Value) +	rval := reflect.ValueOf(val) +	if rval.Kind() != reflect.Ptr { +		return fmt.Errorf("argument to Unmarshal* must be a pointer to a type, but got %v", rval) +	} +	rval = rval.Elem() +	dec, err := r.LookupDecoder(rval.Type()) +	if err != nil { +		return err +	} +	return dec.DecodeValue(bsoncodec.DecodeContext{Registry: r}, vr, rval) +} + +// UnmarshalWithContext performs the same unmarshalling as Unmarshal but uses the provided DecodeContext +// instead of the one attached or the default registry. +func (rv RawValue) UnmarshalWithContext(dc *bsoncodec.DecodeContext, val interface{}) error { +	if dc == nil { +		return ErrNilContext +	} + +	vr := bsonrw.NewBSONValueReader(rv.Type, rv.Value) +	rval := reflect.ValueOf(val) +	if rval.Kind() != reflect.Ptr { +		return fmt.Errorf("argument to Unmarshal* must be a pointer to a type, but got %v", rval) +	} +	rval = rval.Elem() +	dec, err := dc.LookupDecoder(rval.Type()) +	if err != nil { +		return err +	} +	return dec.DecodeValue(*dc, vr, rval) +} + +func convertFromCoreValue(v bsoncore.Value) RawValue { return RawValue{Type: v.Type, Value: v.Data} } +func convertToCoreValue(v RawValue) bsoncore.Value { +	return bsoncore.Value{Type: v.Type, Data: v.Value} +} + +// Validate ensures the value is a valid BSON value. +func (rv RawValue) Validate() error { return convertToCoreValue(rv).Validate() } + +// IsNumber returns true if the type of v is a numeric BSON type. +func (rv RawValue) IsNumber() bool { return convertToCoreValue(rv).IsNumber() } + +// String implements the fmt.String interface. This method will return values in extended JSON +// format. If the value is not valid, this returns an empty string +func (rv RawValue) String() string { return convertToCoreValue(rv).String() } + +// DebugString outputs a human readable version of Document. It will attempt to stringify the +// valid components of the document even if the entire document is not valid. +func (rv RawValue) DebugString() string { return convertToCoreValue(rv).DebugString() } + +// Double returns the float64 value for this element. +// It panics if e's BSON type is not bsontype.Double. +func (rv RawValue) Double() float64 { return convertToCoreValue(rv).Double() } + +// DoubleOK is the same as Double, but returns a boolean instead of panicking. +func (rv RawValue) DoubleOK() (float64, bool) { return convertToCoreValue(rv).DoubleOK() } + +// StringValue returns the string value for this element. +// It panics if e's BSON type is not bsontype.String. +// +// NOTE: This method is called StringValue to avoid a collision with the String method which +// implements the fmt.Stringer interface. +func (rv RawValue) StringValue() string { return convertToCoreValue(rv).StringValue() } + +// StringValueOK is the same as StringValue, but returns a boolean instead of +// panicking. +func (rv RawValue) StringValueOK() (string, bool) { return convertToCoreValue(rv).StringValueOK() } + +// Document returns the BSON document the Value represents as a Document. It panics if the +// value is a BSON type other than document. +func (rv RawValue) Document() Raw { return Raw(convertToCoreValue(rv).Document()) } + +// DocumentOK is the same as Document, except it returns a boolean +// instead of panicking. +func (rv RawValue) DocumentOK() (Raw, bool) { +	doc, ok := convertToCoreValue(rv).DocumentOK() +	return Raw(doc), ok +} + +// Array returns the BSON array the Value represents as an Array. It panics if the +// value is a BSON type other than array. +func (rv RawValue) Array() Raw { return Raw(convertToCoreValue(rv).Array()) } + +// ArrayOK is the same as Array, except it returns a boolean instead +// of panicking. +func (rv RawValue) ArrayOK() (Raw, bool) { +	doc, ok := convertToCoreValue(rv).ArrayOK() +	return Raw(doc), ok +} + +// Binary returns the BSON binary value the Value represents. It panics if the value is a BSON type +// other than binary. +func (rv RawValue) Binary() (subtype byte, data []byte) { return convertToCoreValue(rv).Binary() } + +// BinaryOK is the same as Binary, except it returns a boolean instead of +// panicking. +func (rv RawValue) BinaryOK() (subtype byte, data []byte, ok bool) { +	return convertToCoreValue(rv).BinaryOK() +} + +// ObjectID returns the BSON objectid value the Value represents. It panics if the value is a BSON +// type other than objectid. +func (rv RawValue) ObjectID() primitive.ObjectID { return convertToCoreValue(rv).ObjectID() } + +// ObjectIDOK is the same as ObjectID, except it returns a boolean instead of +// panicking. +func (rv RawValue) ObjectIDOK() (primitive.ObjectID, bool) { +	return convertToCoreValue(rv).ObjectIDOK() +} + +// Boolean returns the boolean value the Value represents. It panics if the +// value is a BSON type other than boolean. +func (rv RawValue) Boolean() bool { return convertToCoreValue(rv).Boolean() } + +// BooleanOK is the same as Boolean, except it returns a boolean instead of +// panicking. +func (rv RawValue) BooleanOK() (bool, bool) { return convertToCoreValue(rv).BooleanOK() } + +// DateTime returns the BSON datetime value the Value represents as a +// unix timestamp. It panics if the value is a BSON type other than datetime. +func (rv RawValue) DateTime() int64 { return convertToCoreValue(rv).DateTime() } + +// DateTimeOK is the same as DateTime, except it returns a boolean instead of +// panicking. +func (rv RawValue) DateTimeOK() (int64, bool) { return convertToCoreValue(rv).DateTimeOK() } + +// Time returns the BSON datetime value the Value represents. It panics if the value is a BSON +// type other than datetime. +func (rv RawValue) Time() time.Time { return convertToCoreValue(rv).Time() } + +// TimeOK is the same as Time, except it returns a boolean instead of +// panicking. +func (rv RawValue) TimeOK() (time.Time, bool) { return convertToCoreValue(rv).TimeOK() } + +// Regex returns the BSON regex value the Value represents. It panics if the value is a BSON +// type other than regex. +func (rv RawValue) Regex() (pattern, options string) { return convertToCoreValue(rv).Regex() } + +// RegexOK is the same as Regex, except it returns a boolean instead of +// panicking. +func (rv RawValue) RegexOK() (pattern, options string, ok bool) { +	return convertToCoreValue(rv).RegexOK() +} + +// DBPointer returns the BSON dbpointer value the Value represents. It panics if the value is a BSON +// type other than DBPointer. +func (rv RawValue) DBPointer() (string, primitive.ObjectID) { +	return convertToCoreValue(rv).DBPointer() +} + +// DBPointerOK is the same as DBPoitner, except that it returns a boolean +// instead of panicking. +func (rv RawValue) DBPointerOK() (string, primitive.ObjectID, bool) { +	return convertToCoreValue(rv).DBPointerOK() +} + +// JavaScript returns the BSON JavaScript code value the Value represents. It panics if the value is +// a BSON type other than JavaScript code. +func (rv RawValue) JavaScript() string { return convertToCoreValue(rv).JavaScript() } + +// JavaScriptOK is the same as Javascript, excepti that it returns a boolean +// instead of panicking. +func (rv RawValue) JavaScriptOK() (string, bool) { return convertToCoreValue(rv).JavaScriptOK() } + +// Symbol returns the BSON symbol value the Value represents. It panics if the value is a BSON +// type other than symbol. +func (rv RawValue) Symbol() string { return convertToCoreValue(rv).Symbol() } + +// SymbolOK is the same as Symbol, excepti that it returns a boolean +// instead of panicking. +func (rv RawValue) SymbolOK() (string, bool) { return convertToCoreValue(rv).SymbolOK() } + +// CodeWithScope returns the BSON JavaScript code with scope the Value represents. +// It panics if the value is a BSON type other than JavaScript code with scope. +func (rv RawValue) CodeWithScope() (string, Raw) { +	code, scope := convertToCoreValue(rv).CodeWithScope() +	return code, Raw(scope) +} + +// CodeWithScopeOK is the same as CodeWithScope, except that it returns a boolean instead of +// panicking. +func (rv RawValue) CodeWithScopeOK() (string, Raw, bool) { +	code, scope, ok := convertToCoreValue(rv).CodeWithScopeOK() +	return code, Raw(scope), ok +} + +// Int32 returns the int32 the Value represents. It panics if the value is a BSON type other than +// int32. +func (rv RawValue) Int32() int32 { return convertToCoreValue(rv).Int32() } + +// Int32OK is the same as Int32, except that it returns a boolean instead of +// panicking. +func (rv RawValue) Int32OK() (int32, bool) { return convertToCoreValue(rv).Int32OK() } + +// AsInt32 returns a BSON number as an int32. If the BSON type is not a numeric one, this method +// will panic. +func (rv RawValue) AsInt32() int32 { return convertToCoreValue(rv).AsInt32() } + +// AsInt32OK is the same as AsInt32, except that it returns a boolean instead of +// panicking. +func (rv RawValue) AsInt32OK() (int32, bool) { return convertToCoreValue(rv).AsInt32OK() } + +// Timestamp returns the BSON timestamp value the Value represents. It panics if the value is a +// BSON type other than timestamp. +func (rv RawValue) Timestamp() (t, i uint32) { return convertToCoreValue(rv).Timestamp() } + +// TimestampOK is the same as Timestamp, except that it returns a boolean +// instead of panicking. +func (rv RawValue) TimestampOK() (t, i uint32, ok bool) { return convertToCoreValue(rv).TimestampOK() } + +// Int64 returns the int64 the Value represents. It panics if the value is a BSON type other than +// int64. +func (rv RawValue) Int64() int64 { return convertToCoreValue(rv).Int64() } + +// Int64OK is the same as Int64, except that it returns a boolean instead of +// panicking. +func (rv RawValue) Int64OK() (int64, bool) { return convertToCoreValue(rv).Int64OK() } + +// AsInt64 returns a BSON number as an int64. If the BSON type is not a numeric one, this method +// will panic. +func (rv RawValue) AsInt64() int64 { return convertToCoreValue(rv).AsInt64() } + +// AsInt64OK is the same as AsInt64, except that it returns a boolean instead of +// panicking. +func (rv RawValue) AsInt64OK() (int64, bool) { return convertToCoreValue(rv).AsInt64OK() } + +// Decimal128 returns the decimal the Value represents. It panics if the value is a BSON type other than +// decimal. +func (rv RawValue) Decimal128() primitive.Decimal128 { return convertToCoreValue(rv).Decimal128() } + +// Decimal128OK is the same as Decimal128, except that it returns a boolean +// instead of panicking. +func (rv RawValue) Decimal128OK() (primitive.Decimal128, bool) { +	return convertToCoreValue(rv).Decimal128OK() +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/registry.go b/vendor/go.mongodb.org/mongo-driver/bson/registry.go new file mode 100644 index 000000000..16d7573e7 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/registry.go @@ -0,0 +1,24 @@ +// 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 bson + +import "go.mongodb.org/mongo-driver/bson/bsoncodec" + +// DefaultRegistry is the default bsoncodec.Registry. It contains the default codecs and the +// primitive codecs. +var DefaultRegistry = NewRegistryBuilder().Build() + +// NewRegistryBuilder creates a new RegistryBuilder configured with the default encoders and +// decoders 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) +	primitiveCodecs.RegisterPrimitiveCodecs(rb) +	return rb +} diff --git a/vendor/go.mongodb.org/mongo-driver/bson/types.go b/vendor/go.mongodb.org/mongo-driver/bson/types.go new file mode 100644 index 000000000..13a1c35cf --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/types.go @@ -0,0 +1,36 @@ +// 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 bson + +import ( +	"go.mongodb.org/mongo-driver/bson/bsontype" +) + +// These constants uniquely refer to each BSON type. +const ( +	TypeDouble           = bsontype.Double +	TypeString           = bsontype.String +	TypeEmbeddedDocument = bsontype.EmbeddedDocument +	TypeArray            = bsontype.Array +	TypeBinary           = bsontype.Binary +	TypeUndefined        = bsontype.Undefined +	TypeObjectID         = bsontype.ObjectID +	TypeBoolean          = bsontype.Boolean +	TypeDateTime         = bsontype.DateTime +	TypeNull             = bsontype.Null +	TypeRegex            = bsontype.Regex +	TypeDBPointer        = bsontype.DBPointer +	TypeJavaScript       = bsontype.JavaScript +	TypeSymbol           = bsontype.Symbol +	TypeCodeWithScope    = bsontype.CodeWithScope +	TypeInt32            = bsontype.Int32 +	TypeTimestamp        = bsontype.Timestamp +	TypeInt64            = bsontype.Int64 +	TypeDecimal128       = bsontype.Decimal128 +	TypeMinKey           = bsontype.MinKey +	TypeMaxKey           = bsontype.MaxKey +) diff --git a/vendor/go.mongodb.org/mongo-driver/bson/unmarshal.go b/vendor/go.mongodb.org/mongo-driver/bson/unmarshal.go new file mode 100644 index 000000000..f936ba183 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/bson/unmarshal.go @@ -0,0 +1,101 @@ +// 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 bson + +import ( +	"bytes" + +	"go.mongodb.org/mongo-driver/bson/bsoncodec" +	"go.mongodb.org/mongo-driver/bson/bsonrw" +	"go.mongodb.org/mongo-driver/bson/bsontype" +) + +// Unmarshaler is an interface implemented by types that can unmarshal a BSON +// document representation of themselves. The BSON bytes can be assumed to be +// valid. UnmarshalBSON must copy the BSON bytes if it wishes to retain the data +// after returning. +type Unmarshaler interface { +	UnmarshalBSON([]byte) error +} + +// ValueUnmarshaler is an interface implemented by types that can unmarshal a +// BSON value representation of themselves. The BSON bytes and type can be +// assumed to be valid. UnmarshalBSONValue must copy the BSON value bytes if it +// wishes to retain the data after returning. +type ValueUnmarshaler interface { +	UnmarshalBSONValue(bsontype.Type, []byte) error +} + +// Unmarshal parses the BSON-encoded data and stores the result in the value +// pointed to by val. If val is nil or not a pointer, Unmarshal returns +// InvalidUnmarshalError. +func Unmarshal(data []byte, val interface{}) error { +	return UnmarshalWithRegistry(DefaultRegistry, data, val) +} + +// UnmarshalWithRegistry parses the BSON-encoded data using Registry r and +// stores the result in the value pointed to by val. If val is nil or not +// a pointer, UnmarshalWithRegistry returns InvalidUnmarshalError. +func UnmarshalWithRegistry(r *bsoncodec.Registry, data []byte, val interface{}) error { +	vr := bsonrw.NewBSONDocumentReader(data) +	return unmarshalFromReader(bsoncodec.DecodeContext{Registry: r}, vr, val) +} + +// UnmarshalWithContext parses the BSON-encoded data using DecodeContext dc and +// stores the result in the value pointed to by val. If val is nil or not +// a pointer, UnmarshalWithRegistry returns InvalidUnmarshalError. +func UnmarshalWithContext(dc bsoncodec.DecodeContext, data []byte, val interface{}) error { +	vr := bsonrw.NewBSONDocumentReader(data) +	return unmarshalFromReader(dc, vr, val) +} + +// UnmarshalExtJSON parses the extended JSON-encoded data and stores the result +// in the value pointed to by val. If val is nil or not a pointer, Unmarshal +// returns InvalidUnmarshalError. +func UnmarshalExtJSON(data []byte, canonical bool, val interface{}) error { +	return UnmarshalExtJSONWithRegistry(DefaultRegistry, data, canonical, val) +} + +// UnmarshalExtJSONWithRegistry parses the extended JSON-encoded data using +// Registry r and stores the result in the value pointed to by val. If val is +// nil or not a pointer, UnmarshalWithRegistry returns InvalidUnmarshalError. +func UnmarshalExtJSONWithRegistry(r *bsoncodec.Registry, data []byte, canonical bool, val interface{}) error { +	ejvr, err := bsonrw.NewExtJSONValueReader(bytes.NewReader(data), canonical) +	if err != nil { +		return err +	} + +	return unmarshalFromReader(bsoncodec.DecodeContext{Registry: r}, ejvr, val) +} + +// UnmarshalExtJSONWithContext parses the extended JSON-encoded data using +// DecodeContext dc and stores the result in the value pointed to by val. If val is +// nil or not a pointer, UnmarshalWithRegistry returns InvalidUnmarshalError. +func UnmarshalExtJSONWithContext(dc bsoncodec.DecodeContext, data []byte, canonical bool, val interface{}) error { +	ejvr, err := bsonrw.NewExtJSONValueReader(bytes.NewReader(data), canonical) +	if err != nil { +		return err +	} + +	return unmarshalFromReader(dc, ejvr, val) +} + +func unmarshalFromReader(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader, val interface{}) error { +	dec := decPool.Get().(*Decoder) +	defer decPool.Put(dec) + +	err := dec.Reset(vr) +	if err != nil { +		return err +	} +	err = dec.SetContext(dc) +	if err != nil { +		return err +	} + +	return dec.Decode(val) +} diff --git a/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/array.go b/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/array.go new file mode 100644 index 000000000..8ea60ba3c --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/array.go @@ -0,0 +1,164 @@ +// 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 bsoncore + +import ( +	"bytes" +	"fmt" +	"io" +	"strconv" +) + +// NewArrayLengthError creates and returns an error for when the length of an array exceeds the +// bytes available. +func NewArrayLengthError(length, rem int) error { +	return lengthError("array", length, rem) +} + +// Array is a raw bytes representation of a BSON array. +type Array []byte + +// NewArrayFromReader reads an array from r. This function will only validate the length is +// correct and that the array ends with a null byte. +func NewArrayFromReader(r io.Reader) (Array, error) { +	return newBufferFromReader(r) +} + +// Index searches for and retrieves the value at the given index. This method will panic if +// the array is invalid or if the index is out of bounds. +func (a Array) Index(index uint) Value { +	value, err := a.IndexErr(index) +	if err != nil { +		panic(err) +	} +	return value +} + +// IndexErr searches for and retrieves the value at the given index. +func (a Array) IndexErr(index uint) (Value, error) { +	elem, err := indexErr(a, index) +	if err != nil { +		return Value{}, err +	} +	return elem.Value(), err +} + +// DebugString outputs a human readable version of Array. It will attempt to stringify the +// valid components of the array even if the entire array is not valid. +func (a Array) DebugString() string { +	if len(a) < 5 { +		return "<malformed>" +	} +	var buf bytes.Buffer +	buf.WriteString("Array") +	length, rem, _ := ReadLength(a) // We know we have enough bytes to read the length +	buf.WriteByte('(') +	buf.WriteString(strconv.Itoa(int(length))) +	length -= 4 +	buf.WriteString(")[") +	var elem Element +	var ok bool +	for length > 1 { +		elem, rem, ok = ReadElement(rem) +		length -= int32(len(elem)) +		if !ok { +			buf.WriteString(fmt.Sprintf("<malformed (%d)>", length)) +			break +		} +		fmt.Fprintf(&buf, "%s", elem.Value().DebugString()) +		if length != 1 { +			buf.WriteByte(',') +		} +	} +	buf.WriteByte(']') + +	return buf.String() +} + +// String outputs an ExtendedJSON version of Array. If the Array is not valid, this method +// returns an empty string. +func (a Array) String() string { +	if len(a) < 5 { +		return "" +	} +	var buf bytes.Buffer +	buf.WriteByte('[') + +	length, rem, _ := ReadLength(a) // We know we have enough bytes to read the length + +	length -= 4 + +	var elem Element +	var ok bool +	for length > 1 { +		elem, rem, ok = ReadElement(rem) +		length -= int32(len(elem)) +		if !ok { +			return "" +		} +		fmt.Fprintf(&buf, "%s", elem.Value().String()) +		if length > 1 { +			buf.WriteByte(',') +		} +	} +	if length != 1 { // Missing final null byte or inaccurate length +		return "" +	} + +	buf.WriteByte(']') +	return buf.String() +} + +// Values returns this array as a slice of values. The returned slice will contain valid values. +// If the array is not valid, the values up to the invalid point will be returned along with an +// error. +func (a Array) Values() ([]Value, error) { +	return values(a) +} + +// Validate validates the array and ensures the elements contained within are valid. +func (a Array) Validate() error { +	length, rem, ok := ReadLength(a) +	if !ok { +		return NewInsufficientBytesError(a, rem) +	} +	if int(length) > len(a) { +		return NewArrayLengthError(int(length), len(a)) +	} +	if a[length-1] != 0x00 { +		return ErrMissingNull +	} + +	length -= 4 +	var elem Element + +	var keyNum int64 +	for length > 1 { +		elem, rem, ok = ReadElement(rem) +		length -= int32(len(elem)) +		if !ok { +			return NewInsufficientBytesError(a, rem) +		} + +		// validate element +		err := elem.Validate() +		if err != nil { +			return err +		} + +		// validate keys increase numerically +		if fmt.Sprint(keyNum) != elem.Key() { +			return fmt.Errorf("array key %q is out of order or invalid", elem.Key()) +		} +		keyNum++ +	} + +	if len(rem) < 1 || rem[0] != 0x00 { +		return ErrMissingNull +	} +	return nil +} diff --git a/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/bson_arraybuilder.go b/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/bson_arraybuilder.go new file mode 100644 index 000000000..7e6937d89 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/bson_arraybuilder.go @@ -0,0 +1,201 @@ +// 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 bsoncore + +import ( +	"strconv" + +	"go.mongodb.org/mongo-driver/bson/bsontype" +	"go.mongodb.org/mongo-driver/bson/primitive" +) + +// ArrayBuilder builds a bson array +type ArrayBuilder struct { +	arr     []byte +	indexes []int32 +	keys    []int +} + +// NewArrayBuilder creates a new ArrayBuilder +func NewArrayBuilder() *ArrayBuilder { +	return (&ArrayBuilder{}).startArray() +} + +// startArray reserves the array's length and sets the index to where the length begins +func (a *ArrayBuilder) startArray() *ArrayBuilder { +	var index int32 +	index, a.arr = AppendArrayStart(a.arr) +	a.indexes = append(a.indexes, index) +	a.keys = append(a.keys, 0) +	return a +} + +// Build updates the length of the array and index to the beginning of the documents length +// bytes, then returns the array (bson bytes) +func (a *ArrayBuilder) Build() Array { +	lastIndex := len(a.indexes) - 1 +	lastKey := len(a.keys) - 1 +	a.arr, _ = AppendArrayEnd(a.arr, a.indexes[lastIndex]) +	a.indexes = a.indexes[:lastIndex] +	a.keys = a.keys[:lastKey] +	return a.arr +} + +// incrementKey() increments the value keys and returns the key to be used to a.appendArray* functions +func (a *ArrayBuilder) incrementKey() string { +	idx := len(a.keys) - 1 +	key := strconv.Itoa(a.keys[idx]) +	a.keys[idx]++ +	return key +} + +// AppendInt32 will append i32 to ArrayBuilder.arr +func (a *ArrayBuilder) AppendInt32(i32 int32) *ArrayBuilder { +	a.arr = AppendInt32Element(a.arr, a.incrementKey(), i32) +	return a +} + +// AppendDocument will append doc to ArrayBuilder.arr +func (a *ArrayBuilder) AppendDocument(doc []byte) *ArrayBuilder { +	a.arr = AppendDocumentElement(a.arr, a.incrementKey(), doc) +	return a +} + +// AppendArray will append arr to ArrayBuilder.arr +func (a *ArrayBuilder) AppendArray(arr []byte) *ArrayBuilder { +	a.arr = AppendArrayElement(a.arr, a.incrementKey(), arr) +	return a +} + +// AppendDouble will append f to ArrayBuilder.doc +func (a *ArrayBuilder) AppendDouble(f float64) *ArrayBuilder { +	a.arr = AppendDoubleElement(a.arr, a.incrementKey(), f) +	return a +} + +// AppendString will append str to ArrayBuilder.doc +func (a *ArrayBuilder) AppendString(str string) *ArrayBuilder { +	a.arr = AppendStringElement(a.arr, a.incrementKey(), str) +	return a +} + +// AppendObjectID will append oid to ArrayBuilder.doc +func (a *ArrayBuilder) AppendObjectID(oid primitive.ObjectID) *ArrayBuilder { +	a.arr = AppendObjectIDElement(a.arr, a.incrementKey(), oid) +	return a +} + +// AppendBinary will append a BSON binary element using subtype, and +// b to a.arr +func (a *ArrayBuilder) AppendBinary(subtype byte, b []byte) *ArrayBuilder { +	a.arr = AppendBinaryElement(a.arr, a.incrementKey(), subtype, b) +	return a +} + +// AppendUndefined will append a BSON undefined element using key to a.arr +func (a *ArrayBuilder) AppendUndefined() *ArrayBuilder { +	a.arr = AppendUndefinedElement(a.arr, a.incrementKey()) +	return a +} + +// AppendBoolean will append a boolean element using b to a.arr +func (a *ArrayBuilder) AppendBoolean(b bool) *ArrayBuilder { +	a.arr = AppendBooleanElement(a.arr, a.incrementKey(), b) +	return a +} + +// AppendDateTime will append datetime element dt to a.arr +func (a *ArrayBuilder) AppendDateTime(dt int64) *ArrayBuilder { +	a.arr = AppendDateTimeElement(a.arr, a.incrementKey(), dt) +	return a +} + +// AppendNull will append a null element to a.arr +func (a *ArrayBuilder) AppendNull() *ArrayBuilder { +	a.arr = AppendNullElement(a.arr, a.incrementKey()) +	return a +} + +// AppendRegex will append pattern and options to a.arr +func (a *ArrayBuilder) AppendRegex(pattern, options string) *ArrayBuilder { +	a.arr = AppendRegexElement(a.arr, a.incrementKey(), pattern, options) +	return a +} + +// AppendDBPointer will append ns and oid to a.arr +func (a *ArrayBuilder) AppendDBPointer(ns string, oid primitive.ObjectID) *ArrayBuilder { +	a.arr = AppendDBPointerElement(a.arr, a.incrementKey(), ns, oid) +	return a +} + +// AppendJavaScript will append js to a.arr +func (a *ArrayBuilder) AppendJavaScript(js string) *ArrayBuilder { +	a.arr = AppendJavaScriptElement(a.arr, a.incrementKey(), js) +	return a +} + +// AppendSymbol will append symbol to a.arr +func (a *ArrayBuilder) AppendSymbol(symbol string) *ArrayBuilder { +	a.arr = AppendSymbolElement(a.arr, a.incrementKey(), symbol) +	return a +} + +// AppendCodeWithScope will append code and scope to a.arr +func (a *ArrayBuilder) AppendCodeWithScope(code string, scope Document) *ArrayBuilder { +	a.arr = AppendCodeWithScopeElement(a.arr, a.incrementKey(), code, scope) +	return a +} + +// AppendTimestamp will append t and i to a.arr +func (a *ArrayBuilder) AppendTimestamp(t, i uint32) *ArrayBuilder { +	a.arr = AppendTimestampElement(a.arr, a.incrementKey(), t, i) +	return a +} + +// AppendInt64 will append i64 to a.arr +func (a *ArrayBuilder) AppendInt64(i64 int64) *ArrayBuilder { +	a.arr = AppendInt64Element(a.arr, a.incrementKey(), i64) +	return a +} + +// AppendDecimal128 will append d128 to a.arr +func (a *ArrayBuilder) AppendDecimal128(d128 primitive.Decimal128) *ArrayBuilder { +	a.arr = AppendDecimal128Element(a.arr, a.incrementKey(), d128) +	return a +} + +// AppendMaxKey will append a max key element to a.arr +func (a *ArrayBuilder) AppendMaxKey() *ArrayBuilder { +	a.arr = AppendMaxKeyElement(a.arr, a.incrementKey()) +	return a +} + +// AppendMinKey will append a min key element to a.arr +func (a *ArrayBuilder) AppendMinKey() *ArrayBuilder { +	a.arr = AppendMinKeyElement(a.arr, a.incrementKey()) +	return a +} + +// AppendValue appends a BSON value to the array. +func (a *ArrayBuilder) AppendValue(val Value) *ArrayBuilder { +	a.arr = AppendValueElement(a.arr, a.incrementKey(), val) +	return a +} + +// StartArray starts building an inline Array. After this document is completed, +// the user must call a.FinishArray +func (a *ArrayBuilder) StartArray() *ArrayBuilder { +	a.arr = AppendHeader(a.arr, bsontype.Array, a.incrementKey()) +	a.startArray() +	return a +} + +// FinishArray builds the most recent array created +func (a *ArrayBuilder) FinishArray() *ArrayBuilder { +	a.arr = a.Build() +	return a +} diff --git a/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/bson_documentbuilder.go b/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/bson_documentbuilder.go new file mode 100644 index 000000000..52162f8aa --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/bson_documentbuilder.go @@ -0,0 +1,189 @@ +// 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 bsoncore + +import ( +	"go.mongodb.org/mongo-driver/bson/bsontype" +	"go.mongodb.org/mongo-driver/bson/primitive" +) + +// DocumentBuilder builds a bson document +type DocumentBuilder struct { +	doc     []byte +	indexes []int32 +} + +// startDocument reserves the document's length and set the index to where the length begins +func (db *DocumentBuilder) startDocument() *DocumentBuilder { +	var index int32 +	index, db.doc = AppendDocumentStart(db.doc) +	db.indexes = append(db.indexes, index) +	return db +} + +// NewDocumentBuilder creates a new DocumentBuilder +func NewDocumentBuilder() *DocumentBuilder { +	return (&DocumentBuilder{}).startDocument() +} + +// Build updates the length of the document and index to the beginning of the documents length +// bytes, then returns the document (bson bytes) +func (db *DocumentBuilder) Build() Document { +	last := len(db.indexes) - 1 +	db.doc, _ = AppendDocumentEnd(db.doc, db.indexes[last]) +	db.indexes = db.indexes[:last] +	return db.doc +} + +// AppendInt32 will append an int32 element using key and i32 to DocumentBuilder.doc +func (db *DocumentBuilder) AppendInt32(key string, i32 int32) *DocumentBuilder { +	db.doc = AppendInt32Element(db.doc, key, i32) +	return db +} + +// AppendDocument will append a bson embedded document element using key +// and doc to DocumentBuilder.doc +func (db *DocumentBuilder) AppendDocument(key string, doc []byte) *DocumentBuilder { +	db.doc = AppendDocumentElement(db.doc, key, doc) +	return db +} + +// AppendArray will append a bson array using key and arr to DocumentBuilder.doc +func (db *DocumentBuilder) AppendArray(key string, arr []byte) *DocumentBuilder { +	db.doc = AppendHeader(db.doc, bsontype.Array, key) +	db.doc = AppendArray(db.doc, arr) +	return db +} + +// AppendDouble will append a double element using key and f to DocumentBuilder.doc +func (db *DocumentBuilder) AppendDouble(key string, f float64) *DocumentBuilder { +	db.doc = AppendDoubleElement(db.doc, key, f) +	return db +} + +// AppendString will append str to DocumentBuilder.doc with the given key +func (db *DocumentBuilder) AppendString(key string, str string) *DocumentBuilder { +	db.doc = AppendStringElement(db.doc, key, str) +	return db +} + +// AppendObjectID will append oid to DocumentBuilder.doc with the given key +func (db *DocumentBuilder) AppendObjectID(key string, oid primitive.ObjectID) *DocumentBuilder { +	db.doc = AppendObjectIDElement(db.doc, key, oid) +	return db +} + +// AppendBinary will append a BSON binary element using key, subtype, and +// b to db.doc +func (db *DocumentBuilder) AppendBinary(key string, subtype byte, b []byte) *DocumentBuilder { +	db.doc = AppendBinaryElement(db.doc, key, subtype, b) +	return db +} + +// AppendUndefined will append a BSON undefined element using key to db.doc +func (db *DocumentBuilder) AppendUndefined(key string) *DocumentBuilder { +	db.doc = AppendUndefinedElement(db.doc, key) +	return db +} + +// AppendBoolean will append a boolean element using key and b to db.doc +func (db *DocumentBuilder) AppendBoolean(key string, b bool) *DocumentBuilder { +	db.doc = AppendBooleanElement(db.doc, key, b) +	return db +} + +// AppendDateTime will append a datetime element using key and dt to db.doc +func (db *DocumentBuilder) AppendDateTime(key string, dt int64) *DocumentBuilder { +	db.doc = AppendDateTimeElement(db.doc, key, dt) +	return db +} + +// AppendNull will append a null element using key to db.doc +func (db *DocumentBuilder) AppendNull(key string) *DocumentBuilder { +	db.doc = AppendNullElement(db.doc, key) +	return db +} + +// AppendRegex will append pattern and options using key to db.doc +func (db *DocumentBuilder) AppendRegex(key, pattern, options string) *DocumentBuilder { +	db.doc = AppendRegexElement(db.doc, key, pattern, options) +	return db +} + +// AppendDBPointer will append ns and oid to using key to db.doc +func (db *DocumentBuilder) AppendDBPointer(key string, ns string, oid primitive.ObjectID) *DocumentBuilder { +	db.doc = AppendDBPointerElement(db.doc, key, ns, oid) +	return db +} + +// AppendJavaScript will append js using the provided key to db.doc +func (db *DocumentBuilder) AppendJavaScript(key, js string) *DocumentBuilder { +	db.doc = AppendJavaScriptElement(db.doc, key, js) +	return db +} + +// AppendSymbol will append a BSON symbol element using key and symbol db.doc +func (db *DocumentBuilder) AppendSymbol(key, symbol string) *DocumentBuilder { +	db.doc = AppendSymbolElement(db.doc, key, symbol) +	return db +} + +// AppendCodeWithScope will append code and scope using key to db.doc +func (db *DocumentBuilder) AppendCodeWithScope(key string, code string, scope Document) *DocumentBuilder { +	db.doc = AppendCodeWithScopeElement(db.doc, key, code, scope) +	return db +} + +// AppendTimestamp will append t and i to db.doc using provided key +func (db *DocumentBuilder) AppendTimestamp(key string, t, i uint32) *DocumentBuilder { +	db.doc = AppendTimestampElement(db.doc, key, t, i) +	return db +} + +// AppendInt64 will append i64 to dst using key to db.doc +func (db *DocumentBuilder) AppendInt64(key string, i64 int64) *DocumentBuilder { +	db.doc = AppendInt64Element(db.doc, key, i64) +	return db +} + +// AppendDecimal128 will append d128 to db.doc using provided key +func (db *DocumentBuilder) AppendDecimal128(key string, d128 primitive.Decimal128) *DocumentBuilder { +	db.doc = AppendDecimal128Element(db.doc, key, d128) +	return db +} + +// AppendMaxKey will append a max key element using key to db.doc +func (db *DocumentBuilder) AppendMaxKey(key string) *DocumentBuilder { +	db.doc = AppendMaxKeyElement(db.doc, key) +	return db +} + +// AppendMinKey will append a min key element using key to db.doc +func (db *DocumentBuilder) AppendMinKey(key string) *DocumentBuilder { +	db.doc = AppendMinKeyElement(db.doc, key) +	return db +} + +// AppendValue will append a BSON element with the provided key and value to the document. +func (db *DocumentBuilder) AppendValue(key string, val Value) *DocumentBuilder { +	db.doc = AppendValueElement(db.doc, key, val) +	return db +} + +// StartDocument starts building an inline document element with the provided key +// After this document is completed, the user must call finishDocument +func (db *DocumentBuilder) StartDocument(key string) *DocumentBuilder { +	db.doc = AppendHeader(db.doc, bsontype.EmbeddedDocument, key) +	db = db.startDocument() +	return db +} + +// FinishDocument builds the most recent document created +func (db *DocumentBuilder) FinishDocument() *DocumentBuilder { +	db.doc = db.Build() +	return db +} diff --git a/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/bsoncore.go b/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/bsoncore.go new file mode 100644 index 000000000..17aad6d71 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/bsoncore.go @@ -0,0 +1,862 @@ +// 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 bsoncore contains functions that can be used to encode and decode BSON +// elements and values to or from a slice of bytes. These functions are aimed at +// allowing low level manipulation of BSON and can be used to build a higher +// level BSON library. +// +// The Read* functions within this package return the values of the element and +// a boolean indicating if the values are valid. A boolean was used instead of +// an error because any error that would be returned would be the same: not +// enough bytes. This library attempts to do no validation, it will only return +// false if there are not enough bytes for an item to be read. For example, the +// ReadDocument function checks the length, if that length is larger than the +// number of bytes available, it will return false, if there are enough bytes, it +// will return those bytes and true. It is the consumers responsibility to +// validate those bytes. +// +// The Append* functions within this package will append the type value to the +// given dst slice. If the slice has enough capacity, it will not grow the +// slice. The Append*Element functions within this package operate in the same +// way, but additionally append the BSON type and the key before the value. +package bsoncore // import "go.mongodb.org/mongo-driver/x/bsonx/bsoncore" + +import ( +	"bytes" +	"fmt" +	"math" +	"strconv" +	"strings" +	"time" + +	"go.mongodb.org/mongo-driver/bson/bsontype" +	"go.mongodb.org/mongo-driver/bson/primitive" +) + +const ( +	// EmptyDocumentLength is the length of a document that has been started/ended but has no elements. +	EmptyDocumentLength = 5 +	// nullTerminator is a string version of the 0 byte that is appended at the end of cstrings. +	nullTerminator       = string(byte(0)) +	invalidKeyPanicMsg   = "BSON element keys cannot contain null bytes" +	invalidRegexPanicMsg = "BSON regex values cannot contain null bytes" +) + +// AppendType will append t to dst and return the extended buffer. +func AppendType(dst []byte, t bsontype.Type) []byte { return append(dst, byte(t)) } + +// AppendKey will append key to dst and return the extended buffer. +func AppendKey(dst []byte, key string) []byte { return append(dst, key+nullTerminator...) } + +// AppendHeader will append Type t and key to dst and return the extended +// buffer. +func AppendHeader(dst []byte, t bsontype.Type, key string) []byte { +	if !isValidCString(key) { +		panic(invalidKeyPanicMsg) +	} + +	dst = AppendType(dst, t) +	dst = append(dst, key...) +	return append(dst, 0x00) +	// return append(AppendType(dst, t), key+string(0x00)...) +} + +// TODO(skriptble): All of the Read* functions should return src resliced to start just after what was read. + +// ReadType will return the first byte of the provided []byte as a type. If +// there is no available byte, false is returned. +func ReadType(src []byte) (bsontype.Type, []byte, bool) { +	if len(src) < 1 { +		return 0, src, false +	} +	return bsontype.Type(src[0]), src[1:], true +} + +// ReadKey will read a key from src. The 0x00 byte will not be present +// in the returned string. If there are not enough bytes available, false is +// returned. +func ReadKey(src []byte) (string, []byte, bool) { return readcstring(src) } + +// ReadKeyBytes will read a key from src as bytes. The 0x00 byte will +// not be present in the returned string. If there are not enough bytes +// available, false is returned. +func ReadKeyBytes(src []byte) ([]byte, []byte, bool) { return readcstringbytes(src) } + +// ReadHeader will read a type byte and a key from src. If both of these +// values cannot be read, false is returned. +func ReadHeader(src []byte) (t bsontype.Type, key string, rem []byte, ok bool) { +	t, rem, ok = ReadType(src) +	if !ok { +		return 0, "", src, false +	} +	key, rem, ok = ReadKey(rem) +	if !ok { +		return 0, "", src, false +	} + +	return t, key, rem, true +} + +// ReadHeaderBytes will read a type and a key from src and the remainder of the bytes +// are returned as rem. If either the type or key cannot be red, ok will be false. +func ReadHeaderBytes(src []byte) (header []byte, rem []byte, ok bool) { +	if len(src) < 1 { +		return nil, src, false +	} +	idx := bytes.IndexByte(src[1:], 0x00) +	if idx == -1 { +		return nil, src, false +	} +	return src[:idx], src[idx+1:], true +} + +// ReadElement reads the next full element from src. It returns the element, the remaining bytes in +// the slice, and a boolean indicating if the read was successful. +func ReadElement(src []byte) (Element, []byte, bool) { +	if len(src) < 1 { +		return nil, src, false +	} +	t := bsontype.Type(src[0]) +	idx := bytes.IndexByte(src[1:], 0x00) +	if idx == -1 { +		return nil, src, false +	} +	length, ok := valueLength(src[idx+2:], t) // We add 2 here because we called IndexByte with src[1:] +	if !ok { +		return nil, src, false +	} +	elemLength := 1 + idx + 1 + int(length) +	if elemLength > len(src) { +		return nil, src, false +	} +	if elemLength < 0 { +		return nil, src, false +	} +	return src[:elemLength], src[elemLength:], true +} + +// AppendValueElement appends value to dst as an element using key as the element's key. +func AppendValueElement(dst []byte, key string, value Value) []byte { +	dst = AppendHeader(dst, value.Type, key) +	dst = append(dst, value.Data...) +	return dst +} + +// ReadValue reads the next value as the provided types and returns a Value, the remaining bytes, +// and a boolean indicating if the read was successful. +func ReadValue(src []byte, t bsontype.Type) (Value, []byte, bool) { +	data, rem, ok := readValue(src, t) +	if !ok { +		return Value{}, src, false +	} +	return Value{Type: t, Data: data}, rem, true +} + +// AppendDouble will append f to dst and return the extended buffer. +func AppendDouble(dst []byte, f float64) []byte { +	return appendu64(dst, math.Float64bits(f)) +} + +// AppendDoubleElement will append a BSON double element using key and f to dst +// and return the extended buffer. +func AppendDoubleElement(dst []byte, key string, f float64) []byte { +	return AppendDouble(AppendHeader(dst, bsontype.Double, key), f) +} + +// ReadDouble will read a float64 from src. If there are not enough bytes it +// will return false. +func ReadDouble(src []byte) (float64, []byte, bool) { +	bits, src, ok := readu64(src) +	if !ok { +		return 0, src, false +	} +	return math.Float64frombits(bits), src, true +} + +// AppendString will append s to dst and return the extended buffer. +func AppendString(dst []byte, s string) []byte { +	return appendstring(dst, s) +} + +// AppendStringElement will append a BSON string element using key and val to dst +// and return the extended buffer. +func AppendStringElement(dst []byte, key, val string) []byte { +	return AppendString(AppendHeader(dst, bsontype.String, key), val) +} + +// ReadString will read a string from src. If there are not enough bytes it +// will return false. +func ReadString(src []byte) (string, []byte, bool) { +	return readstring(src) +} + +// AppendDocumentStart reserves a document's length and returns the index where the length begins. +// This index can later be used to write the length of the document. +func AppendDocumentStart(dst []byte) (index int32, b []byte) { +	// TODO(skriptble): We really need AppendDocumentStart and AppendDocumentEnd.  AppendDocumentStart would handle calling +	// TODO ReserveLength and providing the index of the start of the document. AppendDocumentEnd would handle taking that +	// TODO start index, adding the null byte, calculating the length, and filling in the length at the start of the +	// TODO document. +	return ReserveLength(dst) +} + +// AppendDocumentStartInline functions the same as AppendDocumentStart but takes a pointer to the +// index int32 which allows this function to be used inline. +func AppendDocumentStartInline(dst []byte, index *int32) []byte { +	idx, doc := AppendDocumentStart(dst) +	*index = idx +	return doc +} + +// AppendDocumentElementStart writes a document element header and then reserves the length bytes. +func AppendDocumentElementStart(dst []byte, key string) (index int32, b []byte) { +	return AppendDocumentStart(AppendHeader(dst, bsontype.EmbeddedDocument, key)) +} + +// AppendDocumentEnd writes the null byte for a document and updates the length of the document. +// The index should be the beginning of the document's length bytes. +func AppendDocumentEnd(dst []byte, index int32) ([]byte, error) { +	if int(index) > len(dst)-4 { +		return dst, fmt.Errorf("not enough bytes available after index to write length") +	} +	dst = append(dst, 0x00) +	dst = UpdateLength(dst, index, int32(len(dst[index:]))) +	return dst, nil +} + +// AppendDocument will append doc to dst and return the extended buffer. +func AppendDocument(dst []byte, doc []byte) []byte { return append(dst, doc...) } + +// AppendDocumentElement will append a BSON embedded document element using key +// and doc to dst and return the extended buffer. +func AppendDocumentElement(dst []byte, key string, doc []byte) []byte { +	return AppendDocument(AppendHeader(dst, bsontype.EmbeddedDocument, key), doc) +} + +// BuildDocument will create a document with the given slice of elements and will append +// it to dst and return the extended buffer. +func BuildDocument(dst []byte, elems ...[]byte) []byte { +	idx, dst := ReserveLength(dst) +	for _, elem := range elems { +		dst = append(dst, elem...) +	} +	dst = append(dst, 0x00) +	dst = UpdateLength(dst, idx, int32(len(dst[idx:]))) +	return dst +} + +// BuildDocumentValue creates an Embedded Document value from the given elements. +func BuildDocumentValue(elems ...[]byte) Value { +	return Value{Type: bsontype.EmbeddedDocument, Data: BuildDocument(nil, elems...)} +} + +// BuildDocumentElement will append a BSON embedded document elemnt using key and the provided +// elements and return the extended buffer. +func BuildDocumentElement(dst []byte, key string, elems ...[]byte) []byte { +	return BuildDocument(AppendHeader(dst, bsontype.EmbeddedDocument, key), elems...) +} + +// BuildDocumentFromElements is an alaias for the BuildDocument function. +var BuildDocumentFromElements = BuildDocument + +// ReadDocument will read a document from src. If there are not enough bytes it +// will return false. +func ReadDocument(src []byte) (doc Document, rem []byte, ok bool) { return readLengthBytes(src) } + +// AppendArrayStart appends the length bytes to an array and then returns the index of the start +// of those length bytes. +func AppendArrayStart(dst []byte) (index int32, b []byte) { return ReserveLength(dst) } + +// AppendArrayElementStart appends an array element header and then the length bytes for an array, +// returning the index where the length starts. +func AppendArrayElementStart(dst []byte, key string) (index int32, b []byte) { +	return AppendArrayStart(AppendHeader(dst, bsontype.Array, key)) +} + +// AppendArrayEnd appends the null byte to an array and calculates the length, inserting that +// calculated length starting at index. +func AppendArrayEnd(dst []byte, index int32) ([]byte, error) { return AppendDocumentEnd(dst, index) } + +// AppendArray will append arr to dst and return the extended buffer. +func AppendArray(dst []byte, arr []byte) []byte { return append(dst, arr...) } + +// AppendArrayElement will append a BSON array element using key and arr to dst +// and return the extended buffer. +func AppendArrayElement(dst []byte, key string, arr []byte) []byte { +	return AppendArray(AppendHeader(dst, bsontype.Array, key), arr) +} + +// BuildArray will append a BSON array to dst built from values. +func BuildArray(dst []byte, values ...Value) []byte { +	idx, dst := ReserveLength(dst) +	for pos, val := range values { +		dst = AppendValueElement(dst, strconv.Itoa(pos), val) +	} +	dst = append(dst, 0x00) +	dst = UpdateLength(dst, idx, int32(len(dst[idx:]))) +	return dst +} + +// BuildArrayElement will create an array element using the provided values. +func BuildArrayElement(dst []byte, key string, values ...Value) []byte { +	return BuildArray(AppendHeader(dst, bsontype.Array, key), values...) +} + +// ReadArray will read an array from src. If there are not enough bytes it +// will return false. +func ReadArray(src []byte) (arr Array, rem []byte, ok bool) { return readLengthBytes(src) } + +// AppendBinary will append subtype and b to dst and return the extended buffer. +func AppendBinary(dst []byte, subtype byte, b []byte) []byte { +	if subtype == 0x02 { +		return appendBinarySubtype2(dst, subtype, b) +	} +	dst = append(appendLength(dst, int32(len(b))), subtype) +	return append(dst, b...) +} + +// AppendBinaryElement will append a BSON binary element using key, subtype, and +// b to dst and return the extended buffer. +func AppendBinaryElement(dst []byte, key string, subtype byte, b []byte) []byte { +	return AppendBinary(AppendHeader(dst, bsontype.Binary, key), subtype, b) +} + +// ReadBinary will read a subtype and bin from src. If there are not enough bytes it +// will return false. +func ReadBinary(src []byte) (subtype byte, bin []byte, rem []byte, ok bool) { +	length, rem, ok := ReadLength(src) +	if !ok { +		return 0x00, nil, src, false +	} +	if len(rem) < 1 { // subtype +		return 0x00, nil, src, false +	} +	subtype, rem = rem[0], rem[1:] + +	if len(rem) < int(length) { +		return 0x00, nil, src, false +	} + +	if subtype == 0x02 { +		length, rem, ok = ReadLength(rem) +		if !ok || len(rem) < int(length) { +			return 0x00, nil, src, false +		} +	} + +	return subtype, rem[:length], rem[length:], true +} + +// AppendUndefinedElement will append a BSON undefined element using key to dst +// and return the extended buffer. +func AppendUndefinedElement(dst []byte, key string) []byte { +	return AppendHeader(dst, bsontype.Undefined, key) +} + +// AppendObjectID will append oid to dst and return the extended buffer. +func AppendObjectID(dst []byte, oid primitive.ObjectID) []byte { return append(dst, oid[:]...) } + +// AppendObjectIDElement will append a BSON ObjectID element using key and oid to dst +// and return the extended buffer. +func AppendObjectIDElement(dst []byte, key string, oid primitive.ObjectID) []byte { +	return AppendObjectID(AppendHeader(dst, bsontype.ObjectID, key), oid) +} + +// ReadObjectID will read an ObjectID from src. If there are not enough bytes it +// will return false. +func ReadObjectID(src []byte) (primitive.ObjectID, []byte, bool) { +	if len(src) < 12 { +		return primitive.ObjectID{}, src, false +	} +	var oid primitive.ObjectID +	copy(oid[:], src[0:12]) +	return oid, src[12:], true +} + +// AppendBoolean will append b to dst and return the extended buffer. +func AppendBoolean(dst []byte, b bool) []byte { +	if b { +		return append(dst, 0x01) +	} +	return append(dst, 0x00) +} + +// AppendBooleanElement will append a BSON boolean element using key and b to dst +// and return the extended buffer. +func AppendBooleanElement(dst []byte, key string, b bool) []byte { +	return AppendBoolean(AppendHeader(dst, bsontype.Boolean, key), b) +} + +// ReadBoolean will read a bool from src. If there are not enough bytes it +// will return false. +func ReadBoolean(src []byte) (bool, []byte, bool) { +	if len(src) < 1 { +		return false, src, false +	} + +	return src[0] == 0x01, src[1:], true +} + +// AppendDateTime will append dt to dst and return the extended buffer. +func AppendDateTime(dst []byte, dt int64) []byte { return appendi64(dst, dt) } + +// AppendDateTimeElement will append a BSON datetime element using key and dt to dst +// and return the extended buffer. +func AppendDateTimeElement(dst []byte, key string, dt int64) []byte { +	return AppendDateTime(AppendHeader(dst, bsontype.DateTime, key), dt) +} + +// ReadDateTime will read an int64 datetime from src. If there are not enough bytes it +// will return false. +func ReadDateTime(src []byte) (int64, []byte, bool) { return readi64(src) } + +// AppendTime will append time as a BSON DateTime to dst and return the extended buffer. +func AppendTime(dst []byte, t time.Time) []byte { +	return AppendDateTime(dst, t.Unix()*1000+int64(t.Nanosecond()/1e6)) +} + +// AppendTimeElement will append a BSON datetime element using key and dt to dst +// and return the extended buffer. +func AppendTimeElement(dst []byte, key string, t time.Time) []byte { +	return AppendTime(AppendHeader(dst, bsontype.DateTime, key), t) +} + +// ReadTime will read an time.Time datetime from src. If there are not enough bytes it +// will return false. +func ReadTime(src []byte) (time.Time, []byte, bool) { +	dt, rem, ok := readi64(src) +	return time.Unix(dt/1e3, dt%1e3*1e6), rem, ok +} + +// AppendNullElement will append a BSON null element using key to dst +// and return the extended buffer. +func AppendNullElement(dst []byte, key string) []byte { return AppendHeader(dst, bsontype.Null, key) } + +// AppendRegex will append pattern and options to dst and return the extended buffer. +func AppendRegex(dst []byte, pattern, options string) []byte { +	if !isValidCString(pattern) || !isValidCString(options) { +		panic(invalidRegexPanicMsg) +	} + +	return append(dst, pattern+nullTerminator+options+nullTerminator...) +} + +// AppendRegexElement will append a BSON regex element using key, pattern, and +// options to dst and return the extended buffer. +func AppendRegexElement(dst []byte, key, pattern, options string) []byte { +	return AppendRegex(AppendHeader(dst, bsontype.Regex, key), pattern, options) +} + +// ReadRegex will read a pattern and options from src. If there are not enough bytes it +// will return false. +func ReadRegex(src []byte) (pattern, options string, rem []byte, ok bool) { +	pattern, rem, ok = readcstring(src) +	if !ok { +		return "", "", src, false +	} +	options, rem, ok = readcstring(rem) +	if !ok { +		return "", "", src, false +	} +	return pattern, options, rem, true +} + +// AppendDBPointer will append ns and oid to dst and return the extended buffer. +func AppendDBPointer(dst []byte, ns string, oid primitive.ObjectID) []byte { +	return append(appendstring(dst, ns), oid[:]...) +} + +// AppendDBPointerElement will append a BSON DBPointer element using key, ns, +// and oid to dst and return the extended buffer. +func AppendDBPointerElement(dst []byte, key, ns string, oid primitive.ObjectID) []byte { +	return AppendDBPointer(AppendHeader(dst, bsontype.DBPointer, key), ns, oid) +} + +// ReadDBPointer will read a ns and oid from src. If there are not enough bytes it +// will return false. +func ReadDBPointer(src []byte) (ns string, oid primitive.ObjectID, rem []byte, ok bool) { +	ns, rem, ok = readstring(src) +	if !ok { +		return "", primitive.ObjectID{}, src, false +	} +	oid, rem, ok = ReadObjectID(rem) +	if !ok { +		return "", primitive.ObjectID{}, src, false +	} +	return ns, oid, rem, true +} + +// AppendJavaScript will append js to dst and return the extended buffer. +func AppendJavaScript(dst []byte, js string) []byte { return appendstring(dst, js) } + +// AppendJavaScriptElement will append a BSON JavaScript element using key and +// js to dst and return the extended buffer. +func AppendJavaScriptElement(dst []byte, key, js string) []byte { +	return AppendJavaScript(AppendHeader(dst, bsontype.JavaScript, key), js) +} + +// ReadJavaScript will read a js string from src. If there are not enough bytes it +// will return false. +func ReadJavaScript(src []byte) (js string, rem []byte, ok bool) { return readstring(src) } + +// AppendSymbol will append symbol to dst and return the extended buffer. +func AppendSymbol(dst []byte, symbol string) []byte { return appendstring(dst, symbol) } + +// AppendSymbolElement will append a BSON symbol element using key and symbol to dst +// and return the extended buffer. +func AppendSymbolElement(dst []byte, key, symbol string) []byte { +	return AppendSymbol(AppendHeader(dst, bsontype.Symbol, key), symbol) +} + +// ReadSymbol will read a symbol string from src. If there are not enough bytes it +// will return false. +func ReadSymbol(src []byte) (symbol string, rem []byte, ok bool) { return readstring(src) } + +// AppendCodeWithScope will append code and scope to dst and return the extended buffer. +func AppendCodeWithScope(dst []byte, code string, scope []byte) []byte { +	length := int32(4 + 4 + len(code) + 1 + len(scope)) // length of cws, length of code, code, 0x00, scope +	dst = appendLength(dst, length) + +	return append(appendstring(dst, code), scope...) +} + +// AppendCodeWithScopeElement will append a BSON code with scope element using +// key, code, and scope to dst +// and return the extended buffer. +func AppendCodeWithScopeElement(dst []byte, key, code string, scope []byte) []byte { +	return AppendCodeWithScope(AppendHeader(dst, bsontype.CodeWithScope, key), code, scope) +} + +// ReadCodeWithScope will read code and scope from src. If there are not enough bytes it +// will return false. +func ReadCodeWithScope(src []byte) (code string, scope []byte, rem []byte, ok bool) { +	length, rem, ok := ReadLength(src) +	if !ok || len(src) < int(length) { +		return "", nil, src, false +	} + +	code, rem, ok = readstring(rem) +	if !ok { +		return "", nil, src, false +	} + +	scope, rem, ok = ReadDocument(rem) +	if !ok { +		return "", nil, src, false +	} +	return code, scope, rem, true +} + +// AppendInt32 will append i32 to dst and return the extended buffer. +func AppendInt32(dst []byte, i32 int32) []byte { return appendi32(dst, i32) } + +// AppendInt32Element will append a BSON int32 element using key and i32 to dst +// and return the extended buffer. +func AppendInt32Element(dst []byte, key string, i32 int32) []byte { +	return AppendInt32(AppendHeader(dst, bsontype.Int32, key), i32) +} + +// ReadInt32 will read an int32 from src. If there are not enough bytes it +// will return false. +func ReadInt32(src []byte) (int32, []byte, bool) { return readi32(src) } + +// AppendTimestamp will append t and i to dst and return the extended buffer. +func AppendTimestamp(dst []byte, t, i uint32) []byte { +	return appendu32(appendu32(dst, i), t) // i is the lower 4 bytes, t is the higher 4 bytes +} + +// AppendTimestampElement will append a BSON timestamp element using key, t, and +// i to dst and return the extended buffer. +func AppendTimestampElement(dst []byte, key string, t, i uint32) []byte { +	return AppendTimestamp(AppendHeader(dst, bsontype.Timestamp, key), t, i) +} + +// ReadTimestamp will read t and i from src. If there are not enough bytes it +// will return false. +func ReadTimestamp(src []byte) (t, i uint32, rem []byte, ok bool) { +	i, rem, ok = readu32(src) +	if !ok { +		return 0, 0, src, false +	} +	t, rem, ok = readu32(rem) +	if !ok { +		return 0, 0, src, false +	} +	return t, i, rem, true +} + +// AppendInt64 will append i64 to dst and return the extended buffer. +func AppendInt64(dst []byte, i64 int64) []byte { return appendi64(dst, i64) } + +// AppendInt64Element will append a BSON int64 element using key and i64 to dst +// and return the extended buffer. +func AppendInt64Element(dst []byte, key string, i64 int64) []byte { +	return AppendInt64(AppendHeader(dst, bsontype.Int64, key), i64) +} + +// ReadInt64 will read an int64 from src. If there are not enough bytes it +// will return false. +func ReadInt64(src []byte) (int64, []byte, bool) { return readi64(src) } + +// AppendDecimal128 will append d128 to dst and return the extended buffer. +func AppendDecimal128(dst []byte, d128 primitive.Decimal128) []byte { +	high, low := d128.GetBytes() +	return appendu64(appendu64(dst, low), high) +} + +// AppendDecimal128Element will append a BSON primitive.28 element using key and +// d128 to dst and return the extended buffer. +func AppendDecimal128Element(dst []byte, key string, d128 primitive.Decimal128) []byte { +	return AppendDecimal128(AppendHeader(dst, bsontype.Decimal128, key), d128) +} + +// ReadDecimal128 will read a primitive.Decimal128 from src. If there are not enough bytes it +// will return false. +func ReadDecimal128(src []byte) (primitive.Decimal128, []byte, bool) { +	l, rem, ok := readu64(src) +	if !ok { +		return primitive.Decimal128{}, src, false +	} + +	h, rem, ok := readu64(rem) +	if !ok { +		return primitive.Decimal128{}, src, false +	} + +	return primitive.NewDecimal128(h, l), rem, true +} + +// AppendMaxKeyElement will append a BSON max key element using key to dst +// and return the extended buffer. +func AppendMaxKeyElement(dst []byte, key string) []byte { +	return AppendHeader(dst, bsontype.MaxKey, key) +} + +// AppendMinKeyElement will append a BSON min key element using key to dst +// and return the extended buffer. +func AppendMinKeyElement(dst []byte, key string) []byte { +	return AppendHeader(dst, bsontype.MinKey, key) +} + +// EqualValue will return true if the two values are equal. +func EqualValue(t1, t2 bsontype.Type, v1, v2 []byte) bool { +	if t1 != t2 { +		return false +	} +	v1, _, ok := readValue(v1, t1) +	if !ok { +		return false +	} +	v2, _, ok = readValue(v2, t2) +	if !ok { +		return false +	} +	return bytes.Equal(v1, v2) +} + +// valueLength will determine the length of the next value contained in src as if it +// is type t. The returned bool will be false if there are not enough bytes in src for +// a value of type t. +func valueLength(src []byte, t bsontype.Type) (int32, bool) { +	var length int32 +	ok := true +	switch t { +	case bsontype.Array, bsontype.EmbeddedDocument, bsontype.CodeWithScope: +		length, _, ok = ReadLength(src) +	case bsontype.Binary: +		length, _, ok = ReadLength(src) +		length += 4 + 1 // binary length + subtype byte +	case bsontype.Boolean: +		length = 1 +	case bsontype.DBPointer: +		length, _, ok = ReadLength(src) +		length += 4 + 12 // string length + ObjectID length +	case bsontype.DateTime, bsontype.Double, bsontype.Int64, bsontype.Timestamp: +		length = 8 +	case bsontype.Decimal128: +		length = 16 +	case bsontype.Int32: +		length = 4 +	case bsontype.JavaScript, bsontype.String, bsontype.Symbol: +		length, _, ok = ReadLength(src) +		length += 4 +	case bsontype.MaxKey, bsontype.MinKey, bsontype.Null, bsontype.Undefined: +		length = 0 +	case bsontype.ObjectID: +		length = 12 +	case bsontype.Regex: +		regex := bytes.IndexByte(src, 0x00) +		if regex < 0 { +			ok = false +			break +		} +		pattern := bytes.IndexByte(src[regex+1:], 0x00) +		if pattern < 0 { +			ok = false +			break +		} +		length = int32(int64(regex) + 1 + int64(pattern) + 1) +	default: +		ok = false +	} + +	return length, ok +} + +func readValue(src []byte, t bsontype.Type) ([]byte, []byte, bool) { +	length, ok := valueLength(src, t) +	if !ok || int(length) > len(src) { +		return nil, src, false +	} + +	return src[:length], src[length:], true +} + +// ReserveLength reserves the space required for length and returns the index where to write the length +// and the []byte with reserved space. +func ReserveLength(dst []byte) (int32, []byte) { +	index := len(dst) +	return int32(index), append(dst, 0x00, 0x00, 0x00, 0x00) +} + +// UpdateLength updates the length at index with length and returns the []byte. +func UpdateLength(dst []byte, index, length int32) []byte { +	dst[index] = byte(length) +	dst[index+1] = byte(length >> 8) +	dst[index+2] = byte(length >> 16) +	dst[index+3] = byte(length >> 24) +	return dst +} + +func appendLength(dst []byte, l int32) []byte { return appendi32(dst, l) } + +func appendi32(dst []byte, i32 int32) []byte { +	return append(dst, byte(i32), byte(i32>>8), byte(i32>>16), byte(i32>>24)) +} + +// ReadLength reads an int32 length from src and returns the length and the remaining bytes. If +// there aren't enough bytes to read a valid length, src is returned unomdified and the returned +// bool will be false. +func ReadLength(src []byte) (int32, []byte, bool) { +	ln, src, ok := readi32(src) +	if ln < 0 { +		return ln, src, false +	} +	return ln, src, ok +} + +func readi32(src []byte) (int32, []byte, bool) { +	if len(src) < 4 { +		return 0, src, false +	} +	return (int32(src[0]) | int32(src[1])<<8 | int32(src[2])<<16 | int32(src[3])<<24), src[4:], true +} + +func appendi64(dst []byte, i64 int64) []byte { +	return append(dst, +		byte(i64), byte(i64>>8), byte(i64>>16), byte(i64>>24), +		byte(i64>>32), byte(i64>>40), byte(i64>>48), byte(i64>>56), +	) +} + +func readi64(src []byte) (int64, []byte, bool) { +	if len(src) < 8 { +		return 0, src, false +	} +	i64 := (int64(src[0]) | int64(src[1])<<8 | int64(src[2])<<16 | int64(src[3])<<24 | +		int64(src[4])<<32 | int64(src[5])<<40 | int64(src[6])<<48 | int64(src[7])<<56) +	return i64, src[8:], true +} + +func appendu32(dst []byte, u32 uint32) []byte { +	return append(dst, byte(u32), byte(u32>>8), byte(u32>>16), byte(u32>>24)) +} + +func readu32(src []byte) (uint32, []byte, bool) { +	if len(src) < 4 { +		return 0, src, false +	} + +	return (uint32(src[0]) | uint32(src[1])<<8 | uint32(src[2])<<16 | uint32(src[3])<<24), src[4:], true +} + +func appendu64(dst []byte, u64 uint64) []byte { +	return append(dst, +		byte(u64), byte(u64>>8), byte(u64>>16), byte(u64>>24), +		byte(u64>>32), byte(u64>>40), byte(u64>>48), byte(u64>>56), +	) +} + +func readu64(src []byte) (uint64, []byte, bool) { +	if len(src) < 8 { +		return 0, src, false +	} +	u64 := (uint64(src[0]) | uint64(src[1])<<8 | uint64(src[2])<<16 | uint64(src[3])<<24 | +		uint64(src[4])<<32 | uint64(src[5])<<40 | uint64(src[6])<<48 | uint64(src[7])<<56) +	return u64, src[8:], true +} + +// keep in sync with readcstringbytes +func readcstring(src []byte) (string, []byte, bool) { +	idx := bytes.IndexByte(src, 0x00) +	if idx < 0 { +		return "", src, false +	} +	return string(src[:idx]), src[idx+1:], true +} + +// keep in sync with readcstring +func readcstringbytes(src []byte) ([]byte, []byte, bool) { +	idx := bytes.IndexByte(src, 0x00) +	if idx < 0 { +		return nil, src, false +	} +	return src[:idx], src[idx+1:], true +} + +func appendstring(dst []byte, s string) []byte { +	l := int32(len(s) + 1) +	dst = appendLength(dst, l) +	dst = append(dst, s...) +	return append(dst, 0x00) +} + +func readstring(src []byte) (string, []byte, bool) { +	l, rem, ok := ReadLength(src) +	if !ok { +		return "", src, false +	} +	if len(src[4:]) < int(l) || l == 0 { +		return "", src, false +	} + +	return string(rem[:l-1]), rem[l:], true +} + +// readLengthBytes attempts to read a length and that number of bytes. This +// function requires that the length include the four bytes for itself. +func readLengthBytes(src []byte) ([]byte, []byte, bool) { +	l, _, ok := ReadLength(src) +	if !ok { +		return nil, src, false +	} +	if len(src) < int(l) { +		return nil, src, false +	} +	return src[:l], src[l:], true +} + +func appendBinarySubtype2(dst []byte, subtype byte, b []byte) []byte { +	dst = appendLength(dst, int32(len(b)+4)) // The bytes we'll encode need to be 4 larger for the length bytes +	dst = append(dst, subtype) +	dst = appendLength(dst, int32(len(b))) +	return append(dst, b...) +} + +func isValidCString(cs string) bool { +	return !strings.ContainsRune(cs, '\x00') +} diff --git a/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/document.go b/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/document.go new file mode 100644 index 000000000..d6e4bb069 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/document.go @@ -0,0 +1,386 @@ +// 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 bsoncore + +import ( +	"bytes" +	"errors" +	"fmt" +	"io" +	"strconv" + +	"go.mongodb.org/mongo-driver/bson/bsontype" +) + +// ValidationError is an error type returned when attempting to validate a document or array. +type ValidationError string + +func (ve ValidationError) Error() string { return string(ve) } + +// NewDocumentLengthError creates and returns an error for when the length of a document exceeds the +// bytes available. +func NewDocumentLengthError(length, rem int) error { +	return lengthError("document", length, rem) +} + +func lengthError(bufferType string, length, rem int) error { +	return ValidationError(fmt.Sprintf("%v length exceeds available bytes. length=%d remainingBytes=%d", +		bufferType, length, rem)) +} + +// InsufficientBytesError indicates that there were not enough bytes to read the next component. +type InsufficientBytesError struct { +	Source    []byte +	Remaining []byte +} + +// NewInsufficientBytesError creates a new InsufficientBytesError with the given Document and +// remaining bytes. +func NewInsufficientBytesError(src, rem []byte) InsufficientBytesError { +	return InsufficientBytesError{Source: src, Remaining: rem} +} + +// Error implements the error interface. +func (ibe InsufficientBytesError) Error() string { +	return "too few bytes to read next component" +} + +// Equal checks that err2 also is an ErrTooSmall. +func (ibe InsufficientBytesError) Equal(err2 error) bool { +	switch err2.(type) { +	case InsufficientBytesError: +		return true +	default: +		return false +	} +} + +// InvalidDepthTraversalError is returned when attempting a recursive Lookup when one component of +// the path is neither an embedded document nor an array. +type InvalidDepthTraversalError struct { +	Key  string +	Type bsontype.Type +} + +func (idte InvalidDepthTraversalError) Error() string { +	return fmt.Sprintf( +		"attempt to traverse into %s, but it's type is %s, not %s nor %s", +		idte.Key, idte.Type, bsontype.EmbeddedDocument, bsontype.Array, +	) +} + +// ErrMissingNull is returned when a document or array's last byte is not null. +const ErrMissingNull ValidationError = "document or array end is missing null byte" + +// ErrInvalidLength indicates that a length in a binary representation of a BSON document or array +// is invalid. +const ErrInvalidLength ValidationError = "document or array length is invalid" + +// ErrNilReader indicates that an operation was attempted on a nil io.Reader. +var ErrNilReader = errors.New("nil reader") + +// ErrEmptyKey indicates that no key was provided to a Lookup method. +var ErrEmptyKey = errors.New("empty key provided") + +// ErrElementNotFound indicates that an Element matching a certain condition does not exist. +var ErrElementNotFound = errors.New("element not found") + +// ErrOutOfBounds indicates that an index provided to access something was invalid. +var ErrOutOfBounds = errors.New("out of bounds") + +// Document is a raw bytes representation of a BSON document. +type Document []byte + +// NewDocumentFromReader reads a document from r. This function will only validate the length is +// correct and that the document ends with a null byte. +func NewDocumentFromReader(r io.Reader) (Document, error) { +	return newBufferFromReader(r) +} + +func newBufferFromReader(r io.Reader) ([]byte, error) { +	if r == nil { +		return nil, ErrNilReader +	} + +	var lengthBytes [4]byte + +	// ReadFull guarantees that we will have read at least len(lengthBytes) if err == nil +	_, err := io.ReadFull(r, lengthBytes[:]) +	if err != nil { +		return nil, err +	} + +	length, _, _ := readi32(lengthBytes[:]) // ignore ok since we always have enough bytes to read a length +	if length < 0 { +		return nil, ErrInvalidLength +	} +	buffer := make([]byte, length) + +	copy(buffer, lengthBytes[:]) + +	_, err = io.ReadFull(r, buffer[4:]) +	if err != nil { +		return nil, err +	} + +	if buffer[length-1] != 0x00 { +		return nil, ErrMissingNull +	} + +	return buffer, nil +} + +// Lookup searches the document, potentially recursively, for the given key. If there are multiple +// keys provided, this method will recurse down, as long as the top and intermediate nodes are +// either documents or arrays. If an error occurs or if the value doesn't exist, an empty Value is +// returned. +func (d Document) Lookup(key ...string) Value { +	val, _ := d.LookupErr(key...) +	return val +} + +// LookupErr is the same as Lookup, except it returns an error in addition to an empty Value. +func (d Document) LookupErr(key ...string) (Value, error) { +	if len(key) < 1 { +		return Value{}, ErrEmptyKey +	} +	length, rem, ok := ReadLength(d) +	if !ok { +		return Value{}, NewInsufficientBytesError(d, rem) +	} + +	length -= 4 + +	var elem Element +	for length > 1 { +		elem, rem, ok = ReadElement(rem) +		length -= int32(len(elem)) +		if !ok { +			return Value{}, NewInsufficientBytesError(d, rem) +		} +		// We use `KeyBytes` rather than `Key` to avoid a needless string alloc. +		if string(elem.KeyBytes()) != key[0] { +			continue +		} +		if len(key) > 1 { +			tt := bsontype.Type(elem[0]) +			switch tt { +			case bsontype.EmbeddedDocument: +				val, err := elem.Value().Document().LookupErr(key[1:]...) +				if err != nil { +					return Value{}, err +				} +				return val, nil +			case bsontype.Array: +				// Convert to Document to continue Lookup recursion. +				val, err := Document(elem.Value().Array()).LookupErr(key[1:]...) +				if err != nil { +					return Value{}, err +				} +				return val, nil +			default: +				return Value{}, InvalidDepthTraversalError{Key: elem.Key(), Type: tt} +			} +		} +		return elem.ValueErr() +	} +	return Value{}, ErrElementNotFound +} + +// Index searches for and retrieves the element at the given index. This method will panic if +// the document is invalid or if the index is out of bounds. +func (d Document) Index(index uint) Element { +	elem, err := d.IndexErr(index) +	if err != nil { +		panic(err) +	} +	return elem +} + +// IndexErr searches for and retrieves the element at the given index. +func (d Document) IndexErr(index uint) (Element, error) { +	return indexErr(d, index) +} + +func indexErr(b []byte, index uint) (Element, error) { +	length, rem, ok := ReadLength(b) +	if !ok { +		return nil, NewInsufficientBytesError(b, rem) +	} + +	length -= 4 + +	var current uint +	var elem Element +	for length > 1 { +		elem, rem, ok = ReadElement(rem) +		length -= int32(len(elem)) +		if !ok { +			return nil, NewInsufficientBytesError(b, rem) +		} +		if current != index { +			current++ +			continue +		} +		return elem, nil +	} +	return nil, ErrOutOfBounds +} + +// DebugString outputs a human readable version of Document. It will attempt to stringify the +// valid components of the document even if the entire document is not valid. +func (d Document) DebugString() string { +	if len(d) < 5 { +		return "<malformed>" +	} +	var buf bytes.Buffer +	buf.WriteString("Document") +	length, rem, _ := ReadLength(d) // We know we have enough bytes to read the length +	buf.WriteByte('(') +	buf.WriteString(strconv.Itoa(int(length))) +	length -= 4 +	buf.WriteString("){") +	var elem Element +	var ok bool +	for length > 1 { +		elem, rem, ok = ReadElement(rem) +		length -= int32(len(elem)) +		if !ok { +			buf.WriteString(fmt.Sprintf("<malformed (%d)>", length)) +			break +		} +		fmt.Fprintf(&buf, "%s ", elem.DebugString()) +	} +	buf.WriteByte('}') + +	return buf.String() +} + +// String outputs an ExtendedJSON version of Document. If the document is not valid, this method +// returns an empty string. +func (d Document) String() string { +	if len(d) < 5 { +		return "" +	} +	var buf bytes.Buffer +	buf.WriteByte('{') + +	length, rem, _ := ReadLength(d) // We know we have enough bytes to read the length + +	length -= 4 + +	var elem Element +	var ok bool +	first := true +	for length > 1 { +		if !first { +			buf.WriteByte(',') +		} +		elem, rem, ok = ReadElement(rem) +		length -= int32(len(elem)) +		if !ok { +			return "" +		} +		fmt.Fprintf(&buf, "%s", elem.String()) +		first = false +	} +	buf.WriteByte('}') + +	return buf.String() +} + +// Elements returns this document as a slice of elements. The returned slice will contain valid +// elements. If the document is not valid, the elements up to the invalid point will be returned +// along with an error. +func (d Document) Elements() ([]Element, error) { +	length, rem, ok := ReadLength(d) +	if !ok { +		return nil, NewInsufficientBytesError(d, rem) +	} + +	length -= 4 + +	var elem Element +	var elems []Element +	for length > 1 { +		elem, rem, ok = ReadElement(rem) +		length -= int32(len(elem)) +		if !ok { +			return elems, NewInsufficientBytesError(d, rem) +		} +		if err := elem.Validate(); err != nil { +			return elems, err +		} +		elems = append(elems, elem) +	} +	return elems, nil +} + +// Values returns this document as a slice of values. The returned slice will contain valid values. +// If the document is not valid, the values up to the invalid point will be returned along with an +// error. +func (d Document) Values() ([]Value, error) { +	return values(d) +} + +func values(b []byte) ([]Value, error) { +	length, rem, ok := ReadLength(b) +	if !ok { +		return nil, NewInsufficientBytesError(b, rem) +	} + +	length -= 4 + +	var elem Element +	var vals []Value +	for length > 1 { +		elem, rem, ok = ReadElement(rem) +		length -= int32(len(elem)) +		if !ok { +			return vals, NewInsufficientBytesError(b, rem) +		} +		if err := elem.Value().Validate(); err != nil { +			return vals, err +		} +		vals = append(vals, elem.Value()) +	} +	return vals, nil +} + +// Validate validates the document and ensures the elements contained within are valid. +func (d Document) Validate() error { +	length, rem, ok := ReadLength(d) +	if !ok { +		return NewInsufficientBytesError(d, rem) +	} +	if int(length) > len(d) { +		return NewDocumentLengthError(int(length), len(d)) +	} +	if d[length-1] != 0x00 { +		return ErrMissingNull +	} + +	length -= 4 +	var elem Element + +	for length > 1 { +		elem, rem, ok = ReadElement(rem) +		length -= int32(len(elem)) +		if !ok { +			return NewInsufficientBytesError(d, rem) +		} +		err := elem.Validate() +		if err != nil { +			return err +		} +	} + +	if len(rem) < 1 || rem[0] != 0x00 { +		return ErrMissingNull +	} +	return nil +} diff --git a/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/document_sequence.go b/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/document_sequence.go new file mode 100644 index 000000000..e35bd0cd9 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/document_sequence.go @@ -0,0 +1,189 @@ +// Copyright (C) MongoDB, Inc. 2022-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 bsoncore + +import ( +	"errors" +	"io" + +	"go.mongodb.org/mongo-driver/bson/bsontype" +) + +// DocumentSequenceStyle is used to represent how a document sequence is laid out in a slice of +// bytes. +type DocumentSequenceStyle uint32 + +// These constants are the valid styles for a DocumentSequence. +const ( +	_ DocumentSequenceStyle = iota +	SequenceStyle +	ArrayStyle +) + +// DocumentSequence represents a sequence of documents. The Style field indicates how the documents +// are laid out inside of the Data field. +type DocumentSequence struct { +	Style DocumentSequenceStyle +	Data  []byte +	Pos   int +} + +// ErrCorruptedDocument is returned when a full document couldn't be read from the sequence. +var ErrCorruptedDocument = errors.New("invalid DocumentSequence: corrupted document") + +// ErrNonDocument is returned when a DocumentSequence contains a non-document BSON value. +var ErrNonDocument = errors.New("invalid DocumentSequence: a non-document value was found in sequence") + +// ErrInvalidDocumentSequenceStyle is returned when an unknown DocumentSequenceStyle is set on a +// DocumentSequence. +var ErrInvalidDocumentSequenceStyle = errors.New("invalid DocumentSequenceStyle") + +// DocumentCount returns the number of documents in the sequence. +func (ds *DocumentSequence) DocumentCount() int { +	if ds == nil { +		return 0 +	} +	switch ds.Style { +	case SequenceStyle: +		var count int +		var ok bool +		rem := ds.Data +		for len(rem) > 0 { +			_, rem, ok = ReadDocument(rem) +			if !ok { +				return 0 +			} +			count++ +		} +		return count +	case ArrayStyle: +		_, rem, ok := ReadLength(ds.Data) +		if !ok { +			return 0 +		} + +		var count int +		for len(rem) > 1 { +			_, rem, ok = ReadElement(rem) +			if !ok { +				return 0 +			} +			count++ +		} +		return count +	default: +		return 0 +	} +} + +// Empty returns true if the sequence is empty. It always returns true for unknown sequence styles. +func (ds *DocumentSequence) Empty() bool { +	if ds == nil { +		return true +	} + +	switch ds.Style { +	case SequenceStyle: +		return len(ds.Data) == 0 +	case ArrayStyle: +		return len(ds.Data) <= 5 +	default: +		return true +	} +} + +// ResetIterator resets the iteration point for the Next method to the beginning of the document +// sequence. +func (ds *DocumentSequence) ResetIterator() { +	if ds == nil { +		return +	} +	ds.Pos = 0 +} + +// Documents returns a slice of the documents. If nil either the Data field is also nil or could not +// be properly read. +func (ds *DocumentSequence) Documents() ([]Document, error) { +	if ds == nil { +		return nil, nil +	} +	switch ds.Style { +	case SequenceStyle: +		rem := ds.Data +		var docs []Document +		var doc Document +		var ok bool +		for { +			doc, rem, ok = ReadDocument(rem) +			if !ok { +				if len(rem) == 0 { +					break +				} +				return nil, ErrCorruptedDocument +			} +			docs = append(docs, doc) +		} +		return docs, nil +	case ArrayStyle: +		if len(ds.Data) == 0 { +			return nil, nil +		} +		vals, err := Document(ds.Data).Values() +		if err != nil { +			return nil, ErrCorruptedDocument +		} +		docs := make([]Document, 0, len(vals)) +		for _, v := range vals { +			if v.Type != bsontype.EmbeddedDocument { +				return nil, ErrNonDocument +			} +			docs = append(docs, v.Data) +		} +		return docs, nil +	default: +		return nil, ErrInvalidDocumentSequenceStyle +	} +} + +// Next retrieves the next document from this sequence and returns it. This method will return +// io.EOF when it has reached the end of the sequence. +func (ds *DocumentSequence) Next() (Document, error) { +	if ds == nil || ds.Pos >= len(ds.Data) { +		return nil, io.EOF +	} +	switch ds.Style { +	case SequenceStyle: +		doc, _, ok := ReadDocument(ds.Data[ds.Pos:]) +		if !ok { +			return nil, ErrCorruptedDocument +		} +		ds.Pos += len(doc) +		return doc, nil +	case ArrayStyle: +		if ds.Pos < 4 { +			if len(ds.Data) < 4 { +				return nil, ErrCorruptedDocument +			} +			ds.Pos = 4 // Skip the length of the document +		} +		if len(ds.Data[ds.Pos:]) == 1 && ds.Data[ds.Pos] == 0x00 { +			return nil, io.EOF // At the end of the document +		} +		elem, _, ok := ReadElement(ds.Data[ds.Pos:]) +		if !ok { +			return nil, ErrCorruptedDocument +		} +		ds.Pos += len(elem) +		val := elem.Value() +		if val.Type != bsontype.EmbeddedDocument { +			return nil, ErrNonDocument +		} +		return val.Data, nil +	default: +		return nil, ErrInvalidDocumentSequenceStyle +	} +} diff --git a/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/element.go b/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/element.go new file mode 100644 index 000000000..3acb4222b --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/element.go @@ -0,0 +1,152 @@ +// 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 bsoncore + +import ( +	"bytes" +	"fmt" + +	"go.mongodb.org/mongo-driver/bson/bsontype" +) + +// MalformedElementError represents a class of errors that RawElement methods return. +type MalformedElementError string + +func (mee MalformedElementError) Error() string { return string(mee) } + +// ErrElementMissingKey is returned when a RawElement is missing a key. +const ErrElementMissingKey MalformedElementError = "element is missing key" + +// ErrElementMissingType is returned when a RawElement is missing a type. +const ErrElementMissingType MalformedElementError = "element is missing type" + +// Element is a raw bytes representation of a BSON element. +type Element []byte + +// Key returns the key for this element. If the element is not valid, this method returns an empty +// string. If knowing if the element is valid is important, use KeyErr. +func (e Element) Key() string { +	key, _ := e.KeyErr() +	return key +} + +// KeyBytes returns the key for this element as a []byte. If the element is not valid, this method +// returns an empty string. If knowing if the element is valid is important, use KeyErr. This method +// will not include the null byte at the end of the key in the slice of bytes. +func (e Element) KeyBytes() []byte { +	key, _ := e.KeyBytesErr() +	return key +} + +// KeyErr returns the key for this element, returning an error if the element is not valid. +func (e Element) KeyErr() (string, error) { +	key, err := e.KeyBytesErr() +	return string(key), err +} + +// KeyBytesErr returns the key for this element as a []byte, returning an error if the element is +// not valid. +func (e Element) KeyBytesErr() ([]byte, error) { +	if len(e) <= 0 { +		return nil, ErrElementMissingType +	} +	idx := bytes.IndexByte(e[1:], 0x00) +	if idx == -1 { +		return nil, ErrElementMissingKey +	} +	return e[1 : idx+1], nil +} + +// Validate ensures the element is a valid BSON element. +func (e Element) Validate() error { +	if len(e) < 1 { +		return ErrElementMissingType +	} +	idx := bytes.IndexByte(e[1:], 0x00) +	if idx == -1 { +		return ErrElementMissingKey +	} +	return Value{Type: bsontype.Type(e[0]), Data: e[idx+2:]}.Validate() +} + +// CompareKey will compare this element's key to key. This method makes it easy to compare keys +// without needing to allocate a string. The key may be null terminated. If a valid key cannot be +// read this method will return false. +func (e Element) CompareKey(key []byte) bool { +	if len(e) < 2 { +		return false +	} +	idx := bytes.IndexByte(e[1:], 0x00) +	if idx == -1 { +		return false +	} +	if index := bytes.IndexByte(key, 0x00); index > -1 { +		key = key[:index] +	} +	return bytes.Equal(e[1:idx+1], key) +} + +// Value returns the value of this element. If the element is not valid, this method returns an +// empty Value. If knowing if the element is valid is important, use ValueErr. +func (e Element) Value() Value { +	val, _ := e.ValueErr() +	return val +} + +// ValueErr returns the value for this element, returning an error if the element is not valid. +func (e Element) ValueErr() (Value, error) { +	if len(e) <= 0 { +		return Value{}, ErrElementMissingType +	} +	idx := bytes.IndexByte(e[1:], 0x00) +	if idx == -1 { +		return Value{}, ErrElementMissingKey +	} + +	val, rem, exists := ReadValue(e[idx+2:], bsontype.Type(e[0])) +	if !exists { +		return Value{}, NewInsufficientBytesError(e, rem) +	} +	return val, nil +} + +// String implements the fmt.String interface. The output will be in extended JSON format. +func (e Element) String() string { +	if len(e) <= 0 { +		return "" +	} +	t := bsontype.Type(e[0]) +	idx := bytes.IndexByte(e[1:], 0x00) +	if idx == -1 { +		return "" +	} +	key, valBytes := []byte(e[1:idx+1]), []byte(e[idx+2:]) +	val, _, valid := ReadValue(valBytes, t) +	if !valid { +		return "" +	} +	return fmt.Sprintf(`"%s": %v`, key, val) +} + +// DebugString outputs a human readable version of RawElement. It will attempt to stringify the +// valid components of the element even if the entire element is not valid. +func (e Element) DebugString() string { +	if len(e) <= 0 { +		return "<malformed>" +	} +	t := bsontype.Type(e[0]) +	idx := bytes.IndexByte(e[1:], 0x00) +	if idx == -1 { +		return fmt.Sprintf(`bson.Element{[%s]<malformed>}`, t) +	} +	key, valBytes := []byte(e[1:idx+1]), []byte(e[idx+2:]) +	val, _, valid := ReadValue(valBytes, t) +	if !valid { +		return fmt.Sprintf(`bson.Element{[%s]"%s": <malformed>}`, t, key) +	} +	return fmt.Sprintf(`bson.Element{[%s]"%s": %v}`, t, key, val) +} diff --git a/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/tables.go b/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/tables.go new file mode 100644 index 000000000..9fd903fd2 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/tables.go @@ -0,0 +1,223 @@ +// 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 +// +// Based on github.com/golang/go by The Go Authors +// See THIRD-PARTY-NOTICES for original license terms. + +package bsoncore + +import "unicode/utf8" + +// safeSet holds the value true if the ASCII character with the given array +// position can be represented inside a JSON string without any further +// escaping. +// +// All values are true except for the ASCII control characters (0-31), the +// double quote ("), and the backslash character ("\"). +var safeSet = [utf8.RuneSelf]bool{ +	' ':      true, +	'!':      true, +	'"':      false, +	'#':      true, +	'$':      true, +	'%':      true, +	'&':      true, +	'\'':     true, +	'(':      true, +	')':      true, +	'*':      true, +	'+':      true, +	',':      true, +	'-':      true, +	'.':      true, +	'/':      true, +	'0':      true, +	'1':      true, +	'2':      true, +	'3':      true, +	'4':      true, +	'5':      true, +	'6':      true, +	'7':      true, +	'8':      true, +	'9':      true, +	':':      true, +	';':      true, +	'<':      true, +	'=':      true, +	'>':      true, +	'?':      true, +	'@':      true, +	'A':      true, +	'B':      true, +	'C':      true, +	'D':      true, +	'E':      true, +	'F':      true, +	'G':      true, +	'H':      true, +	'I':      true, +	'J':      true, +	'K':      true, +	'L':      true, +	'M':      true, +	'N':      true, +	'O':      true, +	'P':      true, +	'Q':      true, +	'R':      true, +	'S':      true, +	'T':      true, +	'U':      true, +	'V':      true, +	'W':      true, +	'X':      true, +	'Y':      true, +	'Z':      true, +	'[':      true, +	'\\':     false, +	']':      true, +	'^':      true, +	'_':      true, +	'`':      true, +	'a':      true, +	'b':      true, +	'c':      true, +	'd':      true, +	'e':      true, +	'f':      true, +	'g':      true, +	'h':      true, +	'i':      true, +	'j':      true, +	'k':      true, +	'l':      true, +	'm':      true, +	'n':      true, +	'o':      true, +	'p':      true, +	'q':      true, +	'r':      true, +	's':      true, +	't':      true, +	'u':      true, +	'v':      true, +	'w':      true, +	'x':      true, +	'y':      true, +	'z':      true, +	'{':      true, +	'|':      true, +	'}':      true, +	'~':      true, +	'\u007f': true, +} + +// htmlSafeSet holds the value true if the ASCII character with the given +// array position can be safely represented inside a JSON string, embedded +// inside of HTML <script> tags, without any additional escaping. +// +// All values are true except for the ASCII control characters (0-31), the +// double quote ("), the backslash character ("\"), HTML opening and closing +// tags ("<" and ">"), and the ampersand ("&"). +var htmlSafeSet = [utf8.RuneSelf]bool{ +	' ':      true, +	'!':      true, +	'"':      false, +	'#':      true, +	'$':      true, +	'%':      true, +	'&':      false, +	'\'':     true, +	'(':      true, +	')':      true, +	'*':      true, +	'+':      true, +	',':      true, +	'-':      true, +	'.':      true, +	'/':      true, +	'0':      true, +	'1':      true, +	'2':      true, +	'3':      true, +	'4':      true, +	'5':      true, +	'6':      true, +	'7':      true, +	'8':      true, +	'9':      true, +	':':      true, +	';':      true, +	'<':      false, +	'=':      true, +	'>':      false, +	'?':      true, +	'@':      true, +	'A':      true, +	'B':      true, +	'C':      true, +	'D':      true, +	'E':      true, +	'F':      true, +	'G':      true, +	'H':      true, +	'I':      true, +	'J':      true, +	'K':      true, +	'L':      true, +	'M':      true, +	'N':      true, +	'O':      true, +	'P':      true, +	'Q':      true, +	'R':      true, +	'S':      true, +	'T':      true, +	'U':      true, +	'V':      true, +	'W':      true, +	'X':      true, +	'Y':      true, +	'Z':      true, +	'[':      true, +	'\\':     false, +	']':      true, +	'^':      true, +	'_':      true, +	'`':      true, +	'a':      true, +	'b':      true, +	'c':      true, +	'd':      true, +	'e':      true, +	'f':      true, +	'g':      true, +	'h':      true, +	'i':      true, +	'j':      true, +	'k':      true, +	'l':      true, +	'm':      true, +	'n':      true, +	'o':      true, +	'p':      true, +	'q':      true, +	'r':      true, +	's':      true, +	't':      true, +	'u':      true, +	'v':      true, +	'w':      true, +	'x':      true, +	'y':      true, +	'z':      true, +	'{':      true, +	'|':      true, +	'}':      true, +	'~':      true, +	'\u007f': true, +} diff --git a/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/value.go b/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/value.go new file mode 100644 index 000000000..789d2b982 --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/value.go @@ -0,0 +1,980 @@ +// 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 bsoncore + +import ( +	"bytes" +	"encoding/base64" +	"fmt" +	"math" +	"sort" +	"strconv" +	"strings" +	"time" +	"unicode/utf8" + +	"go.mongodb.org/mongo-driver/bson/bsontype" +	"go.mongodb.org/mongo-driver/bson/primitive" +) + +// ElementTypeError specifies that a method to obtain a BSON value an incorrect type was called on a bson.Value. +type ElementTypeError struct { +	Method string +	Type   bsontype.Type +} + +// Error implements the error interface. +func (ete ElementTypeError) Error() string { +	return "Call of " + ete.Method + " on " + ete.Type.String() + " type" +} + +// Value represents a BSON value with a type and raw bytes. +type Value struct { +	Type bsontype.Type +	Data []byte +} + +// Validate ensures the value is a valid BSON value. +func (v Value) Validate() error { +	_, _, valid := readValue(v.Data, v.Type) +	if !valid { +		return NewInsufficientBytesError(v.Data, v.Data) +	} +	return nil +} + +// IsNumber returns true if the type of v is a numeric BSON type. +func (v Value) IsNumber() bool { +	switch v.Type { +	case bsontype.Double, bsontype.Int32, bsontype.Int64, bsontype.Decimal128: +		return true +	default: +		return false +	} +} + +// AsInt32 returns a BSON number as an int32. If the BSON type is not a numeric one, this method +// will panic. +// +// TODO(skriptble): Add support for Decimal128. +func (v Value) AsInt32() int32 { +	if !v.IsNumber() { +		panic(ElementTypeError{"bsoncore.Value.AsInt32", v.Type}) +	} +	var i32 int32 +	switch v.Type { +	case bsontype.Double: +		f64, _, ok := ReadDouble(v.Data) +		if !ok { +			panic(NewInsufficientBytesError(v.Data, v.Data)) +		} +		i32 = int32(f64) +	case bsontype.Int32: +		var ok bool +		i32, _, ok = ReadInt32(v.Data) +		if !ok { +			panic(NewInsufficientBytesError(v.Data, v.Data)) +		} +	case bsontype.Int64: +		i64, _, ok := ReadInt64(v.Data) +		if !ok { +			panic(NewInsufficientBytesError(v.Data, v.Data)) +		} +		i32 = int32(i64) +	case bsontype.Decimal128: +		panic(ElementTypeError{"bsoncore.Value.AsInt32", v.Type}) +	} +	return i32 +} + +// AsInt32OK functions the same as AsInt32 but returns a boolean instead of panicking. False +// indicates an error. +// +// TODO(skriptble): Add support for Decimal128. +func (v Value) AsInt32OK() (int32, bool) { +	if !v.IsNumber() { +		return 0, false +	} +	var i32 int32 +	switch v.Type { +	case bsontype.Double: +		f64, _, ok := ReadDouble(v.Data) +		if !ok { +			return 0, false +		} +		i32 = int32(f64) +	case bsontype.Int32: +		var ok bool +		i32, _, ok = ReadInt32(v.Data) +		if !ok { +			return 0, false +		} +	case bsontype.Int64: +		i64, _, ok := ReadInt64(v.Data) +		if !ok { +			return 0, false +		} +		i32 = int32(i64) +	case bsontype.Decimal128: +		return 0, false +	} +	return i32, true +} + +// AsInt64 returns a BSON number as an int64. If the BSON type is not a numeric one, this method +// will panic. +// +// TODO(skriptble): Add support for Decimal128. +func (v Value) AsInt64() int64 { +	if !v.IsNumber() { +		panic(ElementTypeError{"bsoncore.Value.AsInt64", v.Type}) +	} +	var i64 int64 +	switch v.Type { +	case bsontype.Double: +		f64, _, ok := ReadDouble(v.Data) +		if !ok { +			panic(NewInsufficientBytesError(v.Data, v.Data)) +		} +		i64 = int64(f64) +	case bsontype.Int32: +		var ok bool +		i32, _, ok := ReadInt32(v.Data) +		if !ok { +			panic(NewInsufficientBytesError(v.Data, v.Data)) +		} +		i64 = int64(i32) +	case bsontype.Int64: +		var ok bool +		i64, _, ok = ReadInt64(v.Data) +		if !ok { +			panic(NewInsufficientBytesError(v.Data, v.Data)) +		} +	case bsontype.Decimal128: +		panic(ElementTypeError{"bsoncore.Value.AsInt64", v.Type}) +	} +	return i64 +} + +// AsInt64OK functions the same as AsInt64 but returns a boolean instead of panicking. False +// indicates an error. +// +// TODO(skriptble): Add support for Decimal128. +func (v Value) AsInt64OK() (int64, bool) { +	if !v.IsNumber() { +		return 0, false +	} +	var i64 int64 +	switch v.Type { +	case bsontype.Double: +		f64, _, ok := ReadDouble(v.Data) +		if !ok { +			return 0, false +		} +		i64 = int64(f64) +	case bsontype.Int32: +		var ok bool +		i32, _, ok := ReadInt32(v.Data) +		if !ok { +			return 0, false +		} +		i64 = int64(i32) +	case bsontype.Int64: +		var ok bool +		i64, _, ok = ReadInt64(v.Data) +		if !ok { +			return 0, false +		} +	case bsontype.Decimal128: +		return 0, false +	} +	return i64, true +} + +// AsFloat64 returns a BSON number as an float64. If the BSON type is not a numeric one, this method +// will panic. +// +// TODO(skriptble): Add support for Decimal128. +func (v Value) AsFloat64() float64 { return 0 } + +// AsFloat64OK functions the same as AsFloat64 but returns a boolean instead of panicking. False +// indicates an error. +// +// TODO(skriptble): Add support for Decimal128. +func (v Value) AsFloat64OK() (float64, bool) { return 0, false } + +// Add will add this value to another. This is currently only implemented for strings and numbers. +// If either value is a string, the other type is coerced into a string and added to the other. +// +// This method will alter v and will attempt to reuse the []byte of v. If the []byte is too small, +// it will be expanded. +func (v *Value) Add(v2 Value) error { return nil } + +// Equal compaes v to v2 and returns true if they are equal. +func (v Value) Equal(v2 Value) bool { +	if v.Type != v2.Type { +		return false +	} + +	return bytes.Equal(v.Data, v2.Data) +} + +// String implements the fmt.String interface. This method will return values in extended JSON +// format. If the value is not valid, this returns an empty string +func (v Value) String() string { +	switch v.Type { +	case bsontype.Double: +		f64, ok := v.DoubleOK() +		if !ok { +			return "" +		} +		return fmt.Sprintf(`{"$numberDouble":"%s"}`, formatDouble(f64)) +	case bsontype.String: +		str, ok := v.StringValueOK() +		if !ok { +			return "" +		} +		return escapeString(str) +	case bsontype.EmbeddedDocument: +		doc, ok := v.DocumentOK() +		if !ok { +			return "" +		} +		return doc.String() +	case bsontype.Array: +		arr, ok := v.ArrayOK() +		if !ok { +			return "" +		} +		return arr.String() +	case bsontype.Binary: +		subtype, data, ok := v.BinaryOK() +		if !ok { +			return "" +		} +		return fmt.Sprintf(`{"$binary":{"base64":"%s","subType":"%02x"}}`, base64.StdEncoding.EncodeToString(data), subtype) +	case bsontype.Undefined: +		return `{"$undefined":true}` +	case bsontype.ObjectID: +		oid, ok := v.ObjectIDOK() +		if !ok { +			return "" +		} +		return fmt.Sprintf(`{"$oid":"%s"}`, oid.Hex()) +	case bsontype.Boolean: +		b, ok := v.BooleanOK() +		if !ok { +			return "" +		} +		return strconv.FormatBool(b) +	case bsontype.DateTime: +		dt, ok := v.DateTimeOK() +		if !ok { +			return "" +		} +		return fmt.Sprintf(`{"$date":{"$numberLong":"%d"}}`, dt) +	case bsontype.Null: +		return "null" +	case bsontype.Regex: +		pattern, options, ok := v.RegexOK() +		if !ok { +			return "" +		} +		return fmt.Sprintf( +			`{"$regularExpression":{"pattern":%s,"options":"%s"}}`, +			escapeString(pattern), sortStringAlphebeticAscending(options), +		) +	case bsontype.DBPointer: +		ns, pointer, ok := v.DBPointerOK() +		if !ok { +			return "" +		} +		return fmt.Sprintf(`{"$dbPointer":{"$ref":%s,"$id":{"$oid":"%s"}}}`, escapeString(ns), pointer.Hex()) +	case bsontype.JavaScript: +		js, ok := v.JavaScriptOK() +		if !ok { +			return "" +		} +		return fmt.Sprintf(`{"$code":%s}`, escapeString(js)) +	case bsontype.Symbol: +		symbol, ok := v.SymbolOK() +		if !ok { +			return "" +		} +		return fmt.Sprintf(`{"$symbol":%s}`, escapeString(symbol)) +	case bsontype.CodeWithScope: +		code, scope, ok := v.CodeWithScopeOK() +		if !ok { +			return "" +		} +		return fmt.Sprintf(`{"$code":%s,"$scope":%s}`, code, scope) +	case bsontype.Int32: +		i32, ok := v.Int32OK() +		if !ok { +			return "" +		} +		return fmt.Sprintf(`{"$numberInt":"%d"}`, i32) +	case bsontype.Timestamp: +		t, i, ok := v.TimestampOK() +		if !ok { +			return "" +		} +		return fmt.Sprintf(`{"$timestamp":{"t":%v,"i":%v}}`, t, i) +	case bsontype.Int64: +		i64, ok := v.Int64OK() +		if !ok { +			return "" +		} +		return fmt.Sprintf(`{"$numberLong":"%d"}`, i64) +	case bsontype.Decimal128: +		d128, ok := v.Decimal128OK() +		if !ok { +			return "" +		} +		return fmt.Sprintf(`{"$numberDecimal":"%s"}`, d128.String()) +	case bsontype.MinKey: +		return `{"$minKey":1}` +	case bsontype.MaxKey: +		return `{"$maxKey":1}` +	default: +		return "" +	} +} + +// DebugString outputs a human readable version of Document. It will attempt to stringify the +// valid components of the document even if the entire document is not valid. +func (v Value) DebugString() string { +	switch v.Type { +	case bsontype.String: +		str, ok := v.StringValueOK() +		if !ok { +			return "<malformed>" +		} +		return escapeString(str) +	case bsontype.EmbeddedDocument: +		doc, ok := v.DocumentOK() +		if !ok { +			return "<malformed>" +		} +		return doc.DebugString() +	case bsontype.Array: +		arr, ok := v.ArrayOK() +		if !ok { +			return "<malformed>" +		} +		return arr.DebugString() +	case bsontype.CodeWithScope: +		code, scope, ok := v.CodeWithScopeOK() +		if !ok { +			return "" +		} +		return fmt.Sprintf(`{"$code":%s,"$scope":%s}`, code, scope.DebugString()) +	default: +		str := v.String() +		if str == "" { +			return "<malformed>" +		} +		return str +	} +} + +// Double returns the float64 value for this element. +// It panics if e's BSON type is not bsontype.Double. +func (v Value) Double() float64 { +	if v.Type != bsontype.Double { +		panic(ElementTypeError{"bsoncore.Value.Double", v.Type}) +	} +	f64, _, ok := ReadDouble(v.Data) +	if !ok { +		panic(NewInsufficientBytesError(v.Data, v.Data)) +	} +	return f64 +} + +// DoubleOK is the same as Double, but returns a boolean instead of panicking. +func (v Value) DoubleOK() (float64, bool) { +	if v.Type != bsontype.Double { +		return 0, false +	} +	f64, _, ok := ReadDouble(v.Data) +	if !ok { +		return 0, false +	} +	return f64, true +} + +// StringValue returns the string balue for this element. +// It panics if e's BSON type is not bsontype.String. +// +// NOTE: This method is called StringValue to avoid a collision with the String method which +// implements the fmt.Stringer interface. +func (v Value) StringValue() string { +	if v.Type != bsontype.String { +		panic(ElementTypeError{"bsoncore.Value.StringValue", v.Type}) +	} +	str, _, ok := ReadString(v.Data) +	if !ok { +		panic(NewInsufficientBytesError(v.Data, v.Data)) +	} +	return str +} + +// StringValueOK is the same as StringValue, but returns a boolean instead of +// panicking. +func (v Value) StringValueOK() (string, bool) { +	if v.Type != bsontype.String { +		return "", false +	} +	str, _, ok := ReadString(v.Data) +	if !ok { +		return "", false +	} +	return str, true +} + +// Document returns the BSON document the Value represents as a Document. It panics if the +// value is a BSON type other than document. +func (v Value) Document() Document { +	if v.Type != bsontype.EmbeddedDocument { +		panic(ElementTypeError{"bsoncore.Value.Document", v.Type}) +	} +	doc, _, ok := ReadDocument(v.Data) +	if !ok { +		panic(NewInsufficientBytesError(v.Data, v.Data)) +	} +	return doc +} + +// DocumentOK is the same as Document, except it returns a boolean +// instead of panicking. +func (v Value) DocumentOK() (Document, bool) { +	if v.Type != bsontype.EmbeddedDocument { +		return nil, false +	} +	doc, _, ok := ReadDocument(v.Data) +	if !ok { +		return nil, false +	} +	return doc, true +} + +// Array returns the BSON array the Value represents as an Array. It panics if the +// value is a BSON type other than array. +func (v Value) Array() Array { +	if v.Type != bsontype.Array { +		panic(ElementTypeError{"bsoncore.Value.Array", v.Type}) +	} +	arr, _, ok := ReadArray(v.Data) +	if !ok { +		panic(NewInsufficientBytesError(v.Data, v.Data)) +	} +	return arr +} + +// ArrayOK is the same as Array, except it returns a boolean instead +// of panicking. +func (v Value) ArrayOK() (Array, bool) { +	if v.Type != bsontype.Array { +		return nil, false +	} +	arr, _, ok := ReadArray(v.Data) +	if !ok { +		return nil, false +	} +	return arr, true +} + +// Binary returns the BSON binary value the Value represents. It panics if the value is a BSON type +// other than binary. +func (v Value) Binary() (subtype byte, data []byte) { +	if v.Type != bsontype.Binary { +		panic(ElementTypeError{"bsoncore.Value.Binary", v.Type}) +	} +	subtype, data, _, ok := ReadBinary(v.Data) +	if !ok { +		panic(NewInsufficientBytesError(v.Data, v.Data)) +	} +	return subtype, data +} + +// BinaryOK is the same as Binary, except it returns a boolean instead of +// panicking. +func (v Value) BinaryOK() (subtype byte, data []byte, ok bool) { +	if v.Type != bsontype.Binary { +		return 0x00, nil, false +	} +	subtype, data, _, ok = ReadBinary(v.Data) +	if !ok { +		return 0x00, nil, false +	} +	return subtype, data, true +} + +// ObjectID returns the BSON objectid value the Value represents. It panics if the value is a BSON +// type other than objectid. +func (v Value) ObjectID() primitive.ObjectID { +	if v.Type != bsontype.ObjectID { +		panic(ElementTypeError{"bsoncore.Value.ObjectID", v.Type}) +	} +	oid, _, ok := ReadObjectID(v.Data) +	if !ok { +		panic(NewInsufficientBytesError(v.Data, v.Data)) +	} +	return oid +} + +// ObjectIDOK is the same as ObjectID, except it returns a boolean instead of +// panicking. +func (v Value) ObjectIDOK() (primitive.ObjectID, bool) { +	if v.Type != bsontype.ObjectID { +		return primitive.ObjectID{}, false +	} +	oid, _, ok := ReadObjectID(v.Data) +	if !ok { +		return primitive.ObjectID{}, false +	} +	return oid, true +} + +// Boolean returns the boolean value the Value represents. It panics if the +// value is a BSON type other than boolean. +func (v Value) Boolean() bool { +	if v.Type != bsontype.Boolean { +		panic(ElementTypeError{"bsoncore.Value.Boolean", v.Type}) +	} +	b, _, ok := ReadBoolean(v.Data) +	if !ok { +		panic(NewInsufficientBytesError(v.Data, v.Data)) +	} +	return b +} + +// BooleanOK is the same as Boolean, except it returns a boolean instead of +// panicking. +func (v Value) BooleanOK() (bool, bool) { +	if v.Type != bsontype.Boolean { +		return false, false +	} +	b, _, ok := ReadBoolean(v.Data) +	if !ok { +		return false, false +	} +	return b, true +} + +// DateTime returns the BSON datetime value the Value represents as a +// unix timestamp. It panics if the value is a BSON type other than datetime. +func (v Value) DateTime() int64 { +	if v.Type != bsontype.DateTime { +		panic(ElementTypeError{"bsoncore.Value.DateTime", v.Type}) +	} +	dt, _, ok := ReadDateTime(v.Data) +	if !ok { +		panic(NewInsufficientBytesError(v.Data, v.Data)) +	} +	return dt +} + +// DateTimeOK is the same as DateTime, except it returns a boolean instead of +// panicking. +func (v Value) DateTimeOK() (int64, bool) { +	if v.Type != bsontype.DateTime { +		return 0, false +	} +	dt, _, ok := ReadDateTime(v.Data) +	if !ok { +		return 0, false +	} +	return dt, true +} + +// Time returns the BSON datetime value the Value represents. It panics if the value is a BSON +// type other than datetime. +func (v Value) Time() time.Time { +	if v.Type != bsontype.DateTime { +		panic(ElementTypeError{"bsoncore.Value.Time", v.Type}) +	} +	dt, _, ok := ReadDateTime(v.Data) +	if !ok { +		panic(NewInsufficientBytesError(v.Data, v.Data)) +	} +	return time.Unix(dt/1000, dt%1000*1000000) +} + +// TimeOK is the same as Time, except it returns a boolean instead of +// panicking. +func (v Value) TimeOK() (time.Time, bool) { +	if v.Type != bsontype.DateTime { +		return time.Time{}, false +	} +	dt, _, ok := ReadDateTime(v.Data) +	if !ok { +		return time.Time{}, false +	} +	return time.Unix(dt/1000, dt%1000*1000000), true +} + +// Regex returns the BSON regex value the Value represents. It panics if the value is a BSON +// type other than regex. +func (v Value) Regex() (pattern, options string) { +	if v.Type != bsontype.Regex { +		panic(ElementTypeError{"bsoncore.Value.Regex", v.Type}) +	} +	pattern, options, _, ok := ReadRegex(v.Data) +	if !ok { +		panic(NewInsufficientBytesError(v.Data, v.Data)) +	} +	return pattern, options +} + +// RegexOK is the same as Regex, except it returns a boolean instead of +// panicking. +func (v Value) RegexOK() (pattern, options string, ok bool) { +	if v.Type != bsontype.Regex { +		return "", "", false +	} +	pattern, options, _, ok = ReadRegex(v.Data) +	if !ok { +		return "", "", false +	} +	return pattern, options, true +} + +// DBPointer returns the BSON dbpointer value the Value represents. It panics if the value is a BSON +// type other than DBPointer. +func (v Value) DBPointer() (string, primitive.ObjectID) { +	if v.Type != bsontype.DBPointer { +		panic(ElementTypeError{"bsoncore.Value.DBPointer", v.Type}) +	} +	ns, pointer, _, ok := ReadDBPointer(v.Data) +	if !ok { +		panic(NewInsufficientBytesError(v.Data, v.Data)) +	} +	return ns, pointer +} + +// DBPointerOK is the same as DBPoitner, except that it returns a boolean +// instead of panicking. +func (v Value) DBPointerOK() (string, primitive.ObjectID, bool) { +	if v.Type != bsontype.DBPointer { +		return "", primitive.ObjectID{}, false +	} +	ns, pointer, _, ok := ReadDBPointer(v.Data) +	if !ok { +		return "", primitive.ObjectID{}, false +	} +	return ns, pointer, true +} + +// JavaScript returns the BSON JavaScript code value the Value represents. It panics if the value is +// a BSON type other than JavaScript code. +func (v Value) JavaScript() string { +	if v.Type != bsontype.JavaScript { +		panic(ElementTypeError{"bsoncore.Value.JavaScript", v.Type}) +	} +	js, _, ok := ReadJavaScript(v.Data) +	if !ok { +		panic(NewInsufficientBytesError(v.Data, v.Data)) +	} +	return js +} + +// JavaScriptOK is the same as Javascript, excepti that it returns a boolean +// instead of panicking. +func (v Value) JavaScriptOK() (string, bool) { +	if v.Type != bsontype.JavaScript { +		return "", false +	} +	js, _, ok := ReadJavaScript(v.Data) +	if !ok { +		return "", false +	} +	return js, true +} + +// Symbol returns the BSON symbol value the Value represents. It panics if the value is a BSON +// type other than symbol. +func (v Value) Symbol() string { +	if v.Type != bsontype.Symbol { +		panic(ElementTypeError{"bsoncore.Value.Symbol", v.Type}) +	} +	symbol, _, ok := ReadSymbol(v.Data) +	if !ok { +		panic(NewInsufficientBytesError(v.Data, v.Data)) +	} +	return symbol +} + +// SymbolOK is the same as Symbol, excepti that it returns a boolean +// instead of panicking. +func (v Value) SymbolOK() (string, bool) { +	if v.Type != bsontype.Symbol { +		return "", false +	} +	symbol, _, ok := ReadSymbol(v.Data) +	if !ok { +		return "", false +	} +	return symbol, true +} + +// CodeWithScope returns the BSON JavaScript code with scope the Value represents. +// It panics if the value is a BSON type other than JavaScript code with scope. +func (v Value) CodeWithScope() (string, Document) { +	if v.Type != bsontype.CodeWithScope { +		panic(ElementTypeError{"bsoncore.Value.CodeWithScope", v.Type}) +	} +	code, scope, _, ok := ReadCodeWithScope(v.Data) +	if !ok { +		panic(NewInsufficientBytesError(v.Data, v.Data)) +	} +	return code, scope +} + +// CodeWithScopeOK is the same as CodeWithScope, except that it returns a boolean instead of +// panicking. +func (v Value) CodeWithScopeOK() (string, Document, bool) { +	if v.Type != bsontype.CodeWithScope { +		return "", nil, false +	} +	code, scope, _, ok := ReadCodeWithScope(v.Data) +	if !ok { +		return "", nil, false +	} +	return code, scope, true +} + +// Int32 returns the int32 the Value represents. It panics if the value is a BSON type other than +// int32. +func (v Value) Int32() int32 { +	if v.Type != bsontype.Int32 { +		panic(ElementTypeError{"bsoncore.Value.Int32", v.Type}) +	} +	i32, _, ok := ReadInt32(v.Data) +	if !ok { +		panic(NewInsufficientBytesError(v.Data, v.Data)) +	} +	return i32 +} + +// Int32OK is the same as Int32, except that it returns a boolean instead of +// panicking. +func (v Value) Int32OK() (int32, bool) { +	if v.Type != bsontype.Int32 { +		return 0, false +	} +	i32, _, ok := ReadInt32(v.Data) +	if !ok { +		return 0, false +	} +	return i32, true +} + +// Timestamp returns the BSON timestamp value the Value represents. It panics if the value is a +// BSON type other than timestamp. +func (v Value) Timestamp() (t, i uint32) { +	if v.Type != bsontype.Timestamp { +		panic(ElementTypeError{"bsoncore.Value.Timestamp", v.Type}) +	} +	t, i, _, ok := ReadTimestamp(v.Data) +	if !ok { +		panic(NewInsufficientBytesError(v.Data, v.Data)) +	} +	return t, i +} + +// TimestampOK is the same as Timestamp, except that it returns a boolean +// instead of panicking. +func (v Value) TimestampOK() (t, i uint32, ok bool) { +	if v.Type != bsontype.Timestamp { +		return 0, 0, false +	} +	t, i, _, ok = ReadTimestamp(v.Data) +	if !ok { +		return 0, 0, false +	} +	return t, i, true +} + +// Int64 returns the int64 the Value represents. It panics if the value is a BSON type other than +// int64. +func (v Value) Int64() int64 { +	if v.Type != bsontype.Int64 { +		panic(ElementTypeError{"bsoncore.Value.Int64", v.Type}) +	} +	i64, _, ok := ReadInt64(v.Data) +	if !ok { +		panic(NewInsufficientBytesError(v.Data, v.Data)) +	} +	return i64 +} + +// Int64OK is the same as Int64, except that it returns a boolean instead of +// panicking. +func (v Value) Int64OK() (int64, bool) { +	if v.Type != bsontype.Int64 { +		return 0, false +	} +	i64, _, ok := ReadInt64(v.Data) +	if !ok { +		return 0, false +	} +	return i64, true +} + +// Decimal128 returns the decimal the Value represents. It panics if the value is a BSON type other than +// decimal. +func (v Value) Decimal128() primitive.Decimal128 { +	if v.Type != bsontype.Decimal128 { +		panic(ElementTypeError{"bsoncore.Value.Decimal128", v.Type}) +	} +	d128, _, ok := ReadDecimal128(v.Data) +	if !ok { +		panic(NewInsufficientBytesError(v.Data, v.Data)) +	} +	return d128 +} + +// Decimal128OK is the same as Decimal128, except that it returns a boolean +// instead of panicking. +func (v Value) Decimal128OK() (primitive.Decimal128, bool) { +	if v.Type != bsontype.Decimal128 { +		return primitive.Decimal128{}, false +	} +	d128, _, ok := ReadDecimal128(v.Data) +	if !ok { +		return primitive.Decimal128{}, false +	} +	return d128, true +} + +var hexChars = "0123456789abcdef" + +func escapeString(s string) string { +	escapeHTML := true +	var buf bytes.Buffer +	buf.WriteByte('"') +	start := 0 +	for i := 0; i < len(s); { +		if b := s[i]; b < utf8.RuneSelf { +			if htmlSafeSet[b] || (!escapeHTML && safeSet[b]) { +				i++ +				continue +			} +			if start < i { +				buf.WriteString(s[start:i]) +			} +			switch b { +			case '\\', '"': +				buf.WriteByte('\\') +				buf.WriteByte(b) +			case '\n': +				buf.WriteByte('\\') +				buf.WriteByte('n') +			case '\r': +				buf.WriteByte('\\') +				buf.WriteByte('r') +			case '\t': +				buf.WriteByte('\\') +				buf.WriteByte('t') +			case '\b': +				buf.WriteByte('\\') +				buf.WriteByte('b') +			case '\f': +				buf.WriteByte('\\') +				buf.WriteByte('f') +			default: +				// This encodes bytes < 0x20 except for \t, \n and \r. +				// If escapeHTML is set, it also escapes <, >, and & +				// because they can lead to security holes when +				// user-controlled strings are rendered into JSON +				// and served to some browsers. +				buf.WriteString(`\u00`) +				buf.WriteByte(hexChars[b>>4]) +				buf.WriteByte(hexChars[b&0xF]) +			} +			i++ +			start = i +			continue +		} +		c, size := utf8.DecodeRuneInString(s[i:]) +		if c == utf8.RuneError && size == 1 { +			if start < i { +				buf.WriteString(s[start:i]) +			} +			buf.WriteString(`\ufffd`) +			i += size +			start = i +			continue +		} +		// U+2028 is LINE SEPARATOR. +		// U+2029 is PARAGRAPH SEPARATOR. +		// They are both technically valid characters in JSON strings, +		// but don't work in JSONP, which has to be evaluated as JavaScript, +		// and can lead to security holes there. It is valid JSON to +		// escape them, so we do so unconditionally. +		// See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion. +		if c == '\u2028' || c == '\u2029' { +			if start < i { +				buf.WriteString(s[start:i]) +			} +			buf.WriteString(`\u202`) +			buf.WriteByte(hexChars[c&0xF]) +			i += size +			start = i +			continue +		} +		i += size +	} +	if start < len(s) { +		buf.WriteString(s[start:]) +	} +	buf.WriteByte('"') +	return buf.String() +} + +func formatDouble(f float64) string { +	var s string +	if math.IsInf(f, 1) { +		s = "Infinity" +	} else if math.IsInf(f, -1) { +		s = "-Infinity" +	} else if math.IsNaN(f) { +		s = "NaN" +	} else { +		// Print exactly one decimalType place for integers; otherwise, print as many are necessary to +		// perfectly represent it. +		s = strconv.FormatFloat(f, 'G', -1, 64) +		if !strings.ContainsRune(s, '.') { +			s += ".0" +		} +	} + +	return s +} + +type sortableString []rune + +func (ss sortableString) Len() int { +	return len(ss) +} + +func (ss sortableString) Less(i, j int) bool { +	return ss[i] < ss[j] +} + +func (ss sortableString) Swap(i, j int) { +	oldI := ss[i] +	ss[i] = ss[j] +	ss[j] = oldI +} + +func sortStringAlphebeticAscending(s string) string { +	ss := sortableString([]rune(s)) +	sort.Sort(ss) +	return string([]rune(ss)) +}  | 
