string_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  	"fmt"
  11  	"reflect"
  12  
  13  	"go.mongodb.org/mongo-driver/bson/bsonoptions"
  14  	"go.mongodb.org/mongo-driver/bson/bsonrw"
  15  	"go.mongodb.org/mongo-driver/bson/bsontype"
  16  )
  17  
  18  // StringCodec is the Codec used for string values.
  19  //
  20  // Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the
  21  // StringCodec registered.
  22  type StringCodec struct {
  23  	// DecodeObjectIDAsHex specifies if object IDs should be decoded as their hex representation.
  24  	// If false, a string made from the raw object ID bytes will be used. Defaults to true.
  25  	//
  26  	// Deprecated: Decoding object IDs as raw bytes will not be supported in Go Driver 2.0.
  27  	DecodeObjectIDAsHex bool
  28  }
  29  
  30  var (
  31  	defaultStringCodec = NewStringCodec()
  32  
  33  	// Assert that defaultStringCodec satisfies the typeDecoder interface, which allows it to be
  34  	// used by collection type decoders (e.g. map, slice, etc) to set individual values in a
  35  	// collection.
  36  	_ typeDecoder = defaultStringCodec
  37  )
  38  
  39  // NewStringCodec returns a StringCodec with options opts.
  40  //
  41  // Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the
  42  // StringCodec registered.
  43  func NewStringCodec(opts ...*bsonoptions.StringCodecOptions) *StringCodec {
  44  	stringOpt := bsonoptions.MergeStringCodecOptions(opts...)
  45  	return &StringCodec{*stringOpt.DecodeObjectIDAsHex}
  46  }
  47  
  48  // EncodeValue is the ValueEncoder for string types.
  49  func (sc *StringCodec) EncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
  50  	if val.Kind() != reflect.String {
  51  		return ValueEncoderError{
  52  			Name:     "StringEncodeValue",
  53  			Kinds:    []reflect.Kind{reflect.String},
  54  			Received: val,
  55  		}
  56  	}
  57  
  58  	return vw.WriteString(val.String())
  59  }
  60  
  61  func (sc *StringCodec) decodeType(_ DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
  62  	if t.Kind() != reflect.String {
  63  		return emptyValue, ValueDecoderError{
  64  			Name:     "StringDecodeValue",
  65  			Kinds:    []reflect.Kind{reflect.String},
  66  			Received: reflect.Zero(t),
  67  		}
  68  	}
  69  
  70  	var str string
  71  	var err error
  72  	switch vr.Type() {
  73  	case bsontype.String:
  74  		str, err = vr.ReadString()
  75  		if err != nil {
  76  			return emptyValue, err
  77  		}
  78  	case bsontype.ObjectID:
  79  		oid, err := vr.ReadObjectID()
  80  		if err != nil {
  81  			return emptyValue, err
  82  		}
  83  		if sc.DecodeObjectIDAsHex {
  84  			str = oid.Hex()
  85  		} else {
  86  			// TODO(GODRIVER-2796): Return an error here instead of decoding to a garbled string.
  87  			byteArray := [12]byte(oid)
  88  			str = string(byteArray[:])
  89  		}
  90  	case bsontype.Symbol:
  91  		str, err = vr.ReadSymbol()
  92  		if err != nil {
  93  			return emptyValue, err
  94  		}
  95  	case bsontype.Binary:
  96  		data, subtype, err := vr.ReadBinary()
  97  		if err != nil {
  98  			return emptyValue, err
  99  		}
 100  		if subtype != bsontype.BinaryGeneric && subtype != bsontype.BinaryBinaryOld {
 101  			return emptyValue, decodeBinaryError{subtype: subtype, typeName: "string"}
 102  		}
 103  		str = string(data)
 104  	case bsontype.Null:
 105  		if err = vr.ReadNull(); err != nil {
 106  			return emptyValue, err
 107  		}
 108  	case bsontype.Undefined:
 109  		if err = vr.ReadUndefined(); err != nil {
 110  			return emptyValue, err
 111  		}
 112  	default:
 113  		return emptyValue, fmt.Errorf("cannot decode %v into a string type", vr.Type())
 114  	}
 115  
 116  	return reflect.ValueOf(str), nil
 117  }
 118  
 119  // DecodeValue is the ValueDecoder for string types.
 120  func (sc *StringCodec) DecodeValue(dctx DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
 121  	if !val.CanSet() || val.Kind() != reflect.String {
 122  		return ValueDecoderError{Name: "StringDecodeValue", Kinds: []reflect.Kind{reflect.String}, Received: val}
 123  	}
 124  
 125  	elem, err := sc.decodeType(dctx, vr, val.Type())
 126  	if err != nil {
 127  		return err
 128  	}
 129  
 130  	val.SetString(elem.String())
 131  	return nil
 132  }
 133