From fcdd960f8c406877b244e924657b021e260fdde7 Mon Sep 17 00:00:00 2001 From: Qingyang Hu Date: Mon, 29 Apr 2024 17:18:42 -0400 Subject: [PATCH] WIP --- bson/array_codec.go | 21 +--- bson/bson_test.go | 17 ++- bson/bsonoptions/byte_slice_codec_options.go | 49 -------- bson/bsonoptions/doc.go | 8 -- .../empty_interface_codec_options.go | 49 -------- bson/bsonoptions/map_codec_options.go | 82 -------------- bson/bsonoptions/slice_codec_options.go | 49 -------- bson/bsonoptions/string_codec_options.go | 52 --------- bson/bsonoptions/struct_codec_options.go | 107 ------------------ bson/bsonoptions/time_codec_options.go | 49 -------- bson/bsonoptions/uint_codec_options.go | 49 -------- bson/byte_slice_codec.go | 48 ++------ bson/cond_addr_codec.go | 6 - bson/cond_addr_codec_test.go | 4 +- bson/default_value_decoders.go | 38 +++---- bson/default_value_decoders_test.go | 29 ++--- bson/default_value_encoders.go | 28 ++--- bson/default_value_encoders_test.go | 22 ++-- bson/empty_interface_codec.go | 51 +++------ bson/map_codec.go | 69 +++-------- bson/mgocompat/bson_test.go | 6 +- bson/mgocompat/doc.go | 5 - bson/mgocompat/registry.go | 93 +-------------- bson/mgoregistry.go | 81 +++++++++++++ bson/pointer_codec.go | 27 ++--- bson/registry.go | 2 +- bson/registry_test.go | 8 +- bson/{mgocompat => }/setter_getter.go | 35 ++---- bson/slice_codec.go | 37 ++---- bson/string_codec.go | 47 +++----- bson/string_codec_test.go | 2 +- bson/struct_codec.go | 105 +++++------------ bson/time_codec.go | 47 ++------ bson/time_codec_test.go | 18 ++- bson/uint_codec.go | 47 ++------ bson/unmarshal_value_test.go | 4 +- 36 files changed, 305 insertions(+), 1086 deletions(-) delete mode 100644 bson/bsonoptions/byte_slice_codec_options.go delete mode 100644 bson/bsonoptions/doc.go delete mode 100644 bson/bsonoptions/empty_interface_codec_options.go delete mode 100644 bson/bsonoptions/map_codec_options.go delete mode 100644 bson/bsonoptions/slice_codec_options.go delete mode 100644 bson/bsonoptions/string_codec_options.go delete mode 100644 bson/bsonoptions/struct_codec_options.go delete mode 100644 bson/bsonoptions/time_codec_options.go delete mode 100644 bson/bsonoptions/uint_codec_options.go create mode 100644 bson/mgoregistry.go rename bson/{mgocompat => }/setter_getter.go (68%) diff --git a/bson/array_codec.go b/bson/array_codec.go index 5b07f4acd4..4a53d376bc 100644 --- a/bson/array_codec.go +++ b/bson/array_codec.go @@ -12,24 +12,11 @@ import ( "go.mongodb.org/mongo-driver/x/bsonx/bsoncore" ) -// ArrayCodec is the Codec used for bsoncore.Array values. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the -// ArrayCodec registered. -type ArrayCodec struct{} - -var defaultArrayCodec = NewArrayCodec() - -// NewArrayCodec returns an ArrayCodec. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the -// ArrayCodec registered. -func NewArrayCodec() *ArrayCodec { - return &ArrayCodec{} -} +// arrayCodec is the Codec used for bsoncore.Array values. +type arrayCodec struct{} // EncodeValue is the ValueEncoder for bsoncore.Array values. -func (ac *ArrayCodec) EncodeValue(_ EncodeContext, vw ValueWriter, val reflect.Value) error { +func (ac *arrayCodec) EncodeValue(_ EncodeContext, vw ValueWriter, val reflect.Value) error { if !val.IsValid() || val.Type() != tCoreArray { return ValueEncoderError{Name: "CoreArrayEncodeValue", Types: []reflect.Type{tCoreArray}, Received: val} } @@ -39,7 +26,7 @@ func (ac *ArrayCodec) EncodeValue(_ EncodeContext, vw ValueWriter, val reflect.V } // DecodeValue is the ValueDecoder for bsoncore.Array values. -func (ac *ArrayCodec) DecodeValue(_ DecodeContext, vr ValueReader, val reflect.Value) error { +func (ac *arrayCodec) DecodeValue(_ DecodeContext, vr ValueReader, val reflect.Value) error { if !val.CanSet() || val.Type() != tCoreArray { return ValueDecoderError{Name: "CoreArrayDecodeValue", Types: []reflect.Type{tCoreArray}, Received: val} } diff --git a/bson/bson_test.go b/bson/bson_test.go index 31b6ffb884..93f641f618 100644 --- a/bson/bson_test.go +++ b/bson/bson_test.go @@ -17,7 +17,6 @@ import ( "time" "github.com/google/go-cmp/cmp" - "go.mongodb.org/mongo-driver/bson/bsonoptions" "go.mongodb.org/mongo-driver/internal/assert" "go.mongodb.org/mongo-driver/internal/require" "go.mongodb.org/mongo-driver/x/bsonx/bsoncore" @@ -349,19 +348,19 @@ func TestMapCodec(t *testing.T) { strstr := stringerString("foo") mapObj := map[stringerString]int{strstr: 1} testCases := []struct { - name string - opts *bsonoptions.MapCodecOptions - key string + name string + codec *mapCodec + //opts *bsonoptions.MapCodecOptions + key string }{ - {"default", bsonoptions.MapCodec(), "foo"}, - {"true", bsonoptions.MapCodec().SetEncodeKeysWithStringer(true), "bar"}, - {"false", bsonoptions.MapCodec().SetEncodeKeysWithStringer(false), "foo"}, + {"default", &mapCodec{}, "foo"}, + {"true", &mapCodec{encodeKeysWithStringer: true}, "bar"}, + {"false", &mapCodec{encodeKeysWithStringer: false}, "foo"}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - mapCodec := NewMapCodec(tc.opts) mapRegistry := NewRegistry() - mapRegistry.RegisterKindEncoder(reflect.Map, mapCodec) + mapRegistry.RegisterKindEncoder(reflect.Map, tc.codec) buf := new(bytes.Buffer) vw := NewValueWriter(buf) enc := NewEncoder(vw) diff --git a/bson/bsonoptions/byte_slice_codec_options.go b/bson/bsonoptions/byte_slice_codec_options.go deleted file mode 100644 index 996bd17127..0000000000 --- a/bson/bsonoptions/byte_slice_codec_options.go +++ /dev/null @@ -1,49 +0,0 @@ -// 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. -// -// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal -// and unmarshal behavior instead. -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 -// -// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal -// and unmarshal behavior instead. -func ByteSliceCodec() *ByteSliceCodecOptions { - return &ByteSliceCodecOptions{} -} - -// SetEncodeNilAsEmpty specifies if a nil byte slice should encode as an empty binary instead of null. Defaults to false. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.NilByteSliceAsEmpty] instead. -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. -// -// Deprecated: Merging options structs will not be supported in Go Driver 2.0. Users should create a -// single options struct instead. -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/bson/bsonoptions/doc.go b/bson/bsonoptions/doc.go deleted file mode 100644 index c40973c8d4..0000000000 --- a/bson/bsonoptions/doc.go +++ /dev/null @@ -1,8 +0,0 @@ -// 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/bson/bsonoptions/empty_interface_codec_options.go b/bson/bsonoptions/empty_interface_codec_options.go deleted file mode 100644 index f522c7e03f..0000000000 --- a/bson/bsonoptions/empty_interface_codec_options.go +++ /dev/null @@ -1,49 +0,0 @@ -// 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. -// -// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal -// and unmarshal behavior instead. -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 -// -// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal -// and unmarshal behavior instead. -func EmptyInterfaceCodec() *EmptyInterfaceCodecOptions { - return &EmptyInterfaceCodecOptions{} -} - -// SetDecodeBinaryAsSlice specifies if Old and Generic type binarys should default to []slice instead of primitive.Binary. Defaults to false. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Decoder.BinaryAsSlice] instead. -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. -// -// Deprecated: Merging options structs will not be supported in Go Driver 2.0. Users should create a -// single options struct instead. -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/bson/bsonoptions/map_codec_options.go b/bson/bsonoptions/map_codec_options.go deleted file mode 100644 index a7a7c1d980..0000000000 --- a/bson/bsonoptions/map_codec_options.go +++ /dev/null @@ -1,82 +0,0 @@ -// 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. -// -// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal -// and unmarshal behavior instead. -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 -// -// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal -// and unmarshal behavior instead. -func MapCodec() *MapCodecOptions { - return &MapCodecOptions{} -} - -// SetDecodeZerosMap specifies if the map should be zeroed before decoding into it. Defaults to false. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Decoder.ZeroMaps] instead. -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. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.NilMapAsEmpty] instead. -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. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.StringifyMapKeysWithFmt] instead. -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. -// -// Deprecated: Merging options structs will not be supported in Go Driver 2.0. Users should create a -// single options struct instead. -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/bson/bsonoptions/slice_codec_options.go b/bson/bsonoptions/slice_codec_options.go deleted file mode 100644 index 3c1e4f35ba..0000000000 --- a/bson/bsonoptions/slice_codec_options.go +++ /dev/null @@ -1,49 +0,0 @@ -// 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. -// -// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal -// and unmarshal behavior instead. -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 -// -// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal -// and unmarshal behavior instead. -func SliceCodec() *SliceCodecOptions { - return &SliceCodecOptions{} -} - -// SetEncodeNilAsEmpty specifies if a nil slice should encode as an empty array instead of null. Defaults to false. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.NilSliceAsEmpty] instead. -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. -// -// Deprecated: Merging options structs will not be supported in Go Driver 2.0. Users should create a -// single options struct instead. -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/bson/bsonoptions/string_codec_options.go b/bson/bsonoptions/string_codec_options.go deleted file mode 100644 index f8b76f996e..0000000000 --- a/bson/bsonoptions/string_codec_options.go +++ /dev/null @@ -1,52 +0,0 @@ -// 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. -// -// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal -// and unmarshal behavior instead. -type StringCodecOptions struct { - DecodeObjectIDAsHex *bool // Specifies if we should decode ObjectID as the hex value. Defaults to true. -} - -// StringCodec creates a new *StringCodecOptions -// -// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal -// and unmarshal behavior instead. -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. -// -// Deprecated: Decoding object IDs as raw bytes will not be supported in Go Driver 2.0. -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. -// -// Deprecated: Merging options structs will not be supported in Go Driver 2.0. Users should create a -// single options struct instead. -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/bson/bsonoptions/struct_codec_options.go b/bson/bsonoptions/struct_codec_options.go deleted file mode 100644 index 1cbfa32e8b..0000000000 --- a/bson/bsonoptions/struct_codec_options.go +++ /dev/null @@ -1,107 +0,0 @@ -// 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. -// -// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal -// and unmarshal behavior instead. -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 -// -// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal -// and unmarshal behavior instead. -func StructCodec() *StructCodecOptions { - return &StructCodecOptions{} -} - -// SetDecodeZeroStruct specifies if structs should be zeroed before decoding into them. Defaults to false. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Decoder.ZeroStructs] instead. -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. -// -// Deprecated: DecodeDeepZeroInline will not be supported in Go Driver 2.0. -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. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.OmitZeroStruct] instead. -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. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.ErrorOnInlineDuplicates] instead. -func (t *StructCodecOptions) SetOverwriteDuplicatedInlinedFields(b bool) *StructCodecOptions { - t.OverwriteDuplicatedInlinedFields = &b - return t -} - -// SetAllowUnexportedFields specifies if unexported fields should be marshaled/unmarshaled. Defaults to false. -// -// Deprecated: AllowUnexportedFields does not work on recent versions of Go and will not be -// supported in Go Driver 2.0. -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. -// -// Deprecated: Merging options structs will not be supported in Go Driver 2.0. Users should create a -// single options struct instead. -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/bson/bsonoptions/time_codec_options.go b/bson/bsonoptions/time_codec_options.go deleted file mode 100644 index 3f38433d22..0000000000 --- a/bson/bsonoptions/time_codec_options.go +++ /dev/null @@ -1,49 +0,0 @@ -// 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. -// -// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal -// and unmarshal behavior instead. -type TimeCodecOptions struct { - UseLocalTimeZone *bool // Specifies if we should decode into the local time zone. Defaults to false. -} - -// TimeCodec creates a new *TimeCodecOptions -// -// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal -// and unmarshal behavior instead. -func TimeCodec() *TimeCodecOptions { - return &TimeCodecOptions{} -} - -// SetUseLocalTimeZone specifies if we should decode into the local time zone. Defaults to false. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Decoder.UseLocalTimeZone] instead. -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. -// -// Deprecated: Merging options structs will not be supported in Go Driver 2.0. Users should create a -// single options struct instead. -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/bson/bsonoptions/uint_codec_options.go b/bson/bsonoptions/uint_codec_options.go deleted file mode 100644 index 5091e4d963..0000000000 --- a/bson/bsonoptions/uint_codec_options.go +++ /dev/null @@ -1,49 +0,0 @@ -// 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. -// -// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal -// and unmarshal behavior instead. -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 -// -// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal -// and unmarshal behavior instead. -func UIntCodec() *UIntCodecOptions { - return &UIntCodecOptions{} -} - -// SetEncodeToMinSize specifies if all uints except uint64 should be decoded to minimum size bsontype. Defaults to false. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.IntMinSize] instead. -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. -// -// Deprecated: Merging options structs will not be supported in Go Driver 2.0. Users should create a -// single options struct instead. -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/bson/byte_slice_codec.go b/bson/byte_slice_codec.go index 586c006467..bd5c5dae85 100644 --- a/bson/byte_slice_codec.go +++ b/bson/byte_slice_codec.go @@ -9,56 +9,32 @@ package bson import ( "fmt" "reflect" - - "go.mongodb.org/mongo-driver/bson/bsonoptions" ) -// ByteSliceCodec is the Codec used for []byte values. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the -// ByteSliceCodec registered. -type ByteSliceCodec struct { - // EncodeNilAsEmpty causes EncodeValue to marshal nil Go byte slices as empty BSON binary values +// byteSliceCodec is the Codec used for []byte values. +type byteSliceCodec struct { + // encodeNilAsEmpty causes EncodeValue to marshal nil Go byte slices as empty BSON binary values // instead of BSON null. - // - // Deprecated: Use bson.Encoder.NilByteSliceAsEmpty instead. - EncodeNilAsEmpty bool + encodeNilAsEmpty bool } -var ( - defaultByteSliceCodec = NewByteSliceCodec() - - // Assert that defaultByteSliceCodec satisfies the typeDecoder interface, which allows it to be - // used by collection type decoders (e.g. map, slice, etc) to set individual values in a - // collection. - _ typeDecoder = defaultByteSliceCodec -) - -// NewByteSliceCodec returns a ByteSliceCodec with options opts. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the -// ByteSliceCodec registered. -func NewByteSliceCodec(opts ...*bsonoptions.ByteSliceCodecOptions) *ByteSliceCodec { - byteSliceOpt := bsonoptions.MergeByteSliceCodecOptions(opts...) - codec := ByteSliceCodec{} - if byteSliceOpt.EncodeNilAsEmpty != nil { - codec.EncodeNilAsEmpty = *byteSliceOpt.EncodeNilAsEmpty - } - return &codec -} +// Assert that defaultByteSliceCodec satisfies the typeDecoder interface, which allows it to be +// used by collection type decoders (e.g. map, slice, etc) to set individual values in a +// collection. +var _ typeDecoder = (*byteSliceCodec)(nil) // EncodeValue is the ValueEncoder for []byte. -func (bsc *ByteSliceCodec) EncodeValue(ec EncodeContext, vw ValueWriter, val reflect.Value) error { +func (bsc *byteSliceCodec) EncodeValue(ec EncodeContext, vw 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 && !ec.nilByteSliceAsEmpty { + if val.IsNil() && !bsc.encodeNilAsEmpty && !ec.nilByteSliceAsEmpty { return vw.WriteNull() } return vw.WriteBinary(val.Interface().([]byte)) } -func (bsc *ByteSliceCodec) decodeType(_ DecodeContext, vr ValueReader, t reflect.Type) (reflect.Value, error) { +func (bsc *byteSliceCodec) decodeType(_ DecodeContext, vr ValueReader, t reflect.Type) (reflect.Value, error) { if t != tByteSlice { return emptyValue, ValueDecoderError{ Name: "ByteSliceDecodeValue", @@ -106,7 +82,7 @@ func (bsc *ByteSliceCodec) decodeType(_ DecodeContext, vr ValueReader, t reflect } // DecodeValue is the ValueDecoder for []byte. -func (bsc *ByteSliceCodec) DecodeValue(dc DecodeContext, vr ValueReader, val reflect.Value) error { +func (bsc *byteSliceCodec) DecodeValue(dc DecodeContext, vr ValueReader, val reflect.Value) error { if !val.CanSet() || val.Type() != tByteSlice { return ValueDecoderError{Name: "ByteSliceDecodeValue", Types: []reflect.Type{tByteSlice}, Received: val} } diff --git a/bson/cond_addr_codec.go b/bson/cond_addr_codec.go index fba139ff07..26eed212f1 100644 --- a/bson/cond_addr_codec.go +++ b/bson/cond_addr_codec.go @@ -18,12 +18,6 @@ type condAddrEncoder struct { 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 ValueWriter, val reflect.Value) error { if val.CanAddr() { diff --git a/bson/cond_addr_codec_test.go b/bson/cond_addr_codec_test.go index c22c29fe72..55d73e8204 100644 --- a/bson/cond_addr_codec_test.go +++ b/bson/cond_addr_codec_test.go @@ -30,7 +30,7 @@ func TestCondAddrCodec(t *testing.T) { invoked = 2 return nil }) - condEncoder := newCondAddrEncoder(encode1, encode2) + condEncoder := &condAddrEncoder{canAddrEnc: encode1, elseEnc: encode2} testCases := []struct { name string @@ -50,7 +50,7 @@ func TestCondAddrCodec(t *testing.T) { } t.Run("error", func(t *testing.T) { - errEncoder := newCondAddrEncoder(encode1, nil) + errEncoder := &condAddrEncoder{canAddrEnc: encode1, elseEnc: nil} err := errEncoder.EncodeValue(EncodeContext{}, rw, unaddressable) want := ErrNoEncoder{Type: unaddressable.Type()} assert.Equal(t, err, want, "expected error %v, got %v", want, err) diff --git a/bson/default_value_decoders.go b/bson/default_value_decoders.go index e4ea1f394e..5ad52e19e2 100644 --- a/bson/default_value_decoders.go +++ b/bson/default_value_decoders.go @@ -31,16 +31,6 @@ 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: %w", err)) - } - return codec -} - // registerDefaultDecoders will register the default decoder methods with the provided Registry. // // There is no support for decoding map[string]interface{} because there is no decoder for @@ -66,10 +56,10 @@ func registerDefaultDecoders(reg *Registry) { reg.RegisterTypeDecoder(tMaxKey, decodeAdapter{maxKeyDecodeValue, maxKeyDecodeType}) reg.RegisterTypeDecoder(tJavaScript, decodeAdapter{javaScriptDecodeValue, javaScriptDecodeType}) reg.RegisterTypeDecoder(tSymbol, decodeAdapter{symbolDecodeValue, symbolDecodeType}) - reg.RegisterTypeDecoder(tByteSlice, defaultByteSliceCodec) - reg.RegisterTypeDecoder(tTime, defaultTimeCodec) - reg.RegisterTypeDecoder(tEmpty, defaultEmptyInterfaceCodec) - reg.RegisterTypeDecoder(tCoreArray, defaultArrayCodec) + reg.RegisterTypeDecoder(tByteSlice, &byteSliceCodec{}) + reg.RegisterTypeDecoder(tTime, &timeCodec{}) + reg.RegisterTypeDecoder(tEmpty, &emptyInterfaceCodec{}) + reg.RegisterTypeDecoder(tCoreArray, &arrayCodec{}) reg.RegisterTypeDecoder(tOID, decodeAdapter{objectIDDecodeValue, objectIDDecodeType}) reg.RegisterTypeDecoder(tDecimal, decodeAdapter{decimal128DecodeValue, decimal128DecodeType}) reg.RegisterTypeDecoder(tJSONNumber, decodeAdapter{jsonNumberDecodeValue, jsonNumberDecodeType}) @@ -82,19 +72,19 @@ func registerDefaultDecoders(reg *Registry) { reg.RegisterKindDecoder(reflect.Int16, intDecoder) reg.RegisterKindDecoder(reflect.Int32, intDecoder) reg.RegisterKindDecoder(reflect.Int64, intDecoder) - reg.RegisterKindDecoder(reflect.Uint, defaultUIntCodec) - reg.RegisterKindDecoder(reflect.Uint8, defaultUIntCodec) - reg.RegisterKindDecoder(reflect.Uint16, defaultUIntCodec) - reg.RegisterKindDecoder(reflect.Uint32, defaultUIntCodec) - reg.RegisterKindDecoder(reflect.Uint64, defaultUIntCodec) + reg.RegisterKindDecoder(reflect.Uint, &uintCodec{}) + reg.RegisterKindDecoder(reflect.Uint8, &uintCodec{}) + reg.RegisterKindDecoder(reflect.Uint16, &uintCodec{}) + reg.RegisterKindDecoder(reflect.Uint32, &uintCodec{}) + reg.RegisterKindDecoder(reflect.Uint64, &uintCodec{}) reg.RegisterKindDecoder(reflect.Float32, floatDecoder) reg.RegisterKindDecoder(reflect.Float64, floatDecoder) reg.RegisterKindDecoder(reflect.Array, ValueDecoderFunc(arrayDecodeValue)) - reg.RegisterKindDecoder(reflect.Map, defaultMapCodec) - reg.RegisterKindDecoder(reflect.Slice, defaultSliceCodec) - reg.RegisterKindDecoder(reflect.String, defaultStringCodec) - reg.RegisterKindDecoder(reflect.Struct, newDefaultStructCodec()) - reg.RegisterKindDecoder(reflect.Ptr, NewPointerCodec()) + reg.RegisterKindDecoder(reflect.Map, &mapCodec{}) + reg.RegisterKindDecoder(reflect.Slice, &sliceCodec{}) + reg.RegisterKindDecoder(reflect.String, &stringCodec{}) + reg.RegisterKindDecoder(reflect.Struct, newStructCodec(DefaultStructTagParser)) + reg.RegisterKindDecoder(reflect.Ptr, &pointerCodec{}) reg.RegisterTypeMapEntry(TypeDouble, tFloat64) reg.RegisterTypeMapEntry(TypeString, tString) reg.RegisterTypeMapEntry(TypeArray, tA) diff --git a/bson/default_value_decoders_test.go b/bson/default_value_decoders_test.go index 56fdc464c2..25165edcb5 100644 --- a/bson/default_value_decoders_test.go +++ b/bson/default_value_decoders_test.go @@ -23,7 +23,7 @@ import ( ) var ( - defaultTestStructCodec = newDefaultStructCodec() + defaultTestStructCodec = newStructCodec(DefaultStructTagParser) ) func TestDefaultValueDecoders(t *testing.T) { @@ -371,7 +371,7 @@ func TestDefaultValueDecoders(t *testing.T) { }, { "defaultUIntCodec.DecodeValue", - defaultUIntCodec, + &uintCodec{}, []subtest{ { "wrong type", @@ -736,7 +736,7 @@ func TestDefaultValueDecoders(t *testing.T) { }, { "defaultTimeCodec.DecodeValue", - defaultTimeCodec, + &timeCodec{}, []subtest{ { "wrong type", @@ -790,7 +790,7 @@ func TestDefaultValueDecoders(t *testing.T) { }, { "defaultMapCodec.DecodeValue", - defaultMapCodec, + &mapCodec{}, []subtest{ { "wrong kind", @@ -962,7 +962,7 @@ func TestDefaultValueDecoders(t *testing.T) { }, { "defaultSliceCodec.DecodeValue", - defaultSliceCodec, + &sliceCodec{}, []subtest{ { "wrong kind", @@ -1373,7 +1373,7 @@ func TestDefaultValueDecoders(t *testing.T) { }, { "defaultByteSliceCodec.DecodeValue", - defaultByteSliceCodec, + &byteSliceCodec{}, []subtest{ { "wrong type", @@ -1441,7 +1441,7 @@ func TestDefaultValueDecoders(t *testing.T) { }, { "defaultStringCodec.DecodeValue", - defaultStringCodec, + &stringCodec{}, []subtest{ { "symbol", @@ -1550,7 +1550,7 @@ func TestDefaultValueDecoders(t *testing.T) { }, { "PointerCodec.DecodeValue", - NewPointerCodec(), + &pointerCodec{}, []subtest{ { "not valid", nil, nil, nil, nothing, @@ -2312,7 +2312,7 @@ func TestDefaultValueDecoders(t *testing.T) { }, { "CoreArrayDecodeValue", - defaultArrayCodec, + &arrayCodec{}, []subtest{ { "wrong type", @@ -3195,6 +3195,7 @@ func TestDefaultValueDecoders(t *testing.T) { }) t.Run("defaultEmptyInterfaceCodec.DecodeValue", func(t *testing.T) { + defaultEmptyInterfaceCodec := &emptyInterfaceCodec{} t.Run("DecodeValue", func(t *testing.T) { testCases := []struct { name string @@ -3486,7 +3487,7 @@ func TestDefaultValueDecoders(t *testing.T) { var got D vr := NewValueReader(doc) val := reflect.ValueOf(&got).Elem() - err := defaultSliceCodec.DecodeValue(DecodeContext{Registry: reg}, vr, val) + err := (&sliceCodec{}).DecodeValue(DecodeContext{Registry: reg}, vr, val) noerr(t, err) if !cmp.Equal(got, want) { t.Fatalf("got %v, want %v", got, want) @@ -3574,7 +3575,7 @@ func TestDefaultValueDecoders(t *testing.T) { D{}, NewValueReader(docBytes), emptyInterfaceErrorRegistry, - defaultSliceCodec, + &sliceCodec{}, docEmptyInterfaceErr, }, { @@ -3583,7 +3584,7 @@ func TestDefaultValueDecoders(t *testing.T) { []string{}, &valueReaderWriter{BSONType: TypeArray}, nil, - defaultSliceCodec, + &sliceCodec{}, &DecodeError{ keys: []string{"0"}, wrapped: errors.New("cannot decode array into a string type"), @@ -3620,7 +3621,7 @@ func TestDefaultValueDecoders(t *testing.T) { map[string]interface{}{}, NewValueReader(docBytes), emptyInterfaceErrorRegistry, - defaultMapCodec, + &mapCodec{}, docEmptyInterfaceErr, }, { @@ -3730,7 +3731,7 @@ func TestDefaultValueDecoders(t *testing.T) { dc := DecodeContext{Registry: buildDefaultRegistry()} vr := NewValueReader(docBytes) val := reflect.New(reflect.TypeOf(myMap{})).Elem() - err := defaultMapCodec.DecodeValue(dc, vr, val) + err := (&mapCodec{}).DecodeValue(dc, vr, val) assert.Nil(t, err, "DecodeValue error: %v", err) want := myMap{ diff --git a/bson/default_value_encoders.go b/bson/default_value_encoders.go index 6b28f1594b..6b2ff14f61 100644 --- a/bson/default_value_encoders.go +++ b/bson/default_value_encoders.go @@ -54,10 +54,10 @@ func registerDefaultEncoders(reg *Registry) { if reg == nil { panic(errors.New("argument to RegisterDefaultEncoders must not be nil")) } - reg.RegisterTypeEncoder(tByteSlice, defaultByteSliceCodec) - reg.RegisterTypeEncoder(tTime, defaultTimeCodec) - reg.RegisterTypeEncoder(tEmpty, defaultEmptyInterfaceCodec) - reg.RegisterTypeEncoder(tCoreArray, defaultArrayCodec) + reg.RegisterTypeEncoder(tByteSlice, &byteSliceCodec{}) + reg.RegisterTypeEncoder(tTime, &timeCodec{}) + reg.RegisterTypeEncoder(tEmpty, &emptyInterfaceCodec{}) + reg.RegisterTypeEncoder(tCoreArray, &arrayCodec{}) reg.RegisterTypeEncoder(tOID, ValueEncoderFunc(objectIDEncodeValue)) reg.RegisterTypeEncoder(tDecimal, ValueEncoderFunc(decimal128EncodeValue)) reg.RegisterTypeEncoder(tJSONNumber, ValueEncoderFunc(jsonNumberEncodeValue)) @@ -81,19 +81,19 @@ func registerDefaultEncoders(reg *Registry) { reg.RegisterKindEncoder(reflect.Int16, ValueEncoderFunc(intEncodeValue)) reg.RegisterKindEncoder(reflect.Int32, ValueEncoderFunc(intEncodeValue)) reg.RegisterKindEncoder(reflect.Int64, ValueEncoderFunc(intEncodeValue)) - reg.RegisterKindEncoder(reflect.Uint, defaultUIntCodec) - reg.RegisterKindEncoder(reflect.Uint8, defaultUIntCodec) - reg.RegisterKindEncoder(reflect.Uint16, defaultUIntCodec) - reg.RegisterKindEncoder(reflect.Uint32, defaultUIntCodec) - reg.RegisterKindEncoder(reflect.Uint64, defaultUIntCodec) + reg.RegisterKindEncoder(reflect.Uint, &uintCodec{}) + reg.RegisterKindEncoder(reflect.Uint8, &uintCodec{}) + reg.RegisterKindEncoder(reflect.Uint16, &uintCodec{}) + reg.RegisterKindEncoder(reflect.Uint32, &uintCodec{}) + reg.RegisterKindEncoder(reflect.Uint64, &uintCodec{}) reg.RegisterKindEncoder(reflect.Float32, ValueEncoderFunc(floatEncodeValue)) reg.RegisterKindEncoder(reflect.Float64, ValueEncoderFunc(floatEncodeValue)) reg.RegisterKindEncoder(reflect.Array, ValueEncoderFunc(arrayEncodeValue)) - reg.RegisterKindEncoder(reflect.Map, defaultMapCodec) - reg.RegisterKindEncoder(reflect.Slice, defaultSliceCodec) - reg.RegisterKindEncoder(reflect.String, defaultStringCodec) - reg.RegisterKindEncoder(reflect.Struct, newDefaultStructCodec()) - reg.RegisterKindEncoder(reflect.Ptr, NewPointerCodec()) + reg.RegisterKindEncoder(reflect.Map, &mapCodec{}) + reg.RegisterKindEncoder(reflect.Slice, &sliceCodec{}) + reg.RegisterKindEncoder(reflect.String, &stringCodec{}) + reg.RegisterKindEncoder(reflect.Struct, newStructCodec(DefaultStructTagParser)) + reg.RegisterKindEncoder(reflect.Ptr, &pointerCodec{}) reg.RegisterInterfaceEncoder(tValueMarshaler, ValueEncoderFunc(valueMarshalerEncodeValue)) reg.RegisterInterfaceEncoder(tMarshaler, ValueEncoderFunc(marshalerEncodeValue)) reg.RegisterInterfaceEncoder(tProxy, ValueEncoderFunc(proxyEncodeValue)) diff --git a/bson/default_value_encoders_test.go b/bson/default_value_encoders_test.go index 1ebd57f891..797a77322a 100644 --- a/bson/default_value_encoders_test.go +++ b/bson/default_value_encoders_test.go @@ -135,7 +135,7 @@ func TestDefaultValueEncoders(t *testing.T) { }, { "UintEncodeValue", - defaultUIntCodec, + &uintCodec{}, []subtest{ { "wrong type", @@ -198,7 +198,7 @@ func TestDefaultValueEncoders(t *testing.T) { }, { "TimeEncodeValue", - defaultTimeCodec, + &timeCodec{}, []subtest{ { "wrong type", @@ -213,7 +213,7 @@ func TestDefaultValueEncoders(t *testing.T) { }, { "MapEncodeValue", - defaultMapCodec, + &mapCodec{}, []subtest{ { "wrong kind", @@ -371,7 +371,7 @@ func TestDefaultValueEncoders(t *testing.T) { }, { "SliceEncodeValue", - defaultSliceCodec, + &sliceCodec{}, []subtest{ { "wrong kind", @@ -535,7 +535,7 @@ func TestDefaultValueEncoders(t *testing.T) { }, { "ByteSliceEncodeValue", - defaultByteSliceCodec, + &byteSliceCodec{}, []subtest{ { "wrong type", @@ -551,7 +551,7 @@ func TestDefaultValueEncoders(t *testing.T) { }, { "EmptyInterfaceEncodeValue", - defaultEmptyInterfaceCodec, + &emptyInterfaceCodec{}, []subtest{ { "wrong type", @@ -775,7 +775,7 @@ func TestDefaultValueEncoders(t *testing.T) { }, { "PointerCodec.EncodeValue", - NewPointerCodec(), + &pointerCodec{}, []subtest{ { "nil", @@ -791,7 +791,7 @@ func TestDefaultValueEncoders(t *testing.T) { nil, nil, nothing, - ValueEncoderError{Name: "PointerCodec.EncodeValue", Kinds: []reflect.Kind{reflect.Ptr}, Received: reflect.ValueOf(int32(123456))}, + ValueEncoderError{Name: "pointerCodec.EncodeValue", Kinds: []reflect.Kind{reflect.Ptr}, Received: reflect.ValueOf(int32(123456))}, }, { "typed nil", @@ -813,7 +813,7 @@ func TestDefaultValueEncoders(t *testing.T) { }, { "pointer implementation addressable interface", - NewPointerCodec(), + &pointerCodec{}, []subtest{ { "ValueMarshaler", @@ -1073,7 +1073,7 @@ func TestDefaultValueEncoders(t *testing.T) { }, { "StructEncodeValue", - defaultTestStructCodec, + newStructCodec(DefaultStructTagParser), []subtest{ { "interface value", @@ -1130,7 +1130,7 @@ func TestDefaultValueEncoders(t *testing.T) { }, { "CoreArrayEncodeValue", - defaultArrayCodec, + &arrayCodec{}, []subtest{ { "wrong type", diff --git a/bson/empty_interface_codec.go b/bson/empty_interface_codec.go index 56468e3068..da9efdded3 100644 --- a/bson/empty_interface_codec.go +++ b/bson/empty_interface_codec.go @@ -8,47 +8,22 @@ package bson import ( "reflect" - - "go.mongodb.org/mongo-driver/bson/bsonoptions" ) -// EmptyInterfaceCodec is the Codec used for interface{} values. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the -// EmptyInterfaceCodec registered. -type EmptyInterfaceCodec struct { - // DecodeBinaryAsSlice causes DecodeValue to unmarshal BSON binary field values that are the +// emptyInterfaceCodec is the Codec used for interface{} values. +type emptyInterfaceCodec struct { + // decodeBinaryAsSlice causes DecodeValue to unmarshal BSON binary field values that are the // "Generic" or "Old" BSON binary subtype as a Go byte slice instead of a Binary. - // - // Deprecated: Use bson.Decoder.BinaryAsSlice instead. - DecodeBinaryAsSlice bool + decodeBinaryAsSlice bool } -var ( - defaultEmptyInterfaceCodec = NewEmptyInterfaceCodec() - - // Assert that defaultEmptyInterfaceCodec satisfies the typeDecoder interface, which allows it - // to be used by collection type decoders (e.g. map, slice, etc) to set individual values in a - // collection. - _ typeDecoder = defaultEmptyInterfaceCodec -) - -// NewEmptyInterfaceCodec returns a EmptyInterfaceCodec with options opts. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the -// EmptyInterfaceCodec registered. -func NewEmptyInterfaceCodec(opts ...*bsonoptions.EmptyInterfaceCodecOptions) *EmptyInterfaceCodec { - interfaceOpt := bsonoptions.MergeEmptyInterfaceCodecOptions(opts...) - - codec := EmptyInterfaceCodec{} - if interfaceOpt.DecodeBinaryAsSlice != nil { - codec.DecodeBinaryAsSlice = *interfaceOpt.DecodeBinaryAsSlice - } - return &codec -} +// Assert that defaultEmptyInterfaceCodec satisfies the typeDecoder interface, which allows it +// to be used by collection type decoders (e.g. map, slice, etc) to set individual values in a +// collection. +var _ typeDecoder = (*emptyInterfaceCodec)(nil) // EncodeValue is the ValueEncoderFunc for interface{}. -func (eic EmptyInterfaceCodec) EncodeValue(ec EncodeContext, vw ValueWriter, val reflect.Value) error { +func (eic emptyInterfaceCodec) EncodeValue(ec EncodeContext, vw ValueWriter, val reflect.Value) error { if !val.IsValid() || val.Type() != tEmpty { return ValueEncoderError{Name: "EmptyInterfaceEncodeValue", Types: []reflect.Type{tEmpty}, Received: val} } @@ -64,7 +39,7 @@ func (eic EmptyInterfaceCodec) EncodeValue(ec EncodeContext, vw ValueWriter, val return encoder.EncodeValue(ec, vw, val.Elem()) } -func (eic EmptyInterfaceCodec) getEmptyInterfaceDecodeType(dc DecodeContext, valueType Type) (reflect.Type, error) { +func (eic emptyInterfaceCodec) getEmptyInterfaceDecodeType(dc DecodeContext, valueType Type) (reflect.Type, error) { isDocument := valueType == Type(0) || valueType == TypeEmbeddedDocument if isDocument { if dc.defaultDocumentType != nil { @@ -105,7 +80,7 @@ func (eic EmptyInterfaceCodec) getEmptyInterfaceDecodeType(dc DecodeContext, val return nil, err } -func (eic EmptyInterfaceCodec) decodeType(dc DecodeContext, vr ValueReader, t reflect.Type) (reflect.Value, error) { +func (eic emptyInterfaceCodec) decodeType(dc DecodeContext, vr ValueReader, t reflect.Type) (reflect.Value, error) { if t != tEmpty { return emptyValue, ValueDecoderError{Name: "EmptyInterfaceDecodeValue", Types: []reflect.Type{tEmpty}, Received: reflect.Zero(t)} } @@ -130,7 +105,7 @@ func (eic EmptyInterfaceCodec) decodeType(dc DecodeContext, vr ValueReader, t re return emptyValue, err } - if (eic.DecodeBinaryAsSlice || dc.binaryAsSlice) && rtype == tBinary { + if (eic.decodeBinaryAsSlice || dc.binaryAsSlice) && rtype == tBinary { binElem := elem.Interface().(Binary) if binElem.Subtype == TypeBinaryGeneric || binElem.Subtype == TypeBinaryBinaryOld { elem = reflect.ValueOf(binElem.Data) @@ -141,7 +116,7 @@ func (eic EmptyInterfaceCodec) decodeType(dc DecodeContext, vr ValueReader, t re } // DecodeValue is the ValueDecoderFunc for interface{}. -func (eic EmptyInterfaceCodec) DecodeValue(dc DecodeContext, vr ValueReader, val reflect.Value) error { +func (eic emptyInterfaceCodec) DecodeValue(dc DecodeContext, vr ValueReader, val reflect.Value) error { if !val.CanSet() || val.Type() != tEmpty { return ValueDecoderError{Name: "EmptyInterfaceDecodeValue", Types: []reflect.Type{tEmpty}, Received: val} } diff --git a/bson/map_codec.go b/bson/map_codec.go index f1294ae99d..e11ffaf726 100644 --- a/bson/map_codec.go +++ b/bson/map_codec.go @@ -12,34 +12,21 @@ import ( "fmt" "reflect" "strconv" - - "go.mongodb.org/mongo-driver/bson/bsonoptions" ) -var defaultMapCodec = NewMapCodec() - -// MapCodec is the Codec used for map values. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the -// MapCodec registered. -type MapCodec struct { - // DecodeZerosMap causes DecodeValue to delete any existing values from Go maps in the destination +// mapCodec is the Codec used for map values. +type mapCodec struct { + // decodeZerosMap causes DecodeValue to delete any existing values from Go maps in the destination // value passed to Decode before unmarshaling BSON documents into them. - // - // Deprecated: Use bson.Decoder.ZeroMaps instead. - DecodeZerosMap bool + decodeZerosMap bool - // EncodeNilAsEmpty causes EncodeValue to marshal nil Go maps as empty BSON documents instead of + // encodeNilAsEmpty causes EncodeValue to marshal nil Go maps as empty BSON documents instead of // BSON null. - // - // Deprecated: Use bson.Encoder.NilMapAsEmpty instead. - EncodeNilAsEmpty bool + encodeNilAsEmpty bool - // EncodeKeysWithStringer causes the Encoder to convert Go map keys to BSON document field name + // encodeKeysWithStringer causes the Encoder to convert Go map keys to BSON document field name // strings using fmt.Sprintf() instead of the default string conversion logic. - // - // Deprecated: Use bson.Encoder.StringifyMapKeysWithFmt instead. - EncodeKeysWithStringer bool + encodeKeysWithStringer bool } // KeyMarshaler is the interface implemented by an object that can marshal itself into a string key. @@ -58,33 +45,13 @@ type KeyUnmarshaler interface { UnmarshalKey(key string) error } -// NewMapCodec returns a MapCodec with options opts. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the -// MapCodec registered. -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 ValueWriter, val reflect.Value) error { +func (mc *mapCodec) EncodeValue(ec EncodeContext, vw 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 && !ec.nilMapAsEmpty { + if val.IsNil() && !mc.encodeNilAsEmpty && !ec.nilMapAsEmpty { // 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, @@ -107,7 +74,7 @@ func (mc *MapCodec) EncodeValue(ec EncodeContext, vw ValueWriter, val reflect.Va // 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 DocumentWriter, val reflect.Value, collisionFn func(string) bool) error { +func (mc *mapCodec) mapEncodeValue(ec EncodeContext, dw DocumentWriter, val reflect.Value, collisionFn func(string) bool) error { elemType := val.Type().Elem() encoder, err := ec.LookupEncoder(elemType) @@ -154,7 +121,7 @@ func (mc *MapCodec) mapEncodeValue(ec EncodeContext, dw DocumentWriter, val refl } // DecodeValue is the ValueDecoder for map[string/decimal]* types. -func (mc *MapCodec) DecodeValue(dc DecodeContext, vr ValueReader, val reflect.Value) error { +func (mc *mapCodec) DecodeValue(dc DecodeContext, vr 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} } @@ -180,7 +147,7 @@ func (mc *MapCodec) DecodeValue(dc DecodeContext, vr ValueReader, val reflect.Va val.Set(reflect.MakeMap(val.Type())) } - if val.Len() > 0 && (mc.DecodeZerosMap || dc.zeroMaps) { + if val.Len() > 0 && (mc.decodeZerosMap || dc.zeroMaps) { clearMap(val) } @@ -228,8 +195,8 @@ func clearMap(m reflect.Value) { } } -func (mc *MapCodec) encodeKey(val reflect.Value, encodeKeysWithStringer bool) (string, error) { - if mc.EncodeKeysWithStringer || encodeKeysWithStringer { +func (mc *mapCodec) encodeKey(val reflect.Value, encodeKeysWithStringer bool) (string, error) { + if mc.encodeKeysWithStringer || encodeKeysWithStringer { return fmt.Sprint(val), nil } @@ -274,12 +241,12 @@ func (mc *MapCodec) encodeKey(val reflect.Value, encodeKeysWithStringer bool) (s 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) { +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): + case !mc.encodeKeysWithStringer && reflect.PtrTo(keyType).Implements(keyUnmarshalerType): keyVal = reflect.New(keyType) v := keyVal.Interface().(KeyUnmarshaler) err = v.UnmarshalKey(key) @@ -309,7 +276,7 @@ func (mc *MapCodec) decodeKey(key string, keyType reflect.Type) (reflect.Value, } keyVal = reflect.ValueOf(n).Convert(keyType) case reflect.Float32, reflect.Float64: - if mc.EncodeKeysWithStringer { + 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 %w", keyType.Kind(), err) diff --git a/bson/mgocompat/bson_test.go b/bson/mgocompat/bson_test.go index a74a5a892d..7571abb19f 100644 --- a/bson/mgocompat/bson_test.go +++ b/bson/mgocompat/bson_test.go @@ -471,7 +471,7 @@ func (t *prefixPtr) GetBSON() (interface{}, error) { func (t *prefixPtr) SetBSON(raw bson.RawValue) error { var s string if raw.Type == 0x0A { - return ErrSetZero + return bson.ErrSetZero } rval := reflect.ValueOf(&s).Elem() decoder, err := Registry.LookupDecoder(rval.Type()) @@ -498,7 +498,7 @@ func (t prefixVal) GetBSON() (interface{}, error) { func (t *prefixVal) SetBSON(raw bson.RawValue) error { var s string if raw.Type == 0x0A { - return ErrSetZero + return bson.ErrSetZero } rval := reflect.ValueOf(&s).Elem() decoder, err := Registry.LookupDecoder(rval.Type()) @@ -1026,7 +1026,7 @@ func TestDMap(t *testing.T) { } func TestUnmarshalSetterErrSetZero(t *testing.T) { - setterResult["foo"] = ErrSetZero + setterResult["foo"] = bson.ErrSetZero defer delete(setterResult, "field") buf := new(bytes.Buffer) diff --git a/bson/mgocompat/doc.go b/bson/mgocompat/doc.go index 8a9434b1d1..a1c91aff4c 100644 --- a/bson/mgocompat/doc.go +++ b/bson/mgocompat/doc.go @@ -9,11 +9,6 @@ // with mgo's BSON with RespectNilValues set to true. A registry can be configured on a // mongo.Client with the SetRegistry option. See the bson docs for more details on registries. // -// Registry supports Getter and Setter equivalents by registering hooks. Note that if a value -// matches the hook for bson.Marshaler, bson.ValueMarshaler, or bson.Proxy, that -// hook will take priority over the Getter hook. The same is true for the hooks for -// bson.Unmarshaler and bson.ValueUnmarshaler and the Setter hook. -// // The functional differences between Registry and globalsign/mgo's BSON library are: // // 1) Registry errors instead of silently skipping mismatched types when decoding. diff --git a/bson/mgocompat/registry.go b/bson/mgocompat/registry.go index 0d61a029ec..7ffb90b22e 100644 --- a/bson/mgocompat/registry.go +++ b/bson/mgocompat/registry.go @@ -7,101 +7,12 @@ package mgocompat import ( - "errors" - "reflect" - "time" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/bsonoptions" -) - -var ( - // ErrSetZero may be returned from a SetBSON method to have the value set to its respective zero value. - ErrSetZero = errors.New("set to zero") - - tInt = reflect.TypeOf(int(0)) - tTime = reflect.TypeOf(time.Time{}) - tM = reflect.TypeOf(bson.M{}) - tInterfaceSlice = reflect.TypeOf([]interface{}{}) - tByteSlice = reflect.TypeOf([]byte{}) - tEmpty = reflect.TypeOf((*interface{})(nil)).Elem() - tGetter = reflect.TypeOf((*Getter)(nil)).Elem() - tSetter = reflect.TypeOf((*Setter)(nil)).Elem() ) // Registry is the mgo compatible bson.Registry. It contains the default and // primitive codecs with mgo compatible options. -var Registry = newRegistry() +var Registry = bson.NewMgoRegistry() // RespectNilValuesRegistry is the bson.Registry compatible with mgo withSetRespectNilValues set to true. -var RespectNilValuesRegistry = newRespectNilValuesRegistry() - -// newRegistry creates a new bson.Registry configured with the default encoders and decoders. -func newRegistry() *bson.Registry { - reg := bson.NewRegistry() - - structcodec, _ := bson.NewStructCodec(bson.DefaultStructTagParser, - bsonoptions.StructCodec(). - SetDecodeZeroStruct(true). - SetEncodeOmitDefaultStruct(true). - SetOverwriteDuplicatedInlinedFields(false). - SetAllowUnexportedFields(true)) - emptyInterCodec := bson.NewEmptyInterfaceCodec( - bsonoptions.EmptyInterfaceCodec(). - SetDecodeBinaryAsSlice(true)) - mapCodec := bson.NewMapCodec( - bsonoptions.MapCodec(). - SetDecodeZerosMap(true). - SetEncodeNilAsEmpty(true). - SetEncodeKeysWithStringer(true)) - uintcodec := bson.NewUIntCodec(bsonoptions.UIntCodec().SetEncodeToMinSize(true)) - - reg.RegisterTypeDecoder(tEmpty, emptyInterCodec) - reg.RegisterKindDecoder(reflect.String, bson.NewStringCodec(bsonoptions.StringCodec().SetDecodeObjectIDAsHex(false))) - reg.RegisterKindDecoder(reflect.Struct, structcodec) - reg.RegisterKindDecoder(reflect.Map, mapCodec) - reg.RegisterTypeEncoder(tByteSlice, bson.NewByteSliceCodec(bsonoptions.ByteSliceCodec().SetEncodeNilAsEmpty(true))) - reg.RegisterKindEncoder(reflect.Struct, structcodec) - reg.RegisterKindEncoder(reflect.Slice, bson.NewSliceCodec(bsonoptions.SliceCodec().SetEncodeNilAsEmpty(true))) - reg.RegisterKindEncoder(reflect.Map, mapCodec) - reg.RegisterKindEncoder(reflect.Uint, uintcodec) - reg.RegisterKindEncoder(reflect.Uint8, uintcodec) - reg.RegisterKindEncoder(reflect.Uint16, uintcodec) - reg.RegisterKindEncoder(reflect.Uint32, uintcodec) - reg.RegisterKindEncoder(reflect.Uint64, uintcodec) - reg.RegisterTypeMapEntry(bson.TypeInt32, tInt) - reg.RegisterTypeMapEntry(bson.TypeDateTime, tTime) - reg.RegisterTypeMapEntry(bson.TypeArray, tInterfaceSlice) - reg.RegisterTypeMapEntry(bson.Type(0), tM) - reg.RegisterTypeMapEntry(bson.TypeEmbeddedDocument, tM) - reg.RegisterInterfaceEncoder(tGetter, bson.ValueEncoderFunc(GetterEncodeValue)) - reg.RegisterInterfaceDecoder(tSetter, bson.ValueDecoderFunc(SetterDecodeValue)) - - return reg -} - -// newRespectNilValuesRegistry creates a new bson.Registry configured to behave like mgo/bson -// with RespectNilValues set to true. -func newRespectNilValuesRegistry() *bson.Registry { - reg := newRegistry() - - structcodec, _ := bson.NewStructCodec(bson.DefaultStructTagParser, - bsonoptions.StructCodec(). - SetDecodeZeroStruct(true). - SetEncodeOmitDefaultStruct(true). - SetOverwriteDuplicatedInlinedFields(false). - SetAllowUnexportedFields(true)) - mapCodec := bson.NewMapCodec( - bsonoptions.MapCodec(). - SetDecodeZerosMap(true). - SetEncodeNilAsEmpty(false)) - - reg.RegisterKindDecoder(reflect.Struct, structcodec) - reg.RegisterKindDecoder(reflect.Map, mapCodec) - reg.RegisterTypeEncoder(tByteSlice, bson.NewByteSliceCodec(bsonoptions.ByteSliceCodec().SetEncodeNilAsEmpty(false))) - reg.RegisterKindEncoder(reflect.Struct, structcodec) - reg.RegisterKindEncoder(reflect.Slice, bson.NewSliceCodec(bsonoptions.SliceCodec().SetEncodeNilAsEmpty(false))) - reg.RegisterKindEncoder(reflect.Map, mapCodec) - - return reg -} +var RespectNilValuesRegistry = bson.NewRespectNilValuesMgoRegistry() diff --git a/bson/mgoregistry.go b/bson/mgoregistry.go new file mode 100644 index 0000000000..398de2afb9 --- /dev/null +++ b/bson/mgoregistry.go @@ -0,0 +1,81 @@ +// Copyright (C) MongoDB, Inc. 2017-present. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + +package bson + +import ( + "errors" + "reflect" +) + +var ( + // ErrSetZero may be returned from a SetBSON method to have the value set to its respective zero value. + ErrSetZero = errors.New("set to zero") + + tInt = reflect.TypeOf(int(0)) + tM = reflect.TypeOf(M{}) + tInterfaceSlice = reflect.TypeOf([]interface{}{}) + tGetter = reflect.TypeOf((*Getter)(nil)).Elem() + tSetter = reflect.TypeOf((*Setter)(nil)).Elem() +) + +// NewMgoRegistry creates a new bson.Registry configured with the default encoders and decoders. +func NewMgoRegistry() *Registry { + reg := NewRegistry() + + structcodec := &structCodec{ + parser: DefaultStructTagParser, + decodeZeroStruct: true, + encodeOmitDefaultStruct: true, + allowUnexportedFields: true, + } + mapCodec := &mapCodec{ + decodeZerosMap: true, + encodeNilAsEmpty: true, + encodeKeysWithStringer: true, + } + uintcodec := &uintCodec{encodeToMinSize: true} + + reg.RegisterTypeDecoder(tEmpty, &emptyInterfaceCodec{decodeBinaryAsSlice: true}) + reg.RegisterKindDecoder(reflect.String, &stringCodec{}) + reg.RegisterKindDecoder(reflect.Struct, structcodec) + reg.RegisterKindDecoder(reflect.Map, mapCodec) + reg.RegisterTypeEncoder(tByteSlice, &byteSliceCodec{encodeNilAsEmpty: true}) + reg.RegisterKindEncoder(reflect.Struct, structcodec) + reg.RegisterKindEncoder(reflect.Slice, &sliceCodec{encodeNilAsEmpty: true}) + reg.RegisterKindEncoder(reflect.Map, mapCodec) + reg.RegisterKindEncoder(reflect.Uint, uintcodec) + reg.RegisterKindEncoder(reflect.Uint8, uintcodec) + reg.RegisterKindEncoder(reflect.Uint16, uintcodec) + reg.RegisterKindEncoder(reflect.Uint32, uintcodec) + reg.RegisterKindEncoder(reflect.Uint64, uintcodec) + reg.RegisterTypeMapEntry(TypeInt32, tInt) + reg.RegisterTypeMapEntry(TypeDateTime, tTime) + reg.RegisterTypeMapEntry(TypeArray, tInterfaceSlice) + reg.RegisterTypeMapEntry(Type(0), tM) + reg.RegisterTypeMapEntry(TypeEmbeddedDocument, tM) + reg.RegisterInterfaceEncoder(tGetter, ValueEncoderFunc(GetterEncodeValue)) + reg.RegisterInterfaceDecoder(tSetter, ValueDecoderFunc(SetterDecodeValue)) + + return reg +} + +// NewRespectNilValuesMgoRegistry creates a new bson.Registry configured to behave like mgo/bson +// with RespectNilValues set to true. +func NewRespectNilValuesMgoRegistry() *Registry { + reg := NewMgoRegistry() + + mapCodec := &mapCodec{ + decodeZerosMap: true, + } + + reg.RegisterKindDecoder(reflect.Map, mapCodec) + reg.RegisterTypeEncoder(tByteSlice, &byteSliceCodec{encodeNilAsEmpty: false}) + reg.RegisterKindEncoder(reflect.Slice, &sliceCodec{}) + reg.RegisterKindEncoder(reflect.Map, mapCodec) + + return reg +} diff --git a/bson/pointer_codec.go b/bson/pointer_codec.go index 5946b9cc9f..4ed1de3013 100644 --- a/bson/pointer_codec.go +++ b/bson/pointer_codec.go @@ -10,34 +10,23 @@ import ( "reflect" ) -var _ ValueEncoder = &PointerCodec{} -var _ ValueDecoder = &PointerCodec{} +var _ ValueEncoder = &pointerCodec{} +var _ ValueDecoder = &pointerCodec{} -// PointerCodec is the Codec used for pointers. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the -// PointerCodec registered. -type PointerCodec struct { +// pointerCodec is the Codec used for pointers. +type pointerCodec struct { ecache typeEncoderCache dcache typeDecoderCache } -// NewPointerCodec returns a PointerCodec that has been initialized. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the -// PointerCodec registered. -func NewPointerCodec() *PointerCodec { - return &PointerCodec{} -} - // 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 ValueWriter, val reflect.Value) error { +func (pc *pointerCodec) EncodeValue(ec EncodeContext, vw 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} + return ValueEncoderError{Name: "pointerCodec.EncodeValue", Kinds: []reflect.Kind{reflect.Ptr}, Received: val} } if val.IsNil() { @@ -62,9 +51,9 @@ func (pc *PointerCodec) EncodeValue(ec EncodeContext, vw ValueWriter, val reflec // 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 ValueReader, val reflect.Value) error { +func (pc *pointerCodec) DecodeValue(dc DecodeContext, vr ValueReader, val reflect.Value) error { if !val.CanSet() || val.Kind() != reflect.Ptr { - return ValueDecoderError{Name: "PointerCodec.DecodeValue", Kinds: []reflect.Kind{reflect.Ptr}, Received: val} + return ValueDecoderError{Name: "pointerCodec.DecodeValue", Kinds: []reflect.Kind{reflect.Ptr}, Received: val} } typ := val.Type() diff --git a/bson/registry.go b/bson/registry.go index d20424b340..71d65259d6 100644 --- a/bson/registry.go +++ b/bson/registry.go @@ -297,7 +297,7 @@ func (r *Registry) lookupInterfaceEncoder(valueType reflect.Type, allowAddr bool if !found { defaultEnc, _ = r.kindEncoders.Load(valueType.Kind()) } - return newCondAddrEncoder(ienc.ve, defaultEnc), true + return &condAddrEncoder{canAddrEnc: ienc.ve, elseEnc: defaultEnc}, true } } return nil, false diff --git a/bson/registry_test.go b/bson/registry_test.go index c7963d4edd..b897f04db6 100644 --- a/bson/registry_test.go +++ b/bson/registry_test.go @@ -195,7 +195,7 @@ func TestRegistryBuilder(t *testing.T) { ti3ImplPtr = reflect.TypeOf((*testInterface3Impl)(nil)) fc1, fc2 = &fakeCodec{num: 1}, &fakeCodec{num: 2} fsc, fslcc, fmc = new(fakeStructCodec), new(fakeSliceCodec), new(fakeMapCodec) - pc = NewPointerCodec() + pc = &pointerCodec{} ) reg := newTestRegistry() @@ -334,7 +334,7 @@ func TestRegistryBuilder(t *testing.T) { } allowunexported := cmp.AllowUnexported(fakeCodec{}, fakeStructCodec{}, fakeSliceCodec{}, fakeMapCodec{}) - comparepc := func(pc1, pc2 *PointerCodec) bool { return true } + comparepc := func(pc1, pc2 *pointerCodec) bool { return true } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Run("Encoder", func(t *testing.T) { @@ -610,7 +610,7 @@ func TestRegistry(t *testing.T) { ti3ImplPtr = reflect.TypeOf((*testInterface3Impl)(nil)) fc1, fc2 = &fakeCodec{num: 1}, &fakeCodec{num: 2} fsc, fslcc, fmc = new(fakeStructCodec), new(fakeSliceCodec), new(fakeMapCodec) - pc = NewPointerCodec() + pc = &pointerCodec{} ) reg := newTestRegistry() @@ -749,7 +749,7 @@ func TestRegistry(t *testing.T) { } allowunexported := cmp.AllowUnexported(fakeCodec{}, fakeStructCodec{}, fakeSliceCodec{}, fakeMapCodec{}) - comparepc := func(pc1, pc2 *PointerCodec) bool { return true } + comparepc := func(pc1, pc2 *pointerCodec) bool { return true } for _, tc := range testCases { tc := tc diff --git a/bson/mgocompat/setter_getter.go b/bson/setter_getter.go similarity index 68% rename from bson/mgocompat/setter_getter.go rename to bson/setter_getter.go index fc620fbba8..3616d25603 100644 --- a/bson/mgocompat/setter_getter.go +++ b/bson/setter_getter.go @@ -4,13 +4,11 @@ // not use this file except in compliance with the License. You may obtain // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -package mgocompat +package bson import ( "errors" "reflect" - - "go.mongodb.org/mongo-driver/bson" ) // Setter interface: a value implementing the bson.Setter interface will receive the BSON @@ -34,7 +32,7 @@ import ( // return raw.Unmarshal(s) // } type Setter interface { - SetBSON(raw bson.RawValue) error + SetBSON(raw RawValue) error } // Getter interface: a value implementing the bson.Getter interface will have its GetBSON @@ -48,35 +46,35 @@ type Getter interface { } // SetterDecodeValue is the ValueDecoderFunc for Setter types. -func SetterDecodeValue(_ bson.DecodeContext, vr bson.ValueReader, val reflect.Value) error { +func SetterDecodeValue(_ DecodeContext, vr ValueReader, val reflect.Value) error { if !val.IsValid() || (!val.Type().Implements(tSetter) && !reflect.PtrTo(val.Type()).Implements(tSetter)) { - return bson.ValueDecoderError{Name: "SetterDecodeValue", Types: []reflect.Type{tSetter}, Received: val} + return ValueDecoderError{Name: "SetterDecodeValue", Types: []reflect.Type{tSetter}, Received: val} } if val.Kind() == reflect.Ptr && val.IsNil() { if !val.CanSet() { - return bson.ValueDecoderError{Name: "SetterDecodeValue", Types: []reflect.Type{tSetter}, Received: val} + return ValueDecoderError{Name: "SetterDecodeValue", Types: []reflect.Type{tSetter}, Received: val} } val.Set(reflect.New(val.Type().Elem())) } if !val.Type().Implements(tSetter) { if !val.CanAddr() { - return bson.ValueDecoderError{Name: "ValueUnmarshalerDecodeValue", Types: []reflect.Type{tSetter}, Received: val} + return ValueDecoderError{Name: "ValueUnmarshalerDecodeValue", Types: []reflect.Type{tSetter}, Received: val} } val = val.Addr() // If the type doesn't implement the interface, a pointer to it must. } - t, src, err := bson.CopyValueToBytes(vr) + t, src, err := CopyValueToBytes(vr) if err != nil { return err } m, ok := val.Interface().(Setter) if !ok { - return bson.ValueDecoderError{Name: "SetterDecodeValue", Types: []reflect.Type{tSetter}, Received: val} + return ValueDecoderError{Name: "SetterDecodeValue", Types: []reflect.Type{tSetter}, Received: val} } - if err := m.SetBSON(bson.RawValue{Type: t, Value: src}); err != nil { + if err := m.SetBSON(RawValue{Type: t, Value: src}); err != nil { if !errors.Is(err, ErrSetZero) { return err } @@ -86,11 +84,11 @@ func SetterDecodeValue(_ bson.DecodeContext, vr bson.ValueReader, val reflect.Va } // GetterEncodeValue is the ValueEncoderFunc for Getter types. -func GetterEncodeValue(ec bson.EncodeContext, vw bson.ValueWriter, val reflect.Value) error { +func GetterEncodeValue(ec EncodeContext, vw ValueWriter, val reflect.Value) error { // Either val or a pointer to val must implement Getter switch { case !val.IsValid(): - return bson.ValueEncoderError{Name: "GetterEncodeValue", Types: []reflect.Type{tGetter}, Received: val} + return ValueEncoderError{Name: "GetterEncodeValue", Types: []reflect.Type{tGetter}, Received: val} case val.Type().Implements(tGetter): // If Getter is implemented on a concrete type, make sure that val isn't a nil pointer if isImplementationNil(val, tGetter) { @@ -99,7 +97,7 @@ func GetterEncodeValue(ec bson.EncodeContext, vw bson.ValueWriter, val reflect.V case reflect.PtrTo(val.Type()).Implements(tGetter) && val.CanAddr(): val = val.Addr() default: - return bson.ValueEncoderError{Name: "GetterEncodeValue", Types: []reflect.Type{tGetter}, Received: val} + return ValueEncoderError{Name: "GetterEncodeValue", Types: []reflect.Type{tGetter}, Received: val} } m, ok := val.Interface().(Getter) @@ -120,12 +118,3 @@ func GetterEncodeValue(ec bson.EncodeContext, vw bson.ValueWriter, val reflect.V } return encoder.EncodeValue(ec, vw, vv) } - -// 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/bson/slice_codec.go b/bson/slice_codec.go index f29c36b26d..6d26f6283c 100644 --- a/bson/slice_codec.go +++ b/bson/slice_codec.go @@ -10,45 +10,22 @@ import ( "errors" "fmt" "reflect" - - "go.mongodb.org/mongo-driver/bson/bsonoptions" ) -var defaultSliceCodec = NewSliceCodec() - -// SliceCodec is the Codec used for slice values. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the -// SliceCodec registered. -type SliceCodec struct { - // EncodeNilAsEmpty causes EncodeValue to marshal nil Go slices as empty BSON arrays instead of +// sliceCodec is the Codec used for slice values. +type sliceCodec struct { + // encodeNilAsEmpty causes EncodeValue to marshal nil Go slices as empty BSON arrays instead of // BSON null. - // - // Deprecated: Use bson.Encoder.NilSliceAsEmpty instead. - EncodeNilAsEmpty bool -} - -// NewSliceCodec returns a MapCodec with options opts. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the -// SliceCodec registered. -func NewSliceCodec(opts ...*bsonoptions.SliceCodecOptions) *SliceCodec { - sliceOpt := bsonoptions.MergeSliceCodecOptions(opts...) - - codec := SliceCodec{} - if sliceOpt.EncodeNilAsEmpty != nil { - codec.EncodeNilAsEmpty = *sliceOpt.EncodeNilAsEmpty - } - return &codec + encodeNilAsEmpty bool } // EncodeValue is the ValueEncoder for slice types. -func (sc SliceCodec) EncodeValue(ec EncodeContext, vw ValueWriter, val reflect.Value) error { +func (sc sliceCodec) EncodeValue(ec EncodeContext, vw 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 && !ec.nilSliceAsEmpty { + if val.IsNil() && !sc.encodeNilAsEmpty && !ec.nilSliceAsEmpty { return vw.WriteNull() } @@ -117,7 +94,7 @@ func (sc SliceCodec) EncodeValue(ec EncodeContext, vw ValueWriter, val reflect.V } // DecodeValue is the ValueDecoder for slice types. -func (sc *SliceCodec) DecodeValue(dc DecodeContext, vr ValueReader, val reflect.Value) error { +func (sc *sliceCodec) DecodeValue(dc DecodeContext, vr ValueReader, val reflect.Value) error { if !val.CanSet() || val.Kind() != reflect.Slice { return ValueDecoderError{Name: "SliceDecodeValue", Kinds: []reflect.Kind{reflect.Slice}, Received: val} } diff --git a/bson/string_codec.go b/bson/string_codec.go index 4681f15bd4..7d7205f34d 100644 --- a/bson/string_codec.go +++ b/bson/string_codec.go @@ -10,42 +10,22 @@ import ( "errors" "fmt" "reflect" - - "go.mongodb.org/mongo-driver/bson/bsonoptions" ) -// StringCodec is the Codec used for string values. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the -// StringCodec registered. -type StringCodec struct { - // DecodeObjectIDAsHex specifies if object IDs should be decoded as their hex representation. +// stringCodec is the Codec used for string values. +type stringCodec struct { + // decodeObjectIDAsHex 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. - // - // Deprecated: Decoding object IDs as raw bytes will not be supported in Go Driver 2.0. - DecodeObjectIDAsHex bool + decodeObjectIDAsHex bool } -var ( - defaultStringCodec = NewStringCodec() - - // Assert that defaultStringCodec satisfies the typeDecoder interface, which allows it to be - // used by collection type decoders (e.g. map, slice, etc) to set individual values in a - // collection. - _ typeDecoder = defaultStringCodec -) - -// NewStringCodec returns a StringCodec with options opts. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the -// StringCodec registered. -func NewStringCodec(opts ...*bsonoptions.StringCodecOptions) *StringCodec { - stringOpt := bsonoptions.MergeStringCodecOptions(opts...) - return &StringCodec{*stringOpt.DecodeObjectIDAsHex} -} +// Assert that defaultStringCodec satisfies the typeDecoder interface, which allows it to be +// used by collection type decoders (e.g. map, slice, etc) to set individual values in a +// collection. +var _ typeDecoder = (*stringCodec)(nil) // EncodeValue is the ValueEncoder for string types. -func (sc *StringCodec) EncodeValue(_ EncodeContext, vw ValueWriter, val reflect.Value) error { +func (sc *stringCodec) EncodeValue(_ EncodeContext, vw ValueWriter, val reflect.Value) error { if val.Kind() != reflect.String { return ValueEncoderError{ Name: "StringEncodeValue", @@ -57,7 +37,7 @@ func (sc *StringCodec) EncodeValue(_ EncodeContext, vw ValueWriter, val reflect. return vw.WriteString(val.String()) } -func (sc *StringCodec) decodeType(dc DecodeContext, vr ValueReader, t reflect.Type) (reflect.Value, error) { +func (sc *stringCodec) decodeType(dc DecodeContext, vr ValueReader, t reflect.Type) (reflect.Value, error) { if t.Kind() != reflect.String { return emptyValue, ValueDecoderError{ Name: "StringDecodeValue", @@ -79,11 +59,10 @@ func (sc *StringCodec) decodeType(dc DecodeContext, vr ValueReader, t reflect.Ty if err != nil { return emptyValue, err } - if dc.decodeObjectIDAsHex { - str = oid.Hex() - } else { + if !sc.decodeObjectIDAsHex && !dc.decodeObjectIDAsHex { return emptyValue, errors.New("cannot decode ObjectID as string if DecodeObjectIDAsHex is not set") } + str = oid.Hex() case TypeSymbol: str, err = vr.ReadSymbol() if err != nil { @@ -114,7 +93,7 @@ func (sc *StringCodec) decodeType(dc DecodeContext, vr ValueReader, t reflect.Ty } // DecodeValue is the ValueDecoder for string types. -func (sc *StringCodec) DecodeValue(dctx DecodeContext, vr ValueReader, val reflect.Value) error { +func (sc *stringCodec) DecodeValue(dctx DecodeContext, vr ValueReader, val reflect.Value) error { if !val.CanSet() || val.Kind() != reflect.String { return ValueDecoderError{Name: "StringDecodeValue", Kinds: []reflect.Kind{reflect.String}, Received: val} } diff --git a/bson/string_codec_test.go b/bson/string_codec_test.go index 56d1215af5..63a06fa57c 100644 --- a/bson/string_codec_test.go +++ b/bson/string_codec_test.go @@ -29,7 +29,7 @@ func TestStringCodec(t *testing.T) { } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - stringCodec := NewStringCodec() + stringCodec := &stringCodec{} actual := reflect.New(reflect.TypeOf("")).Elem() err := stringCodec.DecodeValue(tc.dctx, reader, actual) diff --git a/bson/struct_codec.go b/bson/struct_codec.go index 17e51bce14..0c3eac5c73 100644 --- a/bson/struct_codec.go +++ b/bson/struct_codec.go @@ -14,8 +14,6 @@ import ( "strings" "sync" "time" - - "go.mongodb.org/mongo-driver/bson/bsonoptions" ) // DecodeError represents an error that occurs when unmarshalling BSON bytes into a native Go type. @@ -49,88 +47,47 @@ func (de *DecodeError) Keys() []string { return reversedKeys } -// StructCodec is the Codec used for struct values. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the -// StructCodec registered. -type StructCodec struct { +// structCodec is the Codec used for struct values. +type structCodec struct { cache sync.Map // map[reflect.Type]*structDescription parser StructTagParser - // DecodeZeroStruct causes DecodeValue to delete any existing values from Go structs in the - // destination value passed to Decode before unmarshaling BSON documents into them. - // - // Deprecated: Use bson.Decoder.ZeroStructs instead. - DecodeZeroStruct bool + // decodeZeroStruct causes DecodeValue to delete any existing values from Go structs in the + decodeZeroStruct bool - // DecodeDeepZeroInline causes DecodeValue to delete any existing values from Go structs in the + // decodeDeepZeroInline causes DecodeValue to delete any existing values from Go structs in the // destination value passed to Decode before unmarshaling BSON documents into them. - // - // Deprecated: DecodeDeepZeroInline will not be supported in Go Driver 2.0. - DecodeDeepZeroInline bool + decodeDeepZeroInline bool - // EncodeOmitDefaultStruct causes the Encoder to consider the zero value for a struct (e.g. + // encodeOmitDefaultStruct causes the Encoder to consider the zero value for a struct (e.g. // MyStruct{}) as empty and omit it from the marshaled BSON when the "omitempty" struct tag // option is set. - // - // Deprecated: Use bson.Encoder.OmitZeroStruct instead. - EncodeOmitDefaultStruct bool + encodeOmitDefaultStruct bool - // AllowUnexportedFields allows encoding and decoding values from un-exported struct fields. - // - // Deprecated: AllowUnexportedFields does not work on recent versions of Go and will not be - // supported in Go Driver 2.0. - AllowUnexportedFields bool + // allowUnexportedFields allows encoding and decoding values from un-exported struct fields. + allowUnexportedFields bool - // OverwriteDuplicatedInlinedFields, if false, causes EncodeValue to return an error if there is + // overwriteDuplicatedInlinedFields, if false, causes EncodeValue to return an error if there is // a duplicate field in the marshaled BSON when the "inline" struct tag option is set. The // default value is true. - // - // Deprecated: Use bson.Encoder.ErrorOnInlineDuplicates instead. - OverwriteDuplicatedInlinedFields bool + overwriteDuplicatedInlinedFields bool } -var _ ValueEncoder = &StructCodec{} -var _ ValueDecoder = &StructCodec{} - -// NewStructCodec returns a StructCodec that uses p for struct tag parsing. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the -// StructCodec registered. -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...) +var _ ValueEncoder = &structCodec{} +var _ ValueDecoder = &structCodec{} - codec := &StructCodec{ - parser: p, +// newStructCodec returns a StructCodec that uses p for struct tag parsing. +func newStructCodec(p StructTagParser) *structCodec { + return &structCodec{ + parser: p, + overwriteDuplicatedInlinedFields: true, } - - 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(ec EncodeContext, vw ValueWriter, val reflect.Value) error { +func (sc *structCodec) EncodeValue(ec EncodeContext, vw ValueWriter, val reflect.Value) error { if !val.IsValid() || val.Kind() != reflect.Struct { - return ValueEncoderError{Name: "StructCodec.EncodeValue", Kinds: []reflect.Kind{reflect.Struct}, Received: val} + return ValueEncoderError{Name: "structCodec.EncodeValue", Kinds: []reflect.Kind{reflect.Struct}, Received: val} } sd, err := sc.describeStruct(ec.Registry, val.Type(), ec.useJSONStructTags, ec.errorOnInlineDuplicates) @@ -188,7 +145,7 @@ func (sc *StructCodec) EncodeValue(ec EncodeContext, vw ValueWriter, val reflect // nil interface separately. empty = rv.IsNil() } else { - empty = isEmpty(rv, sc.EncodeOmitDefaultStruct || ec.omitZeroStruct) + empty = isEmpty(rv, sc.encodeOmitDefaultStruct || ec.omitZeroStruct) } if desc.omitEmpty && empty { continue @@ -223,7 +180,7 @@ func (sc *StructCodec) EncodeValue(ec EncodeContext, vw ValueWriter, val reflect return exists } - return defaultMapCodec.mapEncodeValue(ec, dw, rv, collisionFn) + return (&mapCodec{}).mapEncodeValue(ec, dw, rv, collisionFn) } return dw.WriteDocumentEnd() @@ -245,9 +202,9 @@ func newDecodeError(key string, original error) error { // 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(dc DecodeContext, vr ValueReader, val reflect.Value) error { +func (sc *structCodec) DecodeValue(dc DecodeContext, vr ValueReader, val reflect.Value) error { if !val.CanSet() || val.Kind() != reflect.Struct { - return ValueDecoderError{Name: "StructCodec.DecodeValue", Kinds: []reflect.Kind{reflect.Struct}, Received: val} + return ValueDecoderError{Name: "structCodec.DecodeValue", Kinds: []reflect.Kind{reflect.Struct}, Received: val} } switch vrType := vr.Type(); vrType { @@ -275,10 +232,10 @@ func (sc *StructCodec) DecodeValue(dc DecodeContext, vr ValueReader, val reflect return err } - if sc.DecodeZeroStruct || dc.zeroStructs { + if sc.decodeZeroStruct || dc.zeroStructs { val.Set(reflect.Zero(val.Type())) } - if sc.DecodeDeepZeroInline && sd.inline { + if sc.decodeDeepZeroInline && sd.inline { val.Set(deepZero(val.Type())) } @@ -461,7 +418,7 @@ func (bi byIndex) Less(i, j int) bool { return len(bi[i].inline) < len(bi[j].inline) } -func (sc *StructCodec) describeStruct( +func (sc *structCodec) describeStruct( r *Registry, t reflect.Type, useJSONStructTags bool, @@ -484,7 +441,7 @@ func (sc *StructCodec) describeStruct( return ds, nil } -func (sc *StructCodec) describeStructSlow( +func (sc *structCodec) describeStructSlow( r *Registry, t reflect.Type, useJSONStructTags bool, @@ -500,7 +457,7 @@ func (sc *StructCodec) describeStructSlow( var fields []fieldDescription for i := 0; i < numFields; i++ { sf := t.Field(i) - if sf.PkgPath != "" && (!sc.AllowUnexportedFields || !sf.Anonymous) { + if sf.PkgPath != "" && (!sc.allowUnexportedFields || !sf.Anonymous) { // field is private or unexported fields aren't allowed, ignore continue } @@ -611,7 +568,7 @@ func (sc *StructCodec) describeStructSlow( continue } dominant, ok := dominantField(fields[i : i+advance]) - if !ok || !sc.OverwriteDuplicatedInlinedFields || errorOnDuplicates { + if !ok || !sc.overwriteDuplicatedInlinedFields || errorOnDuplicates { return nil, fmt.Errorf("struct %s has duplicated key %s", t.String(), name) } sd.fl = append(sd.fl, dominant) diff --git a/bson/time_codec.go b/bson/time_codec.go index a168d1e769..6bbe300e4a 100644 --- a/bson/time_codec.go +++ b/bson/time_codec.go @@ -10,48 +10,23 @@ import ( "fmt" "reflect" "time" - - "go.mongodb.org/mongo-driver/bson/bsonoptions" ) const ( timeFormatString = "2006-01-02T15:04:05.999Z07:00" ) -// TimeCodec is the Codec used for time.Time values. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the -// TimeCodec registered. -type TimeCodec struct { - // UseLocalTimeZone specifies if we should decode into the local time zone. Defaults to false. - // - // Deprecated: Use bson.Decoder.UseLocalTimeZone instead. - UseLocalTimeZone bool +// timeCodec is the Codec used for time.Time values. +type timeCodec struct { + // useLocalTimeZone specifies if we should decode into the local time zone. Defaults to false. + useLocalTimeZone bool } -var ( - defaultTimeCodec = NewTimeCodec() - - // Assert that defaultTimeCodec satisfies the typeDecoder interface, which allows it to be used - // by collection type decoders (e.g. map, slice, etc) to set individual values in a collection. - _ typeDecoder = defaultTimeCodec -) - -// NewTimeCodec returns a TimeCodec with options opts. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the -// TimeCodec registered. -func NewTimeCodec(opts ...*bsonoptions.TimeCodecOptions) *TimeCodec { - timeOpt := bsonoptions.MergeTimeCodecOptions(opts...) - - codec := TimeCodec{} - if timeOpt.UseLocalTimeZone != nil { - codec.UseLocalTimeZone = *timeOpt.UseLocalTimeZone - } - return &codec -} +// Assert that defaultTimeCodec satisfies the typeDecoder interface, which allows it to be used +// by collection type decoders (e.g. map, slice, etc) to set individual values in a collection. +var _ typeDecoder = (*timeCodec)(nil) -func (tc *TimeCodec) decodeType(dc DecodeContext, vr ValueReader, t reflect.Type) (reflect.Value, error) { +func (tc *timeCodec) decodeType(dc DecodeContext, vr ValueReader, t reflect.Type) (reflect.Value, error) { if t != tTime { return emptyValue, ValueDecoderError{ Name: "TimeDecodeValue", @@ -102,14 +77,14 @@ func (tc *TimeCodec) decodeType(dc DecodeContext, vr ValueReader, t reflect.Type return emptyValue, fmt.Errorf("cannot decode %v into a time.Time", vrType) } - if !tc.UseLocalTimeZone && !dc.useLocalTimeZone { + if !tc.useLocalTimeZone && !dc.useLocalTimeZone { timeVal = timeVal.UTC() } return reflect.ValueOf(timeVal), nil } // DecodeValue is the ValueDecoderFunc for time.Time. -func (tc *TimeCodec) DecodeValue(dc DecodeContext, vr ValueReader, val reflect.Value) error { +func (tc *timeCodec) DecodeValue(dc DecodeContext, vr ValueReader, val reflect.Value) error { if !val.CanSet() || val.Type() != tTime { return ValueDecoderError{Name: "TimeDecodeValue", Types: []reflect.Type{tTime}, Received: val} } @@ -124,7 +99,7 @@ func (tc *TimeCodec) DecodeValue(dc DecodeContext, vr ValueReader, val reflect.V } // EncodeValue is the ValueEncoderFunc for time.TIme. -func (tc *TimeCodec) EncodeValue(_ EncodeContext, vw ValueWriter, val reflect.Value) error { +func (tc *timeCodec) EncodeValue(_ EncodeContext, vw ValueWriter, val reflect.Value) error { if !val.IsValid() || val.Type() != tTime { return ValueEncoderError{Name: "TimeEncodeValue", Types: []reflect.Type{tTime}, Received: val} } diff --git a/bson/time_codec_test.go b/bson/time_codec_test.go index 1f185692da..70f52906b2 100644 --- a/bson/time_codec_test.go +++ b/bson/time_codec_test.go @@ -11,7 +11,6 @@ import ( "testing" "time" - "go.mongodb.org/mongo-driver/bson/bsonoptions" "go.mongodb.org/mongo-driver/internal/assert" "go.mongodb.org/mongo-driver/x/bsonx/bsoncore" ) @@ -22,20 +21,17 @@ func TestTimeCodec(t *testing.T) { t.Run("UseLocalTimeZone", func(t *testing.T) { reader := &valueReaderWriter{BSONType: TypeDateTime, Return: now.UnixNano() / int64(time.Millisecond)} testCases := []struct { - name string - opts *bsonoptions.TimeCodecOptions - utc bool + name string + codec *timeCodec + utc bool }{ - {"default", bsonoptions.TimeCodec(), true}, - {"false", bsonoptions.TimeCodec().SetUseLocalTimeZone(false), true}, - {"true", bsonoptions.TimeCodec().SetUseLocalTimeZone(true), false}, + {"default", &timeCodec{}, true}, + {"true", &timeCodec{useLocalTimeZone: true}, false}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - timeCodec := NewTimeCodec(tc.opts) - actual := reflect.New(reflect.TypeOf(now)).Elem() - err := timeCodec.DecodeValue(DecodeContext{}, reader, actual) + err := tc.codec.DecodeValue(DecodeContext{}, reader, actual) assert.Nil(t, err, "TimeCodec.DecodeValue error: %v", err) actualTime := actual.Interface().(time.Time) @@ -69,7 +65,7 @@ func TestTimeCodec(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { actual := reflect.New(reflect.TypeOf(now)).Elem() - err := defaultTimeCodec.DecodeValue(DecodeContext{}, tc.reader, actual) + err := (&timeCodec{}).DecodeValue(DecodeContext{}, tc.reader, actual) assert.Nil(t, err, "DecodeValue error: %v", err) actualTime := actual.Interface().(time.Time) diff --git a/bson/uint_codec.go b/bson/uint_codec.go index 73bc01966e..b8f97ae5ab 100644 --- a/bson/uint_codec.go +++ b/bson/uint_codec.go @@ -10,46 +10,21 @@ import ( "fmt" "math" "reflect" - - "go.mongodb.org/mongo-driver/bson/bsonoptions" ) -// UIntCodec is the Codec used for uint values. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the -// UIntCodec registered. -type UIntCodec struct { - // EncodeToMinSize causes EncodeValue to marshal Go uint values (excluding uint64) as the +// uintCodec is the Codec used for uint values. +type uintCodec struct { + // encodeToMinSize causes EncodeValue to marshal Go uint values (excluding uint64) as the // minimum BSON int size (either 32-bit or 64-bit) that can represent the integer value. - // - // Deprecated: Use bson.Encoder.IntMinSize instead. - EncodeToMinSize bool + encodeToMinSize bool } -var ( - defaultUIntCodec = NewUIntCodec() - - // Assert that defaultUIntCodec satisfies the typeDecoder interface, which allows it to be used - // by collection type decoders (e.g. map, slice, etc) to set individual values in a collection. - _ typeDecoder = defaultUIntCodec -) - -// NewUIntCodec returns a UIntCodec with options opts. -// -// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the -// UIntCodec registered. -func NewUIntCodec(opts ...*bsonoptions.UIntCodecOptions) *UIntCodec { - uintOpt := bsonoptions.MergeUIntCodecOptions(opts...) - - codec := UIntCodec{} - if uintOpt.EncodeToMinSize != nil { - codec.EncodeToMinSize = *uintOpt.EncodeToMinSize - } - return &codec -} +// Assert that defaultUIntCodec satisfies the typeDecoder interface, which allows it to be used +// by collection type decoders (e.g. map, slice, etc) to set individual values in a collection. +var _ typeDecoder = (*uintCodec)(nil) // EncodeValue is the ValueEncoder for uint types. -func (uic *UIntCodec) EncodeValue(ec EncodeContext, vw ValueWriter, val reflect.Value) error { +func (uic *uintCodec) EncodeValue(ec EncodeContext, vw ValueWriter, val reflect.Value) error { switch val.Kind() { case reflect.Uint8, reflect.Uint16: return vw.WriteInt32(int32(val.Uint())) @@ -57,7 +32,7 @@ func (uic *UIntCodec) EncodeValue(ec EncodeContext, vw ValueWriter, val reflect. 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) + useMinSize := ec.MinSize || (uic.encodeToMinSize && val.Kind() != reflect.Uint64) if u64 <= math.MaxInt32 && useMinSize { return vw.WriteInt32(int32(u64)) @@ -75,7 +50,7 @@ func (uic *UIntCodec) EncodeValue(ec EncodeContext, vw ValueWriter, val reflect. } } -func (uic *UIntCodec) decodeType(dc DecodeContext, vr ValueReader, t reflect.Type) (reflect.Value, error) { +func (uic *uintCodec) decodeType(dc DecodeContext, vr ValueReader, t reflect.Type) (reflect.Value, error) { var i64 int64 var err error switch vrType := vr.Type(); vrType { @@ -163,7 +138,7 @@ func (uic *UIntCodec) decodeType(dc DecodeContext, vr ValueReader, t reflect.Typ } // DecodeValue is the ValueDecoder for uint types. -func (uic *UIntCodec) DecodeValue(dc DecodeContext, vr ValueReader, val reflect.Value) error { +func (uic *uintCodec) DecodeValue(dc DecodeContext, vr ValueReader, val reflect.Value) error { if !val.CanSet() { return ValueDecoderError{ Name: "UintDecodeValue", diff --git a/bson/unmarshal_value_test.go b/bson/unmarshal_value_test.go index 8d9dfb5351..fd379b5daa 100644 --- a/bson/unmarshal_value_test.go +++ b/bson/unmarshal_value_test.go @@ -76,7 +76,7 @@ func TestUnmarshalValue(t *testing.T) { }, } reg := NewRegistry() - reg.RegisterTypeDecoder(reflect.TypeOf([]byte{}), NewSliceCodec()) + reg.RegisterTypeDecoder(reflect.TypeOf([]byte{}), &sliceCodec{}) for _, tc := range testCases { tc := tc @@ -111,7 +111,7 @@ func BenchmarkSliceCodecUnmarshal(b *testing.B) { }, } reg := NewRegistry() - reg.RegisterTypeDecoder(reflect.TypeOf([]byte{}), NewSliceCodec()) + reg.RegisterTypeDecoder(reflect.TypeOf([]byte{}), &sliceCodec{}) for _, bm := range benchmarks { b.Run(bm.name, func(b *testing.B) { b.RunParallel(func(pb *testing.PB) {