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