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 7package bsoncodec 8 9import ( 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. 19type EmptyInterfaceCodec struct { 20 DecodeBinaryAsSlice bool 21} 22 23var ( 24 defaultEmptyInterfaceCodec = NewEmptyInterfaceCodec() 25 26 _ ValueCodec = defaultEmptyInterfaceCodec 27 _ typeDecoder = defaultEmptyInterfaceCodec 28) 29 30// NewEmptyInterfaceCodec returns a EmptyInterfaceCodec with options opts. 31func NewEmptyInterfaceCodec(opts ...*bsonoptions.EmptyInterfaceCodecOptions) *EmptyInterfaceCodec { 32 interfaceOpt := bsonoptions.MergeEmptyInterfaceCodecOptions(opts...) 33 34 codec := EmptyInterfaceCodec{} 35 if interfaceOpt.DecodeBinaryAsSlice != nil { 36 codec.DecodeBinaryAsSlice = *interfaceOpt.DecodeBinaryAsSlice 37 } 38 return &codec 39} 40 41// EncodeValue is the ValueEncoderFunc for interface{}. 42func (eic EmptyInterfaceCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { 43 if !val.IsValid() || val.Type() != tEmpty { 44 return ValueEncoderError{Name: "EmptyInterfaceEncodeValue", Types: []reflect.Type{tEmpty}, Received: val} 45 } 46 47 if val.IsNil() { 48 return vw.WriteNull() 49 } 50 encoder, err := ec.LookupEncoder(val.Elem().Type()) 51 if err != nil { 52 return err 53 } 54 55 return encoder.EncodeValue(ec, vw, val.Elem()) 56} 57 58func (eic EmptyInterfaceCodec) getEmptyInterfaceDecodeType(dc DecodeContext, valueType bsontype.Type) (reflect.Type, error) { 59 isDocument := valueType == bsontype.Type(0) || valueType == bsontype.EmbeddedDocument 60 if isDocument && dc.Ancestor != nil { 61 // Using ancestor information rather than looking up the type map entry forces consistent decoding. 62 // If we're decoding into a bson.D, subdocuments should also be decoded as bson.D, even if a type map entry 63 // has been registered. 64 return dc.Ancestor, nil 65 } 66 67 rtype, err := dc.LookupTypeMapEntry(valueType) 68 if err == nil { 69 return rtype, nil 70 } 71 72 if isDocument { 73 // For documents, fallback to looking up a type map entry for bsontype.Type(0) or bsontype.EmbeddedDocument, 74 // depending on the original valueType. 75 var lookupType bsontype.Type 76 switch valueType { 77 case bsontype.Type(0): 78 lookupType = bsontype.EmbeddedDocument 79 case bsontype.EmbeddedDocument: 80 lookupType = bsontype.Type(0) 81 } 82 83 rtype, err = dc.LookupTypeMapEntry(lookupType) 84 if err == nil { 85 return rtype, nil 86 } 87 } 88 89 return nil, err 90} 91 92func (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)} 95 } 96 97 rtype, err := eic.getEmptyInterfaceDecodeType(dc, vr.Type()) 98 if err != nil { 99 switch vr.Type() { 100 case bsontype.Null: 101 return reflect.Zero(t), vr.ReadNull() 102 default: 103 return emptyValue, err 104 } 105 } 106 107 decoder, err := dc.LookupDecoder(rtype) 108 if err != nil { 109 return emptyValue, err 110 } 111 112 elem, err := decodeTypeOrValue(decoder, dc, vr, rtype) 113 if err != nil { 114 return emptyValue, err 115 } 116 117 if eic.DecodeBinaryAsSlice && rtype == tBinary { 118 binElem := elem.Interface().(primitive.Binary) 119 if binElem.Subtype == bsontype.BinaryGeneric || binElem.Subtype == bsontype.BinaryBinaryOld { 120 elem = reflect.ValueOf(binElem.Data) 121 } 122 } 123 124 return elem, nil 125} 126 127// DecodeValue is the ValueDecoderFunc for interface{}. 128func (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 138 val.Set(elem) 139 return nil 140} 141