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