Skip to content

Commit d305fc0

Browse files
committed
Update codec system to use reflect.Value
Add support for pointers to the BSON codec system. When doing an interface lookup for a decoder, we now check if the type or a pointer to the type implement the interface. If either one does, we return the decoder for that interface. This change changes the ValueEncoder and ValueDecoder interfaces to use reflect.Value instead of interface{}. Move the bson.D family of types into the primitive package. GODRIVER-535 GODRIVER-598 GODRIVER-588 GODRIVER-645 GODRIVER-662 GODRIVER-649 GODRIVER-670 Change-Id: Idec68f74e354973160bd59f9f8fef009f026f943
1 parent c1c5633 commit d305fc0

25 files changed

+3311
-3260
lines changed

bson/bson.go

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import (
1313
"math"
1414
"strconv"
1515
"strings"
16+
17+
"github.com/mongodb/mongo-go-driver/bson/primitive"
1618
)
1719

1820
// Zeroer allows custom struct types to implement a report of zero
@@ -32,22 +34,7 @@ type Zeroer interface {
3234
//
3335
// This type should be used in situations where order matters, such as MongoDB commands. If the
3436
// order is not important, a map is more comfortable and concise.
35-
type D []E
36-
37-
// Map creates a map from the elements of the D.
38-
func (d D) Map() M {
39-
m := make(M, len(d))
40-
for _, e := range d {
41-
m[e.Key] = e.Value
42-
}
43-
return m
44-
}
45-
46-
// E represents a BSON element for a D. It is usually used inside a D.
47-
type E struct {
48-
Key string
49-
Value interface{}
50-
}
37+
type D = primitive.D
5138

5239
// M is an unordered, concise representation of a BSON Document. It should generally be used to
5340
// serialize BSON when the order of the elements of a BSON document do not matter. If the element
@@ -59,7 +46,7 @@ type E struct {
5946
//
6047
// This type is handled in the encoders as a regular map[string]interface{}. The elements will be
6148
// serialized in an undefined, random order, and the order will be different each time.
62-
type M map[string]interface{}
49+
type M = primitive.M
6350

6451
// An A represents a BSON array. This type can be used to represent a BSON array in a concise and
6552
// readable manner. It should generally be used when serializing to BSON. For deserializing, the
@@ -69,7 +56,7 @@ type M map[string]interface{}
6956
//
7057
// bson.A{"bar", "world", 3.14159, bson.D{{"qux", 12345}}}
7158
//
72-
type A []interface{}
59+
type A = primitive.A
7360

7461
func formatDouble(f float64) string {
7562
var s string

bson/bson_corpus_spec_test.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"fmt"
1414
"io/ioutil"
1515
"path"
16+
"reflect"
1617
"strconv"
1718
"strings"
1819
"testing"
@@ -61,7 +62,7 @@ type parseErrorTestCase struct {
6162

6263
const dataDir = "../data"
6364

64-
var pc PrimitiveCodecs
65+
var pc bsonx.PrimitiveCodecs
6566
var dvd bsoncodec.DefaultValueDecoders
6667
var dve bsoncodec.DefaultValueEncoders
6768

@@ -163,10 +164,10 @@ func normalizeRelaxedDouble(t *testing.T, key string, rEJ string) string {
163164

164165
// bsonToNative decodes the BSON bytes (b) into a native Document
165166
func bsonToNative(t *testing.T, b []byte, bType, testDesc string) bsonx.Doc {
166-
var doc bsonx.Doc
167-
err := pc.x.DocumentDecodeValue(dc, bsonrw.NewBSONDocumentReader(b), &doc)
167+
doc := reflect.New(reflect.TypeOf(bsonx.Doc{})).Elem()
168+
err := pc.DocumentDecodeValue(dc, bsonrw.NewBSONDocumentReader(b), doc)
168169
expectNoError(t, err, fmt.Sprintf("%s: decoding %s BSON", testDesc, bType))
169-
return doc
170+
return doc.Interface().(bsonx.Doc)
170171
}
171172

172173
// nativeToBSON encodes the native Document (doc) into canonical BSON and compares it to the expected
@@ -175,7 +176,7 @@ func nativeToBSON(t *testing.T, cB []byte, doc bsonx.Doc, testDesc, bType, docSr
175176
actualB := new(bytes.Buffer)
176177
vw, err := bsonrw.NewBSONValueWriter(actualB)
177178
expectNoError(t, err, fmt.Sprintf("%s: creating ValueWriter", testDesc))
178-
err = pc.x.DocumentEncodeValue(ec, vw, doc)
179+
err = pc.DocumentEncodeValue(ec, vw, reflect.ValueOf(doc))
179180
expectNoError(t, err, fmt.Sprintf("%s: encoding %s BSON", testDesc, bType))
180181

181182
if diff := cmp.Diff(cB, actualB.Bytes()); diff != "" {
@@ -299,8 +300,8 @@ func runTest(t *testing.T, file string) {
299300
b, err := hex.DecodeString(d.Bson)
300301
expectNoError(t, err, d.Description)
301302

302-
var doc bsonx.Doc
303-
err = pc.x.DocumentDecodeValue(dc, bsonrw.NewBSONDocumentReader(b), &doc)
303+
doc := reflect.New(reflect.TypeOf(bsonx.Doc{})).Elem()
304+
err = pc.DocumentDecodeValue(dc, bsonrw.NewBSONDocumentReader(b), doc)
304305
expectError(t, err, fmt.Sprintf("%s: expected decode error", d.Description))
305306
}
306307

bson/bsoncodec/bsoncodec.go

Lines changed: 51 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package bsoncodec
88

99
import (
1010
"fmt"
11+
"reflect"
1112
"strings"
1213

1314
"github.com/mongodb/mongo-go-driver/bson/bsonrw"
@@ -45,36 +46,60 @@ type ValueUnmarshaler interface {
4546
UnmarshalBSONValue(bsontype.Type, []byte) error
4647
}
4748

48-
// ValueEncoderError is an error returned from a ValueEncoder when the provided
49-
// value can't be encoded by the ValueEncoder.
49+
// ValueEncoderError is an error returned from a ValueEncoder when the provided value can't be
50+
// encoded by the ValueEncoder.
5051
type ValueEncoderError struct {
5152
Name string
52-
Types []interface{}
53-
Received interface{}
53+
Types []reflect.Type
54+
Kinds []reflect.Kind
55+
Received reflect.Value
5456
}
5557

5658
func (vee ValueEncoderError) Error() string {
57-
types := make([]string, 0, len(vee.Types))
59+
typeKinds := make([]string, 0, len(vee.Types)+len(vee.Kinds))
5860
for _, t := range vee.Types {
59-
types = append(types, fmt.Sprintf("%T", t))
61+
typeKinds = append(typeKinds, t.String())
6062
}
61-
return fmt.Sprintf("%s can only process %s, but got a %T", vee.Name, strings.Join(types, ", "), vee.Received)
63+
for _, k := range vee.Kinds {
64+
if k == reflect.Map {
65+
typeKinds = append(typeKinds, "map[string]*")
66+
continue
67+
}
68+
typeKinds = append(typeKinds, k.String())
69+
}
70+
received := vee.Received.Kind().String()
71+
if vee.Received.IsValid() {
72+
received = vee.Received.Type().String()
73+
}
74+
return fmt.Sprintf("%s can only encode valid %s, but got %s", vee.Name, strings.Join(typeKinds, ", "), received)
6275
}
6376

64-
// ValueDecoderError is an error returned from a ValueDecoder when the provided
65-
// value can't be decoded by the ValueDecoder.
77+
// ValueDecoderError is an error returned from a ValueDecoder when the provided value can't be
78+
// decoded by the ValueDecoder.
6679
type ValueDecoderError struct {
6780
Name string
68-
Types []interface{}
69-
Received interface{}
81+
Types []reflect.Type
82+
Kinds []reflect.Kind
83+
Received reflect.Value
7084
}
7185

7286
func (vde ValueDecoderError) Error() string {
73-
types := make([]string, 0, len(vde.Types))
87+
typeKinds := make([]string, 0, len(vde.Types)+len(vde.Kinds))
7488
for _, t := range vde.Types {
75-
types = append(types, fmt.Sprintf("%T", t))
89+
typeKinds = append(typeKinds, t.String())
90+
}
91+
for _, k := range vde.Kinds {
92+
if k == reflect.Map {
93+
typeKinds = append(typeKinds, "map[string]*")
94+
continue
95+
}
96+
typeKinds = append(typeKinds, k.String())
97+
}
98+
received := vde.Received.Kind().String()
99+
if vde.Received.IsValid() {
100+
received = vde.Received.Type().String()
76101
}
77-
return fmt.Sprintf("%s can only process %s, but got a %T", vde.Name, strings.Join(types, ", "), vde.Received)
102+
return fmt.Sprintf("%s can only decode valid and settable %s, but got %s", vde.Name, strings.Join(typeKinds, ", "), received)
78103
}
79104

80105
// EncodeContext is the contextual information required for a Codec to encode a
@@ -98,36 +123,31 @@ type ValueCodec interface {
98123
ValueDecoder
99124
}
100125

101-
// ValueEncoder is the interface implemented by types that can handle the
102-
// encoding of a value. Implementations must handle both values and
103-
// pointers to values.
126+
// ValueEncoder is the interface implemented by types that can handle the encoding of a value.
104127
type ValueEncoder interface {
105-
EncodeValue(EncodeContext, bsonrw.ValueWriter, interface{}) error
128+
EncodeValue(EncodeContext, bsonrw.ValueWriter, reflect.Value) error
106129
}
107130

108-
// ValueEncoderFunc is an adapter function that allows a function with the
109-
// correct signature to be used as a ValueEncoder.
110-
type ValueEncoderFunc func(EncodeContext, bsonrw.ValueWriter, interface{}) error
131+
// ValueEncoderFunc is an adapter function that allows a function with the correct signature to be
132+
// used as a ValueEncoder.
133+
type ValueEncoderFunc func(EncodeContext, bsonrw.ValueWriter, reflect.Value) error
111134

112135
// EncodeValue implements the ValueEncoder interface.
113-
func (fn ValueEncoderFunc) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val interface{}) error {
136+
func (fn ValueEncoderFunc) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
114137
return fn(ec, vw, val)
115138
}
116139

117-
// ValueDecoder is the interface implemented by types that can handle the
118-
// decoding of a value. Implementations must handle pointers to values,
119-
// including pointers to pointer values. The implementation may create a new
120-
// value and assign it to the pointer if necessary.
140+
// ValueDecoder is the interface implemented by types that can handle the decoding of a value.
121141
type ValueDecoder interface {
122-
DecodeValue(DecodeContext, bsonrw.ValueReader, interface{}) error
142+
DecodeValue(DecodeContext, bsonrw.ValueReader, reflect.Value) error
123143
}
124144

125-
// ValueDecoderFunc is an adapter function that allows a function with the
126-
// correct signature to be used as a ValueDecoder.
127-
type ValueDecoderFunc func(DecodeContext, bsonrw.ValueReader, interface{}) error
145+
// ValueDecoderFunc is an adapter function that allows a function with the correct signature to be
146+
// used as a ValueDecoder.
147+
type ValueDecoderFunc func(DecodeContext, bsonrw.ValueReader, reflect.Value) error
128148

129149
// DecodeValue implements the ValueDecoder interface.
130-
func (fn ValueDecoderFunc) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val interface{}) error {
150+
func (fn ValueDecoderFunc) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
131151
return fn(dc, vr, val)
132152
}
133153

bson/bsoncodec/bsoncodec_test.go

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -91,22 +91,16 @@ func (llc *llCodec) EncodeValue(_ EncodeContext, _ bsonrw.ValueWriter, i interfa
9191
return nil
9292
}
9393

94-
func (llc *llCodec) DecodeValue(_ DecodeContext, _ bsonrw.ValueReader, i interface{}) error {
94+
func (llc *llCodec) DecodeValue(_ DecodeContext, _ bsonrw.ValueReader, val reflect.Value) error {
9595
if llc.err != nil {
9696
return llc.err
9797
}
9898

99-
val := reflect.ValueOf(i)
100-
if val.Type().Kind() != reflect.Ptr {
101-
llc.t.Errorf("Value provided to DecodeValue must be a pointer, but got %T", i)
99+
if !reflect.TypeOf(llc.decodeval).AssignableTo(val.Type()) {
100+
llc.t.Errorf("decodeval must be assignable to val provided to DecodeValue, but is not. decodeval %T; val %T", llc.decodeval, val)
102101
return nil
103102
}
104103

105-
if !reflect.TypeOf(llc.decodeval).AssignableTo(val.Type().Elem()) {
106-
llc.t.Errorf("decodeval must be assignable to i provided to DecodeValue, but is not. decodeval %T; i %T", llc.decodeval, i)
107-
return nil
108-
}
109-
110-
val.Elem().Set(reflect.ValueOf(llc.decodeval))
104+
val.Set(reflect.ValueOf(llc.decodeval))
111105
return nil
112106
}

0 commit comments

Comments
 (0)