...

Source file src/go.mongodb.org/mongo-driver/bson/bsoncodec/empty_interface_codec.go

Documentation: go.mongodb.org/mongo-driver/bson/bsoncodec

     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: EmptyInterfaceCodec will not be directly configurable in Go
    21  // Driver 2.0. To configure the empty interface encode and decode behavior, use
    22  // the configuration methods on a [go.mongodb.org/mongo-driver/bson.Encoder] or
    23  // [go.mongodb.org/mongo-driver/bson.Decoder]. To configure the empty interface
    24  // encode and decode behavior for a mongo.Client, use
    25  // [go.mongodb.org/mongo-driver/mongo/options.ClientOptions.SetBSONOptions].
    26  //
    27  // For example, to configure a mongo.Client to unmarshal BSON binary field
    28  // values as a Go byte slice, use:
    29  //
    30  //	opt := options.Client().SetBSONOptions(&options.BSONOptions{
    31  //	    BinaryAsSlice: true,
    32  //	})
    33  //
    34  // See the deprecation notice for each field in EmptyInterfaceCodec for the
    35  // corresponding settings.
    36  type EmptyInterfaceCodec struct {
    37  	// DecodeBinaryAsSlice causes DecodeValue to unmarshal BSON binary field values that are the
    38  	// "Generic" or "Old" BSON binary subtype as a Go byte slice instead of a primitive.Binary.
    39  	//
    40  	// Deprecated: Use bson.Decoder.BinaryAsSlice or options.BSONOptions.BinaryAsSlice instead.
    41  	DecodeBinaryAsSlice bool
    42  }
    43  
    44  var (
    45  	defaultEmptyInterfaceCodec = NewEmptyInterfaceCodec()
    46  
    47  	// Assert that defaultEmptyInterfaceCodec satisfies the typeDecoder interface, which allows it
    48  	// to be used by collection type decoders (e.g. map, slice, etc) to set individual values in a
    49  	// collection.
    50  	_ typeDecoder = defaultEmptyInterfaceCodec
    51  )
    52  
    53  // NewEmptyInterfaceCodec returns a EmptyInterfaceCodec with options opts.
    54  //
    55  // Deprecated: NewEmptyInterfaceCodec will not be available in Go Driver 2.0. See
    56  // [EmptyInterfaceCodec] for more details.
    57  func NewEmptyInterfaceCodec(opts ...*bsonoptions.EmptyInterfaceCodecOptions) *EmptyInterfaceCodec {
    58  	interfaceOpt := bsonoptions.MergeEmptyInterfaceCodecOptions(opts...)
    59  
    60  	codec := EmptyInterfaceCodec{}
    61  	if interfaceOpt.DecodeBinaryAsSlice != nil {
    62  		codec.DecodeBinaryAsSlice = *interfaceOpt.DecodeBinaryAsSlice
    63  	}
    64  	return &codec
    65  }
    66  
    67  // EncodeValue is the ValueEncoderFunc for interface{}.
    68  func (eic EmptyInterfaceCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
    69  	if !val.IsValid() || val.Type() != tEmpty {
    70  		return ValueEncoderError{Name: "EmptyInterfaceEncodeValue", Types: []reflect.Type{tEmpty}, Received: val}
    71  	}
    72  
    73  	if val.IsNil() {
    74  		return vw.WriteNull()
    75  	}
    76  	encoder, err := ec.LookupEncoder(val.Elem().Type())
    77  	if err != nil {
    78  		return err
    79  	}
    80  
    81  	return encoder.EncodeValue(ec, vw, val.Elem())
    82  }
    83  
    84  func (eic EmptyInterfaceCodec) getEmptyInterfaceDecodeType(dc DecodeContext, valueType bsontype.Type) (reflect.Type, error) {
    85  	isDocument := valueType == bsontype.Type(0) || valueType == bsontype.EmbeddedDocument
    86  	if isDocument {
    87  		if dc.defaultDocumentType != nil {
    88  			// If the bsontype is an embedded document and the DocumentType is set on the DecodeContext, then return
    89  			// that type.
    90  			return dc.defaultDocumentType, nil
    91  		}
    92  		if dc.Ancestor != nil {
    93  			// Using ancestor information rather than looking up the type map entry forces consistent decoding.
    94  			// If we're decoding into a bson.D, subdocuments should also be decoded as bson.D, even if a type map entry
    95  			// has been registered.
    96  			return dc.Ancestor, nil
    97  		}
    98  	}
    99  
   100  	rtype, err := dc.LookupTypeMapEntry(valueType)
   101  	if err == nil {
   102  		return rtype, nil
   103  	}
   104  
   105  	if isDocument {
   106  		// For documents, fallback to looking up a type map entry for bsontype.Type(0) or bsontype.EmbeddedDocument,
   107  		// depending on the original valueType.
   108  		var lookupType bsontype.Type
   109  		switch valueType {
   110  		case bsontype.Type(0):
   111  			lookupType = bsontype.EmbeddedDocument
   112  		case bsontype.EmbeddedDocument:
   113  			lookupType = bsontype.Type(0)
   114  		}
   115  
   116  		rtype, err = dc.LookupTypeMapEntry(lookupType)
   117  		if err == nil {
   118  			return rtype, nil
   119  		}
   120  	}
   121  
   122  	return nil, err
   123  }
   124  
   125  func (eic EmptyInterfaceCodec) decodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
   126  	if t != tEmpty {
   127  		return emptyValue, ValueDecoderError{Name: "EmptyInterfaceDecodeValue", Types: []reflect.Type{tEmpty}, Received: reflect.Zero(t)}
   128  	}
   129  
   130  	rtype, err := eic.getEmptyInterfaceDecodeType(dc, vr.Type())
   131  	if err != nil {
   132  		switch vr.Type() {
   133  		case bsontype.Null:
   134  			return reflect.Zero(t), vr.ReadNull()
   135  		default:
   136  			return emptyValue, err
   137  		}
   138  	}
   139  
   140  	decoder, err := dc.LookupDecoder(rtype)
   141  	if err != nil {
   142  		return emptyValue, err
   143  	}
   144  
   145  	elem, err := decodeTypeOrValue(decoder, dc, vr, rtype)
   146  	if err != nil {
   147  		return emptyValue, err
   148  	}
   149  
   150  	if (eic.DecodeBinaryAsSlice || dc.binaryAsSlice) && rtype == tBinary {
   151  		binElem := elem.Interface().(primitive.Binary)
   152  		if binElem.Subtype == bsontype.BinaryGeneric || binElem.Subtype == bsontype.BinaryBinaryOld {
   153  			elem = reflect.ValueOf(binElem.Data)
   154  		}
   155  	}
   156  
   157  	return elem, nil
   158  }
   159  
   160  // DecodeValue is the ValueDecoderFunc for interface{}.
   161  func (eic EmptyInterfaceCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
   162  	if !val.CanSet() || val.Type() != tEmpty {
   163  		return ValueDecoderError{Name: "EmptyInterfaceDecodeValue", Types: []reflect.Type{tEmpty}, Received: val}
   164  	}
   165  
   166  	elem, err := eic.decodeType(dc, vr, val.Type())
   167  	if err != nil {
   168  		return err
   169  	}
   170  
   171  	val.Set(elem)
   172  	return nil
   173  }
   174  

View as plain text