decoder.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  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. package bson
  7. import (
  8. "errors"
  9. "fmt"
  10. "reflect"
  11. "sync"
  12. "go.mongodb.org/mongo-driver/bson/bsoncodec"
  13. "go.mongodb.org/mongo-driver/bson/bsonrw"
  14. )
  15. // ErrDecodeToNil is the error returned when trying to decode to a nil value
  16. var ErrDecodeToNil = errors.New("cannot Decode to nil value")
  17. // This pool is used to keep the allocations of Decoders down. This is only used for the Marshal*
  18. // methods and is not consumable from outside of this package. The Decoders retrieved from this pool
  19. // must have both Reset and SetRegistry called on them.
  20. var decPool = sync.Pool{
  21. New: func() interface{} {
  22. return new(Decoder)
  23. },
  24. }
  25. // A Decoder reads and decodes BSON documents from a stream. It reads from a bsonrw.ValueReader as
  26. // the source of BSON data.
  27. type Decoder struct {
  28. dc bsoncodec.DecodeContext
  29. vr bsonrw.ValueReader
  30. // We persist defaultDocumentM and defaultDocumentD on the Decoder to prevent overwriting from
  31. // (*Decoder).SetContext.
  32. defaultDocumentM bool
  33. defaultDocumentD bool
  34. binaryAsSlice bool
  35. useJSONStructTags bool
  36. useLocalTimeZone bool
  37. zeroMaps bool
  38. zeroStructs bool
  39. }
  40. // NewDecoder returns a new decoder that uses the DefaultRegistry to read from vr.
  41. func NewDecoder(vr bsonrw.ValueReader) (*Decoder, error) {
  42. if vr == nil {
  43. return nil, errors.New("cannot create a new Decoder with a nil ValueReader")
  44. }
  45. return &Decoder{
  46. dc: bsoncodec.DecodeContext{Registry: DefaultRegistry},
  47. vr: vr,
  48. }, nil
  49. }
  50. // NewDecoderWithContext returns a new decoder that uses DecodeContext dc to read from vr.
  51. //
  52. // Deprecated: Use [NewDecoder] and use the Decoder configuration methods set the desired unmarshal
  53. // behavior instead.
  54. func NewDecoderWithContext(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader) (*Decoder, error) {
  55. if dc.Registry == nil {
  56. dc.Registry = DefaultRegistry
  57. }
  58. if vr == nil {
  59. return nil, errors.New("cannot create a new Decoder with a nil ValueReader")
  60. }
  61. return &Decoder{
  62. dc: dc,
  63. vr: vr,
  64. }, nil
  65. }
  66. // Decode reads the next BSON document from the stream and decodes it into the
  67. // value pointed to by val.
  68. //
  69. // See [Unmarshal] for details about BSON unmarshaling behavior.
  70. func (d *Decoder) Decode(val interface{}) error {
  71. if unmarshaler, ok := val.(Unmarshaler); ok {
  72. // TODO(skriptble): Reuse a []byte here and use the AppendDocumentBytes method.
  73. buf, err := bsonrw.Copier{}.CopyDocumentToBytes(d.vr)
  74. if err != nil {
  75. return err
  76. }
  77. return unmarshaler.UnmarshalBSON(buf)
  78. }
  79. rval := reflect.ValueOf(val)
  80. switch rval.Kind() {
  81. case reflect.Ptr:
  82. if rval.IsNil() {
  83. return ErrDecodeToNil
  84. }
  85. rval = rval.Elem()
  86. case reflect.Map:
  87. if rval.IsNil() {
  88. return ErrDecodeToNil
  89. }
  90. default:
  91. return fmt.Errorf("argument to Decode must be a pointer or a map, but got %v", rval)
  92. }
  93. decoder, err := d.dc.LookupDecoder(rval.Type())
  94. if err != nil {
  95. return err
  96. }
  97. if d.defaultDocumentM {
  98. d.dc.DefaultDocumentM()
  99. }
  100. if d.defaultDocumentD {
  101. d.dc.DefaultDocumentD()
  102. }
  103. if d.binaryAsSlice {
  104. d.dc.BinaryAsSlice()
  105. }
  106. if d.useJSONStructTags {
  107. d.dc.UseJSONStructTags()
  108. }
  109. if d.useLocalTimeZone {
  110. d.dc.UseLocalTimeZone()
  111. }
  112. if d.zeroMaps {
  113. d.dc.ZeroMaps()
  114. }
  115. if d.zeroStructs {
  116. d.dc.ZeroStructs()
  117. }
  118. return decoder.DecodeValue(d.dc, d.vr, rval)
  119. }
  120. // Reset will reset the state of the decoder, using the same *DecodeContext used in
  121. // the original construction but using vr for reading.
  122. func (d *Decoder) Reset(vr bsonrw.ValueReader) error {
  123. // TODO:(GODRIVER-2719): Remove error return value.
  124. d.vr = vr
  125. return nil
  126. }
  127. // SetRegistry replaces the current registry of the decoder with r.
  128. func (d *Decoder) SetRegistry(r *bsoncodec.Registry) error {
  129. // TODO:(GODRIVER-2719): Remove error return value.
  130. d.dc.Registry = r
  131. return nil
  132. }
  133. // SetContext replaces the current registry of the decoder with dc.
  134. //
  135. // Deprecated: Use the Decoder configuration methods to set the desired unmarshal behavior instead.
  136. func (d *Decoder) SetContext(dc bsoncodec.DecodeContext) error {
  137. // TODO:(GODRIVER-2719): Remove error return value.
  138. d.dc = dc
  139. return nil
  140. }
  141. // DefaultDocumentM causes the Decoder to always unmarshal documents into the primitive.M type. This
  142. // behavior is restricted to data typed as "interface{}" or "map[string]interface{}".
  143. func (d *Decoder) DefaultDocumentM() {
  144. d.defaultDocumentM = true
  145. }
  146. // DefaultDocumentD causes the Decoder to always unmarshal documents into the primitive.D type. This
  147. // behavior is restricted to data typed as "interface{}" or "map[string]interface{}".
  148. func (d *Decoder) DefaultDocumentD() {
  149. d.defaultDocumentD = true
  150. }
  151. // AllowTruncatingDoubles causes the Decoder to truncate the fractional part of BSON "double" values
  152. // when attempting to unmarshal them into a Go integer (int, int8, int16, int32, or int64) struct
  153. // field. The truncation logic does not apply to BSON "decimal128" values.
  154. func (d *Decoder) AllowTruncatingDoubles() {
  155. d.dc.Truncate = true
  156. }
  157. // BinaryAsSlice causes the Decoder to unmarshal BSON binary field values that are the "Generic" or
  158. // "Old" BSON binary subtype as a Go byte slice instead of a primitive.Binary.
  159. func (d *Decoder) BinaryAsSlice() {
  160. d.binaryAsSlice = true
  161. }
  162. // UseJSONStructTags causes the Decoder to fall back to using the "json" struct tag if a "bson"
  163. // struct tag is not specified.
  164. func (d *Decoder) UseJSONStructTags() {
  165. d.useJSONStructTags = true
  166. }
  167. // UseLocalTimeZone causes the Decoder to unmarshal time.Time values in the local timezone instead
  168. // of the UTC timezone.
  169. func (d *Decoder) UseLocalTimeZone() {
  170. d.useLocalTimeZone = true
  171. }
  172. // ZeroMaps causes the Decoder to delete any existing values from Go maps in the destination value
  173. // passed to Decode before unmarshaling BSON documents into them.
  174. func (d *Decoder) ZeroMaps() {
  175. d.zeroMaps = true
  176. }
  177. // ZeroStructs causes the Decoder to delete any existing values from Go structs in the destination
  178. // value passed to Decode before unmarshaling BSON documents into them.
  179. func (d *Decoder) ZeroStructs() {
  180. d.zeroStructs = true
  181. }