Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
qingyang-hu committed Apr 30, 2024
1 parent d8fba65 commit 1834500
Show file tree
Hide file tree
Showing 21 changed files with 134 additions and 374 deletions.
171 changes: 17 additions & 154 deletions bson/bsoncodec.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,10 @@ func (vde ValueDecoderError) Error() string {
type EncodeContext struct {
*Registry

// MinSize causes the Encoder to marshal Go integer values (int, int8, int16, int32, int64,
// minSize causes the Encoder to marshal Go integer values (int, int8, int16, int32, int64,
// uint, uint8, uint16, uint32, or uint64) as the minimum BSON int size (either 32 or 64 bits)
// that can represent the integer value.
//
// Deprecated: Use bson.Encoder.IntMinSize instead.
MinSize bool
minSize bool

errorOnInlineDuplicates bool
stringifyMapKeysWithFmt bool
Expand All @@ -93,92 +91,29 @@ type EncodeContext struct {
useJSONStructTags bool
}

// ErrorOnInlineDuplicates causes the Encoder to return an error if there is a duplicate field in
// the marshaled BSON when the "inline" struct tag option is set.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.ErrorOnInlineDuplicates] instead.
func (ec *EncodeContext) ErrorOnInlineDuplicates() {
ec.errorOnInlineDuplicates = true
}

// StringifyMapKeysWithFmt 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 [go.mongodb.org/mongo-driver/bson.Encoder.StringifyMapKeysWithFmt] instead.
func (ec *EncodeContext) StringifyMapKeysWithFmt() {
ec.stringifyMapKeysWithFmt = true
}

// NilMapAsEmpty causes the Encoder to marshal nil Go maps as empty BSON documents instead of BSON
// null.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.NilMapAsEmpty] instead.
func (ec *EncodeContext) NilMapAsEmpty() {
ec.nilMapAsEmpty = true
}

// NilSliceAsEmpty causes the Encoder to marshal nil Go slices as empty BSON arrays instead of BSON
// null.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.NilSliceAsEmpty] instead.
func (ec *EncodeContext) NilSliceAsEmpty() {
ec.nilSliceAsEmpty = true
}

// NilByteSliceAsEmpty causes the Encoder to marshal nil Go byte slices as empty BSON binary values
// instead of BSON null.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.NilByteSliceAsEmpty] instead.
func (ec *EncodeContext) NilByteSliceAsEmpty() {
ec.nilByteSliceAsEmpty = true
}

// OmitZeroStruct 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.
//
// Note that the Encoder only examines exported struct fields when determining if a struct is the
// zero value. It considers pointers to a zero struct value (e.g. &MyStruct{}) not empty.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.OmitZeroStruct] instead.
func (ec *EncodeContext) OmitZeroStruct() {
ec.omitZeroStruct = true
}

// UseJSONStructTags causes the Encoder to fall back to using the "json" struct tag if a "bson"
// struct tag is not specified.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.UseJSONStructTags] instead.
func (ec *EncodeContext) UseJSONStructTags() {
ec.useJSONStructTags = true
}

// DecodeContext is the contextual information required for a Codec to decode a
// value.
type DecodeContext struct {
*Registry

// Truncate, if true, instructs decoders to to truncate the fractional part of BSON "double"
// values when attempting to unmarshal them into a Go integer (int, int8, int16, int32, int64,
// uint, uint8, uint16, uint32, or uint64) struct field. The truncation logic does not apply to
// BSON "decimal128" values.
//
// Deprecated: Use bson.Decoder.AllowTruncatingDoubles instead.
Truncate bool

// Ancestor is the type of a containing document. This is mainly used to determine what type
// ancestor is the type of a containing document. This is mainly used to determine what type
// should be used when decoding an embedded document into an empty interface. For example, if
// Ancestor is a bson.M, BSON embedded document values being decoded into an empty interface
// will be decoded into a bson.M.
//
// Deprecated: Use bson.Decoder.DefaultDocumentM or bson.Decoder.DefaultDocumentD instead.
Ancestor reflect.Type
ancestor reflect.Type

// defaultDocumentType specifies the Go type to decode top-level and nested BSON documents into. In particular, the
// usage for this field is restricted to data typed as "interface{}" or "map[string]interface{}". If DocumentType is
// set to a type that a BSON document cannot be unmarshaled into (e.g. "string"), unmarshalling will result in an
// error. DocumentType overrides the Ancestor field.
defaultDocumentType reflect.Type

// truncate, if true, instructs decoders to to truncate the fractional part of BSON "double"
// values when attempting to unmarshal them into a Go integer (int, int8, int16, int32, int64,
// uint, uint8, uint16, uint32, or uint64) struct field. The truncation logic does not apply to
// BSON "decimal128" values.
truncate bool

binaryAsSlice bool
decodeObjectIDAsHex bool
useJSONStructTags bool
Expand All @@ -187,85 +122,13 @@ type DecodeContext struct {
zeroStructs bool
}

// BinaryAsSlice causes the Decoder 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 [go.mongodb.org/mongo-driver/bson.Decoder.BinaryAsSlice] instead.
func (dc *DecodeContext) BinaryAsSlice() {
dc.binaryAsSlice = true
}

// DecodeObjectIDAsHex causes the Decoder to unmarshal BSON ObjectID as a hexadecimal string.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Decoder.DecodeObjectIDAsHex] instead.
func (dc *DecodeContext) DecodeObjectIDAsHex() {
dc.decodeObjectIDAsHex = true
}

// UseJSONStructTags causes the Decoder to fall back to using the "json" struct tag if a "bson"
// struct tag is not specified.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Decoder.UseJSONStructTags] instead.
func (dc *DecodeContext) UseJSONStructTags() {
dc.useJSONStructTags = true
}

// UseLocalTimeZone causes the Decoder to unmarshal time.Time values in the local timezone instead
// of the UTC timezone.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Decoder.UseLocalTimeZone] instead.
func (dc *DecodeContext) UseLocalTimeZone() {
dc.useLocalTimeZone = true
}

// ZeroMaps causes the Decoder to delete any existing values from Go maps in the destination value
// passed to Decode before unmarshaling BSON documents into them.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Decoder.ZeroMaps] instead.
func (dc *DecodeContext) ZeroMaps() {
dc.zeroMaps = true
}

// ZeroStructs causes the Decoder to delete any existing values from Go structs in the destination
// value passed to Decode before unmarshaling BSON documents into them.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Decoder.ZeroStructs] instead.
func (dc *DecodeContext) ZeroStructs() {
dc.zeroStructs = true
}

// DefaultDocumentM causes the Decoder to always unmarshal documents into the M type. This
// behavior is restricted to data typed as "interface{}" or "map[string]interface{}".
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Decoder.DefaultDocumentM] instead.
func (dc *DecodeContext) DefaultDocumentM() {
dc.defaultDocumentType = reflect.TypeOf(M{})
}

// DefaultDocumentD causes the Decoder to always unmarshal documents into the D type. This
// behavior is restricted to data typed as "interface{}" or "map[string]interface{}".
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Decoder.DefaultDocumentD] instead.
func (dc *DecodeContext) DefaultDocumentD() {
dc.defaultDocumentType = reflect.TypeOf(D{})
}

// ValueCodec is an interface for encoding and decoding a reflect.Value.
// values.
//
// Deprecated: Use [ValueEncoder] and [ValueDecoder] instead.
type ValueCodec interface {
ValueEncoder
ValueDecoder
}

// ValueEncoder is the interface implemented by types that can encode a provided Go type to BSON.
// valueEncoder is the interface implemented by types that can encode a provided Go type to BSON.
// The value to encode is provided as a reflect.Value and a bson.ValueWriter is used within the
// EncodeValue method to actually create the BSON representation. For convenience, ValueEncoderFunc
// is provided to allow use of a function with the correct signature as a ValueEncoder. An
// EncodeContext instance is provided to allow implementations to lookup further ValueEncoders and
// to provide configuration information.
type ValueEncoder interface {
type valueEncoder interface {
EncodeValue(EncodeContext, ValueWriter, reflect.Value) error
}

Expand All @@ -278,12 +141,12 @@ func (fn ValueEncoderFunc) EncodeValue(ec EncodeContext, vw ValueWriter, val ref
return fn(ec, vw, val)
}

// ValueDecoder is the interface implemented by types that can decode BSON to a provided Go type.
// valueDecoder is the interface implemented by types that can decode BSON to a provided Go type.
// Implementations should ensure that the value they receive is settable. Similar to ValueEncoderFunc,
// ValueDecoderFunc is provided to allow the use of a function with the correct signature as a
// ValueDecoder. A DecodeContext instance is provided and serves similar functionality to the
// EncodeContext.
type ValueDecoder interface {
type valueDecoder interface {
DecodeValue(DecodeContext, ValueReader, reflect.Value) error
}

Expand Down Expand Up @@ -314,17 +177,17 @@ type decodeAdapter struct {
typeDecoderFunc
}

var _ ValueDecoder = decodeAdapter{}
var _ valueDecoder = decodeAdapter{}
var _ typeDecoder = decodeAdapter{}

// decodeTypeOrValue calls decoder.decodeType is decoder is a typeDecoder. Otherwise, it allocates a new element of type
// t and calls decoder.DecodeValue on it.
func decodeTypeOrValue(decoder ValueDecoder, dc DecodeContext, vr ValueReader, t reflect.Type) (reflect.Value, error) {
func decodeTypeOrValue(decoder valueDecoder, dc DecodeContext, vr ValueReader, t reflect.Type) (reflect.Value, error) {
td, _ := decoder.(typeDecoder)
return decodeTypeOrValueWithInfo(decoder, td, dc, vr, t, true)
}

func decodeTypeOrValueWithInfo(vd ValueDecoder, td typeDecoder, dc DecodeContext, vr ValueReader, t reflect.Type, convert bool) (reflect.Value, error) {
func decodeTypeOrValueWithInfo(vd valueDecoder, td typeDecoder, dc DecodeContext, vr ValueReader, t reflect.Type, convert bool) (reflect.Value, error) {
if td != nil {
val, err := td.decodeType(dc, vr, t)
if err == nil && convert && val.Type() != t {
Expand Down
30 changes: 0 additions & 30 deletions bson/bsoncodec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,40 +7,10 @@
package bson

import (
"fmt"
"reflect"
"testing"
)

func ExampleValueEncoder() {
var _ ValueEncoderFunc = func(ec EncodeContext, vw ValueWriter, val reflect.Value) error {
if val.Kind() != reflect.String {
return ValueEncoderError{Name: "StringEncodeValue", Kinds: []reflect.Kind{reflect.String}, Received: val}
}

return vw.WriteString(val.String())
}
}

func ExampleValueDecoder() {
var _ ValueDecoderFunc = func(dc 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}
}

if vr.Type() != TypeString {
return fmt.Errorf("cannot decode %v into a string type", vr.Type())
}

str, err := vr.ReadString()
if err != nil {
return err
}
val.SetString(str)
return nil
}
}

type llCodec struct {
t *testing.T
decodeval interface{}
Expand Down
32 changes: 16 additions & 16 deletions bson/codec_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,20 @@ type typeEncoderCache struct {
cache sync.Map // map[reflect.Type]ValueEncoder
}

func (c *typeEncoderCache) Store(rt reflect.Type, enc ValueEncoder) {
func (c *typeEncoderCache) Store(rt reflect.Type, enc valueEncoder) {
c.cache.Store(rt, enc)
}

func (c *typeEncoderCache) Load(rt reflect.Type) (ValueEncoder, bool) {
func (c *typeEncoderCache) Load(rt reflect.Type) (valueEncoder, bool) {
if v, _ := c.cache.Load(rt); v != nil {
return v.(ValueEncoder), true
return v.(valueEncoder), true
}
return nil, false
}

func (c *typeEncoderCache) LoadOrStore(rt reflect.Type, enc ValueEncoder) ValueEncoder {
func (c *typeEncoderCache) LoadOrStore(rt reflect.Type, enc valueEncoder) valueEncoder {
if v, loaded := c.cache.LoadOrStore(rt, enc); loaded {
enc = v.(ValueEncoder)
enc = v.(valueEncoder)
}
return enc
}
Expand All @@ -62,20 +62,20 @@ type typeDecoderCache struct {
cache sync.Map // map[reflect.Type]ValueDecoder
}

func (c *typeDecoderCache) Store(rt reflect.Type, dec ValueDecoder) {
func (c *typeDecoderCache) Store(rt reflect.Type, dec valueDecoder) {
c.cache.Store(rt, dec)
}

func (c *typeDecoderCache) Load(rt reflect.Type) (ValueDecoder, bool) {
func (c *typeDecoderCache) Load(rt reflect.Type) (valueDecoder, bool) {
if v, _ := c.cache.Load(rt); v != nil {
return v.(ValueDecoder), true
return v.(valueDecoder), true
}
return nil, false
}

func (c *typeDecoderCache) LoadOrStore(rt reflect.Type, dec ValueDecoder) ValueDecoder {
func (c *typeDecoderCache) LoadOrStore(rt reflect.Type, dec valueDecoder) valueDecoder {
if v, loaded := c.cache.LoadOrStore(rt, dec); loaded {
dec = v.(ValueDecoder)
dec = v.(valueDecoder)
}
return dec
}
Expand All @@ -96,20 +96,20 @@ func (c *typeDecoderCache) Clone() *typeDecoderCache {
// is always the same (since different concrete types may implement the
// ValueEncoder interface).
type kindEncoderCacheEntry struct {
enc ValueEncoder
enc valueEncoder
}

type kindEncoderCache struct {
entries [reflect.UnsafePointer + 1]atomic.Value // *kindEncoderCacheEntry
}

func (c *kindEncoderCache) Store(rt reflect.Kind, enc ValueEncoder) {
func (c *kindEncoderCache) Store(rt reflect.Kind, enc valueEncoder) {
if enc != nil && rt < reflect.Kind(len(c.entries)) {
c.entries[rt].Store(&kindEncoderCacheEntry{enc: enc})
}
}

func (c *kindEncoderCache) Load(rt reflect.Kind) (ValueEncoder, bool) {
func (c *kindEncoderCache) Load(rt reflect.Kind) (valueEncoder, bool) {
if rt < reflect.Kind(len(c.entries)) {
if ent, ok := c.entries[rt].Load().(*kindEncoderCacheEntry); ok {
return ent.enc, ent.enc != nil
Expand All @@ -133,20 +133,20 @@ func (c *kindEncoderCache) Clone() *kindEncoderCache {
// is always the same (since different concrete types may implement the
// ValueDecoder interface).
type kindDecoderCacheEntry struct {
dec ValueDecoder
dec valueDecoder
}

type kindDecoderCache struct {
entries [reflect.UnsafePointer + 1]atomic.Value // *kindDecoderCacheEntry
}

func (c *kindDecoderCache) Store(rt reflect.Kind, dec ValueDecoder) {
func (c *kindDecoderCache) Store(rt reflect.Kind, dec valueDecoder) {
if rt < reflect.Kind(len(c.entries)) {
c.entries[rt].Store(&kindDecoderCacheEntry{dec: dec})
}
}

func (c *kindDecoderCache) Load(rt reflect.Kind) (ValueDecoder, bool) {
func (c *kindDecoderCache) Load(rt reflect.Kind) (valueDecoder, bool) {
if rt < reflect.Kind(len(c.entries)) {
if ent, ok := c.entries[rt].Load().(*kindDecoderCacheEntry); ok {
return ent.dec, ent.dec != nil
Expand Down
4 changes: 2 additions & 2 deletions bson/codec_cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,15 +134,15 @@ func TestKindCacheClone(t *testing.T) {
func TestKindCacheEncoderNilEncoder(t *testing.T) {
t.Run("Encoder", func(t *testing.T) {
c := new(kindEncoderCache)
c.Store(reflect.Invalid, ValueEncoder(nil))
c.Store(reflect.Invalid, valueEncoder(nil))
v, ok := c.Load(reflect.Invalid)
if v != nil || ok {
t.Errorf("Load of nil ValueEncoder should return: nil, false; got: %v, %t", v, ok)
}
})
t.Run("Decoder", func(t *testing.T) {
c := new(kindDecoderCache)
c.Store(reflect.Invalid, ValueDecoder(nil))
c.Store(reflect.Invalid, valueDecoder(nil))
v, ok := c.Load(reflect.Invalid)
if v != nil || ok {
t.Errorf("Load of nil ValueDecoder should return: nil, false; got: %v, %t", v, ok)
Expand Down
Loading

0 comments on commit 1834500

Please sign in to comment.