You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

99 lines
2.8 KiB

  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. "reflect"
  10. "sync"
  11. "go.mongodb.org/mongo-driver/bson/bsoncodec"
  12. "go.mongodb.org/mongo-driver/bson/bsonrw"
  13. )
  14. // This pool is used to keep the allocations of Encoders down. This is only used for the Marshal*
  15. // methods and is not consumable from outside of this package. The Encoders retrieved from this pool
  16. // must have both Reset and SetRegistry called on them.
  17. var encPool = sync.Pool{
  18. New: func() interface{} {
  19. return new(Encoder)
  20. },
  21. }
  22. // An Encoder writes a serialization format to an output stream. It writes to a bsonrw.ValueWriter
  23. // as the destination of BSON data.
  24. type Encoder struct {
  25. ec bsoncodec.EncodeContext
  26. vw bsonrw.ValueWriter
  27. }
  28. // NewEncoder returns a new encoder that uses the DefaultRegistry to write to vw.
  29. func NewEncoder(vw bsonrw.ValueWriter) (*Encoder, error) {
  30. if vw == nil {
  31. return nil, errors.New("cannot create a new Encoder with a nil ValueWriter")
  32. }
  33. return &Encoder{
  34. ec: bsoncodec.EncodeContext{Registry: DefaultRegistry},
  35. vw: vw,
  36. }, nil
  37. }
  38. // NewEncoderWithContext returns a new encoder that uses EncodeContext ec to write to vw.
  39. func NewEncoderWithContext(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter) (*Encoder, error) {
  40. if ec.Registry == nil {
  41. ec = bsoncodec.EncodeContext{Registry: DefaultRegistry}
  42. }
  43. if vw == nil {
  44. return nil, errors.New("cannot create a new Encoder with a nil ValueWriter")
  45. }
  46. return &Encoder{
  47. ec: ec,
  48. vw: vw,
  49. }, nil
  50. }
  51. // Encode writes the BSON encoding of val to the stream.
  52. //
  53. // The documentation for Marshal contains details about the conversion of Go
  54. // values to BSON.
  55. func (e *Encoder) Encode(val interface{}) error {
  56. if marshaler, ok := val.(Marshaler); ok {
  57. // TODO(skriptble): Should we have a MarshalAppender interface so that we can have []byte reuse?
  58. buf, err := marshaler.MarshalBSON()
  59. if err != nil {
  60. return err
  61. }
  62. return bsonrw.Copier{}.CopyDocumentFromBytes(e.vw, buf)
  63. }
  64. encoder, err := e.ec.LookupEncoder(reflect.TypeOf(val))
  65. if err != nil {
  66. return err
  67. }
  68. return encoder.EncodeValue(e.ec, e.vw, reflect.ValueOf(val))
  69. }
  70. // Reset will reset the state of the encoder, using the same *EncodeContext used in
  71. // the original construction but using vw.
  72. func (e *Encoder) Reset(vw bsonrw.ValueWriter) error {
  73. e.vw = vw
  74. return nil
  75. }
  76. // SetRegistry replaces the current registry of the encoder with r.
  77. func (e *Encoder) SetRegistry(r *bsoncodec.Registry) error {
  78. e.ec.Registry = r
  79. return nil
  80. }
  81. // SetContext replaces the current EncodeContext of the encoder with er.
  82. func (e *Encoder) SetContext(ec bsoncodec.EncodeContext) error {
  83. e.ec = ec
  84. return nil
  85. }