Skip to content

Commit 92e7984

Browse files
author
Divjot Arora
committed
GODRIVER-1680 Add typeDecoder and dedicated bson.D decoder
This commit also changes EmptyInterfaceCodec to implement typeDecoder. Co-authored by: David Bartley <[email protected]>
1 parent 4979f16 commit 92e7984

File tree

4 files changed

+135
-13
lines changed

4 files changed

+135
-13
lines changed

bson/bsoncodec/bsoncodec.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ import (
1515
"go.mongodb.org/mongo-driver/bson/bsontype"
1616
)
1717

18+
var (
19+
emptyValue = reflect.Value{}
20+
)
21+
1822
// Marshaler is an interface implemented by types that can marshal themselves
1923
// into a BSON document represented as bytes. The bytes returned must be a valid
2024
// BSON document if the error is nil.
@@ -156,6 +160,41 @@ func (fn ValueDecoderFunc) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader,
156160
return fn(dc, vr, val)
157161
}
158162

163+
// typeDecoder is the interface implemented by types that can handle the decoding of a value by
164+
type typeDecoder interface {
165+
decodeType(DecodeContext, bsonrw.ValueReader, reflect.Type) (reflect.Value, error)
166+
}
167+
168+
// typeDecoderFunc is an adapter function that allows a function with the correct signature to be
169+
// used as a TypeDecoder.
170+
type typeDecoderFunc func(DecodeContext, bsonrw.ValueReader, reflect.Type) (reflect.Value, error)
171+
172+
func (fn typeDecoderFunc) decodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
173+
return fn(dc, vr, t)
174+
}
175+
176+
// ValueTypeDecoderFunc is an adapter struct that allows two functions with the correct signature
177+
// to be used as a ValueTypeDecoder.
178+
type decodeAdapter struct {
179+
ValueDecoderFunc
180+
typeDecoderFunc
181+
}
182+
183+
var _ ValueDecoder = decodeAdapter{}
184+
var _ typeDecoder = decodeAdapter{}
185+
186+
// decodeTypeOrValue calls decoder.decodeType is decoder is a typeDecoder. Otherwise, it allocates a new element of
187+
// type t and calls decoder.DecodeValue on it.
188+
func decodeTypeOrValue(decoder ValueDecoder, dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
189+
if typeDecoder, ok := decoder.(typeDecoder); ok {
190+
return typeDecoder.decodeType(dc, vr, t)
191+
}
192+
193+
val := reflect.New(t).Elem()
194+
err := decoder.DecodeValue(dc, vr, val)
195+
return val, err
196+
}
197+
159198
// CodecZeroer is the interface implemented by Codecs that can also determine if
160199
// a value of the type that would be encoded is zero.
161200
type CodecZeroer interface {

bson/bsoncodec/default_value_decoders.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ func (dvd DefaultValueDecoders) RegisterDefaultDecoders(rb *RegistryBuilder) {
4040
}
4141

4242
rb.
43+
RegisterTypeDecoder(tD, ValueDecoderFunc(dvd.DDecodeValue)).
4344
RegisterTypeDecoder(tBinary, ValueDecoderFunc(dvd.BinaryDecodeValue)).
4445
RegisterTypeDecoder(tUndefined, ValueDecoderFunc(dvd.UndefinedDecodeValue)).
4546
RegisterTypeDecoder(tDateTime, ValueDecoderFunc(dvd.DateTimeDecodeValue)).
@@ -104,6 +105,69 @@ func (dvd DefaultValueDecoders) RegisterDefaultDecoders(rb *RegistryBuilder) {
104105
RegisterHookDecoder(tUnmarshaler, ValueDecoderFunc(dvd.UnmarshalerDecodeValue))
105106
}
106107

108+
// DDecodeValue is the ValueDecoderFunc for primitive.D instances.
109+
func (dvd DefaultValueDecoders) DDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
110+
if !val.IsValid() || !val.CanSet() || val.Type() != tD {
111+
return ValueDecoderError{Name: "DDecodeValue", Kinds: []reflect.Kind{reflect.Slice}, Received: val}
112+
}
113+
114+
switch vrType := vr.Type(); vrType {
115+
case bsontype.Type(0), bsontype.EmbeddedDocument:
116+
dc.Ancestor = tD
117+
case bsontype.Null:
118+
val.Set(reflect.Zero(val.Type()))
119+
return vr.ReadNull()
120+
default:
121+
return fmt.Errorf("cannot decode %v into a primitive.D", vrType)
122+
}
123+
124+
dr, err := vr.ReadDocument()
125+
if err != nil {
126+
return err
127+
}
128+
129+
decoder, err := dc.LookupDecoder(tEmpty)
130+
if err != nil {
131+
return err
132+
}
133+
typeDecoder, isTypeDecoder := decoder.(typeDecoder)
134+
135+
var elems primitive.D
136+
if !val.IsNil() {
137+
val.SetLen(0)
138+
elems = val.Interface().(primitive.D)
139+
} else {
140+
elems = make(primitive.D, 0)
141+
}
142+
143+
for {
144+
key, elemVr, err := dr.ReadElement()
145+
if err == bsonrw.ErrEOD {
146+
break
147+
} else if err != nil {
148+
return err
149+
}
150+
151+
// Delegate out to the typeDecoder for interface{} if it exists. If not, create a new interface{} value and
152+
// delegate out to the ValueDecoder.
153+
var elem reflect.Value
154+
if isTypeDecoder {
155+
elem, err = typeDecoder.decodeType(dc, elemVr, tEmpty)
156+
} else {
157+
elem = reflect.New(tEmpty).Elem()
158+
err = decoder.DecodeValue(dc, elemVr, elem)
159+
}
160+
if err != nil {
161+
return err
162+
}
163+
164+
elems = append(elems, primitive.E{Key: key, Value: elem.Interface()})
165+
}
166+
167+
val.Set(reflect.ValueOf(elems))
168+
return nil
169+
}
170+
107171
// BooleanDecodeValue is the ValueDecoderFunc for bool types.
108172
func (dvd DefaultValueDecoders) BooleanDecodeValue(dctx DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
109173
if !val.IsValid() || !val.CanSet() || val.Kind() != reflect.Bool {

bson/bsoncodec/default_value_decoders_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1322,7 +1322,11 @@ func TestDefaultValueDecoders(t *testing.T) {
13221322
nil,
13231323
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String, Return: string("not-valid-%%%%://")},
13241324
bsonrwtest.ReadString,
1325-
errors.New("parse not-valid-%%%%://: first path segment in URL cannot contain colon"),
1325+
&url.Error{
1326+
Op: "parse",
1327+
URL: "not-valid-%%%%://",
1328+
Err: errors.New("first path segment in URL cannot contain colon"),
1329+
},
13261330
},
13271331
{
13281332
"can set false",

bson/bsoncodec/empty_interface_codec.go

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ type EmptyInterfaceCodec struct {
2222
DecodeBinaryAsSlice bool
2323
}
2424

25-
var _ ValueCodec = &EmptyInterfaceCodec{}
25+
var (
26+
_ ValueCodec = defaultEmptyInterfaceCodec
27+
_ typeDecoder = defaultEmptyInterfaceCodec
28+
)
2629

2730
// NewEmptyInterfaceCodec returns a EmptyInterfaceCodec with options opts.
2831
func NewEmptyInterfaceCodec(opts ...*bsonoptions.EmptyInterfaceCodecOptions) *EmptyInterfaceCodec {
@@ -86,40 +89,52 @@ func (eic EmptyInterfaceCodec) getEmptyInterfaceDecodeType(dc DecodeContext, val
8689
return nil, err
8790
}
8891

89-
// DecodeValue is the ValueDecoderFunc for interface{}.
90-
func (eic EmptyInterfaceCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
91-
if !val.CanSet() || val.Type() != tEmpty {
92-
return ValueDecoderError{Name: "EmptyInterfaceDecodeValue", Types: []reflect.Type{tEmpty}, Received: val}
92+
func (eic EmptyInterfaceCodec) decodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
93+
if t != tEmpty {
94+
return emptyValue, ValueDecoderError{Name: "EmptyInterfaceDecodeValue", Types: []reflect.Type{tEmpty}, Received: reflect.Zero(t)}
9395
}
9496

9597
rtype, err := eic.getEmptyInterfaceDecodeType(dc, vr.Type())
9698
if err != nil {
9799
switch vr.Type() {
98100
case bsontype.Null:
99-
val.Set(reflect.Zero(val.Type()))
100-
return vr.ReadNull()
101+
return reflect.Zero(t), vr.ReadNull()
101102
default:
102-
return err
103+
return emptyValue, err
103104
}
104105
}
105106

106107
decoder, err := dc.LookupDecoder(rtype)
107108
if err != nil {
108-
return err
109+
return emptyValue, err
109110
}
110111

111-
elem := reflect.New(rtype).Elem()
112-
err = decoder.DecodeValue(dc, vr, elem)
112+
elem, err := decodeTypeOrValue(decoder, dc, vr, rtype)
113113
if err != nil {
114-
return err
114+
return emptyValue, err
115115
}
116+
116117
if eic.DecodeBinaryAsSlice && rtype == tBinary {
117118
binElem := elem.Interface().(primitive.Binary)
118119
if binElem.Subtype == bsontype.BinaryGeneric || binElem.Subtype == bsontype.BinaryBinaryOld {
119120
elem = reflect.ValueOf(binElem.Data)
120121
}
121122
}
122123

124+
return elem, nil
125+
}
126+
127+
// DecodeValue is the ValueDecoderFunc for interface{}.
128+
func (eic EmptyInterfaceCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
129+
if !val.CanSet() || val.Type() != tEmpty {
130+
return ValueDecoderError{Name: "EmptyInterfaceDecodeValue", Types: []reflect.Type{tEmpty}, Received: val}
131+
}
132+
133+
elem, err := eic.decodeType(dc, vr, val.Type())
134+
if err != nil {
135+
return err
136+
}
137+
123138
val.Set(elem)
124139
return nil
125140
}

0 commit comments

Comments
 (0)