empty_interface_codec.go raw
1 // Copyright (C) MongoDB, Inc. 2017-present.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may
4 // not use this file except in compliance with the License. You may obtain
5 // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
7 package bsoncodec
8
9 import (
10 "reflect"
11
12 "go.mongodb.org/mongo-driver/bson/bsonoptions"
13 "go.mongodb.org/mongo-driver/bson/bsonrw"
14 "go.mongodb.org/mongo-driver/bson/bsontype"
15 "go.mongodb.org/mongo-driver/bson/primitive"
16 )
17
18 // EmptyInterfaceCodec is the Codec used for interface{} values.
19 //
20 // Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the
21 // EmptyInterfaceCodec registered.
22 type EmptyInterfaceCodec struct {
23 // DecodeBinaryAsSlice causes DecodeValue to unmarshal BSON binary field values that are the
24 // "Generic" or "Old" BSON binary subtype as a Go byte slice instead of a primitive.Binary.
25 //
26 // Deprecated: Use bson.Decoder.BinaryAsSlice instead.
27 DecodeBinaryAsSlice bool
28 }
29
30 var (
31 defaultEmptyInterfaceCodec = NewEmptyInterfaceCodec()
32
33 // Assert that defaultEmptyInterfaceCodec satisfies the typeDecoder interface, which allows it
34 // to be used by collection type decoders (e.g. map, slice, etc) to set individual values in a
35 // collection.
36 _ typeDecoder = defaultEmptyInterfaceCodec
37 )
38
39 // NewEmptyInterfaceCodec returns a EmptyInterfaceCodec with options opts.
40 //
41 // Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the
42 // EmptyInterfaceCodec registered.
43 func NewEmptyInterfaceCodec(opts ...*bsonoptions.EmptyInterfaceCodecOptions) *EmptyInterfaceCodec {
44 interfaceOpt := bsonoptions.MergeEmptyInterfaceCodecOptions(opts...)
45
46 codec := EmptyInterfaceCodec{}
47 if interfaceOpt.DecodeBinaryAsSlice != nil {
48 codec.DecodeBinaryAsSlice = *interfaceOpt.DecodeBinaryAsSlice
49 }
50 return &codec
51 }
52
53 // EncodeValue is the ValueEncoderFunc for interface{}.
54 func (eic EmptyInterfaceCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
55 if !val.IsValid() || val.Type() != tEmpty {
56 return ValueEncoderError{Name: "EmptyInterfaceEncodeValue", Types: []reflect.Type{tEmpty}, Received: val}
57 }
58
59 if val.IsNil() {
60 return vw.WriteNull()
61 }
62 encoder, err := ec.LookupEncoder(val.Elem().Type())
63 if err != nil {
64 return err
65 }
66
67 return encoder.EncodeValue(ec, vw, val.Elem())
68 }
69
70 func (eic EmptyInterfaceCodec) getEmptyInterfaceDecodeType(dc DecodeContext, valueType bsontype.Type) (reflect.Type, error) {
71 isDocument := valueType == bsontype.Type(0) || valueType == bsontype.EmbeddedDocument
72 if isDocument {
73 if dc.defaultDocumentType != nil {
74 // If the bsontype is an embedded document and the DocumentType is set on the DecodeContext, then return
75 // that type.
76 return dc.defaultDocumentType, nil
77 }
78 if dc.Ancestor != nil {
79 // Using ancestor information rather than looking up the type map entry forces consistent decoding.
80 // If we're decoding into a bson.D, subdocuments should also be decoded as bson.D, even if a type map entry
81 // has been registered.
82 return dc.Ancestor, nil
83 }
84 }
85
86 rtype, err := dc.LookupTypeMapEntry(valueType)
87 if err == nil {
88 return rtype, nil
89 }
90
91 if isDocument {
92 // For documents, fallback to looking up a type map entry for bsontype.Type(0) or bsontype.EmbeddedDocument,
93 // depending on the original valueType.
94 var lookupType bsontype.Type
95 switch valueType {
96 case bsontype.Type(0):
97 lookupType = bsontype.EmbeddedDocument
98 case bsontype.EmbeddedDocument:
99 lookupType = bsontype.Type(0)
100 }
101
102 rtype, err = dc.LookupTypeMapEntry(lookupType)
103 if err == nil {
104 return rtype, nil
105 }
106 }
107
108 return nil, err
109 }
110
111 func (eic EmptyInterfaceCodec) decodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
112 if t != tEmpty {
113 return emptyValue, ValueDecoderError{Name: "EmptyInterfaceDecodeValue", Types: []reflect.Type{tEmpty}, Received: reflect.Zero(t)}
114 }
115
116 rtype, err := eic.getEmptyInterfaceDecodeType(dc, vr.Type())
117 if err != nil {
118 switch vr.Type() {
119 case bsontype.Null:
120 return reflect.Zero(t), vr.ReadNull()
121 default:
122 return emptyValue, err
123 }
124 }
125
126 decoder, err := dc.LookupDecoder(rtype)
127 if err != nil {
128 return emptyValue, err
129 }
130
131 elem, err := decodeTypeOrValue(decoder, dc, vr, rtype)
132 if err != nil {
133 return emptyValue, err
134 }
135
136 if (eic.DecodeBinaryAsSlice || dc.binaryAsSlice) && rtype == tBinary {
137 binElem := elem.Interface().(primitive.Binary)
138 if binElem.Subtype == bsontype.BinaryGeneric || binElem.Subtype == bsontype.BinaryBinaryOld {
139 elem = reflect.ValueOf(binElem.Data)
140 }
141 }
142
143 return elem, nil
144 }
145
146 // DecodeValue is the ValueDecoderFunc for interface{}.
147 func (eic EmptyInterfaceCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
148 if !val.CanSet() || val.Type() != tEmpty {
149 return ValueDecoderError{Name: "EmptyInterfaceDecodeValue", Types: []reflect.Type{tEmpty}, Received: val}
150 }
151
152 elem, err := eic.decodeType(dc, vr, val.Type())
153 if err != nil {
154 return err
155 }
156
157 val.Set(elem)
158 return nil
159 }
160