Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
qingyang-hu committed May 1, 2024
1 parent 1834500 commit dfdb9c3
Show file tree
Hide file tree
Showing 32 changed files with 431 additions and 400 deletions.
6 changes: 5 additions & 1 deletion bson/array_codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@ import (
// arrayCodec is the Codec used for bsoncore.Array values.
type arrayCodec struct{}

var (
defaultArrayCodec = &arrayCodec{}
)

// EncodeValue is the ValueEncoder for bsoncore.Array values.
func (ac *arrayCodec) EncodeValue(_ EncodeContext, vw ValueWriter, val reflect.Value) error {
func (ac *arrayCodec) EncodeValue(_ *Registry, vw ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Type() != tCoreArray {
return ValueEncoderError{Name: "CoreArrayEncodeValue", Types: []reflect.Type{tCoreArray}, Received: val}
}
Expand Down
46 changes: 13 additions & 33 deletions bson/bsoncodec.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,25 +72,6 @@ func (vde ValueDecoderError) Error() string {
return fmt.Sprintf("%s can only decode valid and settable %s, but got %s", vde.Name, strings.Join(typeKinds, ", "), received)
}

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

// minSize 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.
minSize bool

errorOnInlineDuplicates bool
stringifyMapKeysWithFmt bool
nilMapAsEmpty bool
nilSliceAsEmpty bool
nilByteSliceAsEmpty bool
omitZeroStruct bool
useJSONStructTags bool
}

// DecodeContext is the contextual information required for a Codec to decode a
// value.
type DecodeContext struct {
Expand Down Expand Up @@ -122,31 +103,30 @@ type DecodeContext struct {
zeroStructs bool
}

// 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 {
EncodeValue(EncodeContext, ValueWriter, reflect.Value) error
// is provided to allow use of a function with the correct signature as a ValueEncoder. A pointer
// to a Registry instance is provided to allow implementations to lookup further ValueEncoders.
type ValueEncoder interface {
EncodeValue(*Registry, ValueWriter, reflect.Value) error
}

// ValueEncoderFunc is an adapter function that allows a function with the correct signature to be
// used as a ValueEncoder.
type ValueEncoderFunc func(EncodeContext, ValueWriter, reflect.Value) error
type ValueEncoderFunc func(*Registry, ValueWriter, reflect.Value) error

// EncodeValue implements the ValueEncoder interface.
func (fn ValueEncoderFunc) EncodeValue(ec EncodeContext, vw ValueWriter, val reflect.Value) error {
return fn(ec, vw, val)
func (fn ValueEncoderFunc) EncodeValue(reg *Registry, vw ValueWriter, val reflect.Value) error {
return fn(reg, 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 @@ -177,17 +157,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
2 changes: 1 addition & 1 deletion bson/bsoncodec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type llCodec struct {
err error
}

func (llc *llCodec) EncodeValue(_ EncodeContext, _ ValueWriter, i interface{}) error {
func (llc *llCodec) EncodeValue(_ *Registry, _ ValueWriter, i interface{}) error {
if llc.err != nil {
return llc.err
}
Expand Down
11 changes: 5 additions & 6 deletions bson/byte_slice_codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,16 @@ type byteSliceCodec struct {
encodeNilAsEmpty bool
}

// 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)
var (
defaultByteSliceCodec = &byteSliceCodec{}
)

// EncodeValue is the ValueEncoder for []byte.
func (bsc *byteSliceCodec) EncodeValue(ec EncodeContext, vw ValueWriter, val reflect.Value) error {
func (bsc *byteSliceCodec) EncodeValue(_ *Registry, 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 {
return vw.WriteNull()
}
return vw.WriteBinary(val.Interface().([]byte))
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
20 changes: 9 additions & 11 deletions bson/cond_addr_codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,31 @@ import (

// condAddrEncoder is the encoder used when a pointer to the encoding value has an encoder.
type condAddrEncoder struct {
canAddrEnc valueEncoder
elseEnc valueEncoder
canAddrEnc ValueEncoder
elseEnc ValueEncoder
}

var _ valueEncoder = (*condAddrEncoder)(nil)

// EncodeValue is the ValueEncoderFunc for a value that may be addressable.
func (cae *condAddrEncoder) EncodeValue(ec EncodeContext, vw ValueWriter, val reflect.Value) error {
func (cae *condAddrEncoder) EncodeValue(reg *Registry, vw ValueWriter, val reflect.Value) error {
if val.CanAddr() {
return cae.canAddrEnc.EncodeValue(ec, vw, val)
return cae.canAddrEnc.EncodeValue(reg, vw, val)
}
if cae.elseEnc != nil {
return cae.elseEnc.EncodeValue(ec, vw, val)
return cae.elseEnc.EncodeValue(reg, vw, val)
}
return ErrNoEncoder{Type: val.Type()}
}

// condAddrDecoder is the decoder used when a pointer to the value has a decoder.
type condAddrDecoder struct {
canAddrDec valueDecoder
elseDec valueDecoder
canAddrDec ValueDecoder
elseDec ValueDecoder
}

var _ valueDecoder = (*condAddrDecoder)(nil)
var _ ValueDecoder = (*condAddrDecoder)(nil)

// newCondAddrDecoder returns an CondAddrDecoder.
func newCondAddrDecoder(canAddrDec, elseDec valueDecoder) *condAddrDecoder {
func newCondAddrDecoder(canAddrDec, elseDec ValueDecoder) *condAddrDecoder {
decoder := condAddrDecoder{canAddrDec: canAddrDec, elseDec: elseDec}
return &decoder
}
Expand Down
8 changes: 4 additions & 4 deletions bson/cond_addr_codec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ func TestCondAddrCodec(t *testing.T) {

t.Run("addressEncode", func(t *testing.T) {
invoked := 0
encode1 := ValueEncoderFunc(func(EncodeContext, ValueWriter, reflect.Value) error {
encode1 := ValueEncoderFunc(func(*Registry, ValueWriter, reflect.Value) error {
invoked = 1
return nil
})
encode2 := ValueEncoderFunc(func(EncodeContext, ValueWriter, reflect.Value) error {
encode2 := ValueEncoderFunc(func(*Registry, ValueWriter, reflect.Value) error {
invoked = 2
return nil
})
Expand All @@ -42,7 +42,7 @@ func TestCondAddrCodec(t *testing.T) {
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := condEncoder.EncodeValue(EncodeContext{}, rw, tc.val)
err := condEncoder.EncodeValue(nil, rw, tc.val)
assert.Nil(t, err, "CondAddrEncoder error: %v", err)

assert.Equal(t, invoked, tc.invoked, "Expected function %v to be called, called %v", tc.invoked, invoked)
Expand All @@ -51,7 +51,7 @@ func TestCondAddrCodec(t *testing.T) {

t.Run("error", func(t *testing.T) {
errEncoder := &condAddrEncoder{canAddrEnc: encode1, elseEnc: nil}
err := errEncoder.EncodeValue(EncodeContext{}, rw, unaddressable)
err := errEncoder.EncodeValue(nil, rw, unaddressable)
want := ErrNoEncoder{Type: unaddressable.Type()}
assert.Equal(t, err, want, "expected error %v, got %v", want, err)
})
Expand Down
26 changes: 13 additions & 13 deletions bson/default_value_decoders.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,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, &byteSliceCodec{})
reg.RegisterTypeDecoder(tTime, &timeCodec{})
reg.RegisterTypeDecoder(tEmpty, &emptyInterfaceCodec{})
reg.RegisterTypeDecoder(tCoreArray, &arrayCodec{})
reg.RegisterTypeDecoder(tByteSlice, defaultByteSliceCodec)
reg.RegisterTypeDecoder(tTime, defaultTimeCodec)
reg.RegisterTypeDecoder(tEmpty, defaultEmptyInterfaceCodec)
reg.RegisterTypeDecoder(tCoreArray, defaultArrayCodec)
reg.RegisterTypeDecoder(tOID, decodeAdapter{objectIDDecodeValue, objectIDDecodeType})
reg.RegisterTypeDecoder(tDecimal, decodeAdapter{decimal128DecodeValue, decimal128DecodeType})
reg.RegisterTypeDecoder(tJSONNumber, decodeAdapter{jsonNumberDecodeValue, jsonNumberDecodeType})
Expand All @@ -72,18 +72,18 @@ func registerDefaultDecoders(reg *Registry) {
reg.RegisterKindDecoder(reflect.Int16, intDecoder)
reg.RegisterKindDecoder(reflect.Int32, intDecoder)
reg.RegisterKindDecoder(reflect.Int64, intDecoder)
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.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.Float32, floatDecoder)
reg.RegisterKindDecoder(reflect.Float64, floatDecoder)
reg.RegisterKindDecoder(reflect.Array, ValueDecoderFunc(arrayDecodeValue))
reg.RegisterKindDecoder(reflect.Map, &mapCodec{})
reg.RegisterKindDecoder(reflect.Slice, &sliceCodec{})
reg.RegisterKindDecoder(reflect.String, &stringCodec{})
reg.RegisterKindDecoder(reflect.Struct, newStructCodec(DefaultStructTagParser))
reg.RegisterKindDecoder(reflect.Map, defaultMapCodec)
reg.RegisterKindDecoder(reflect.Slice, defaultSliceCodec)
reg.RegisterKindDecoder(reflect.String, defaultStringCodec)
reg.RegisterKindDecoder(reflect.Struct, defaultStructCodec)
reg.RegisterKindDecoder(reflect.Ptr, &pointerCodec{})
reg.RegisterTypeMapEntry(TypeDouble, tFloat64)
reg.RegisterTypeMapEntry(TypeString, tString)
Expand Down
4 changes: 2 additions & 2 deletions bson/default_value_decoders_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func TestDefaultValueDecoders(t *testing.T) {

testCases := []struct {
name string
vd valueDecoder
vd ValueDecoder
subtests []subtest
}{
{
Expand Down Expand Up @@ -3566,7 +3566,7 @@ func TestDefaultValueDecoders(t *testing.T) {
val interface{}
vr ValueReader
registry *Registry // buildDefaultRegistry will be used if this is nil
decoder valueDecoder
decoder ValueDecoder
err error
}{
{
Expand Down

0 comments on commit dfdb9c3

Please sign in to comment.