github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/vendor_skip/go.mongodb.org/mongo-driver/bson/encoder.go (about)

     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 bson
     8  
     9  import (
    10  	"errors"
    11  	"reflect"
    12  	"sync"
    13  
    14  	"go.mongodb.org/mongo-driver/bson/bsoncodec"
    15  	"go.mongodb.org/mongo-driver/bson/bsonrw"
    16  )
    17  
    18  // This pool is used to keep the allocations of Encoders down. This is only used for the Marshal*
    19  // methods and is not consumable from outside of this package. The Encoders retrieved from this pool
    20  // must have both Reset and SetRegistry called on them.
    21  var encPool = sync.Pool{
    22  	New: func() interface{} {
    23  		return new(Encoder)
    24  	},
    25  }
    26  
    27  // An Encoder writes a serialization format to an output stream. It writes to a bsonrw.ValueWriter
    28  // as the destination of BSON data.
    29  type Encoder struct {
    30  	ec bsoncodec.EncodeContext
    31  	vw bsonrw.ValueWriter
    32  
    33  	errorOnInlineDuplicates bool
    34  	intMinSize              bool
    35  	stringifyMapKeysWithFmt bool
    36  	nilMapAsEmpty           bool
    37  	nilSliceAsEmpty         bool
    38  	nilByteSliceAsEmpty     bool
    39  	omitZeroStruct          bool
    40  	useJSONStructTags       bool
    41  }
    42  
    43  // NewEncoder returns a new encoder that uses the DefaultRegistry to write to vw.
    44  func NewEncoder(vw bsonrw.ValueWriter) (*Encoder, error) {
    45  	// TODO:(GODRIVER-2719): Remove error return value.
    46  	if vw == nil {
    47  		return nil, errors.New("cannot create a new Encoder with a nil ValueWriter")
    48  	}
    49  
    50  	return &Encoder{
    51  		ec: bsoncodec.EncodeContext{Registry: DefaultRegistry},
    52  		vw: vw,
    53  	}, nil
    54  }
    55  
    56  // NewEncoderWithContext returns a new encoder that uses EncodeContext ec to write to vw.
    57  //
    58  // Deprecated: Use [NewEncoder] and use the Encoder configuration methods to set the desired marshal
    59  // behavior instead.
    60  func NewEncoderWithContext(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter) (*Encoder, error) {
    61  	if ec.Registry == nil {
    62  		ec = bsoncodec.EncodeContext{Registry: DefaultRegistry}
    63  	}
    64  	if vw == nil {
    65  		return nil, errors.New("cannot create a new Encoder with a nil ValueWriter")
    66  	}
    67  
    68  	return &Encoder{
    69  		ec: ec,
    70  		vw: vw,
    71  	}, nil
    72  }
    73  
    74  // Encode writes the BSON encoding of val to the stream.
    75  //
    76  // See [Marshal] for details about BSON marshaling behavior.
    77  func (e *Encoder) Encode(val interface{}) error {
    78  	if marshaler, ok := val.(Marshaler); ok {
    79  		// TODO(skriptble): Should we have a MarshalAppender interface so that we can have []byte reuse?
    80  		buf, err := marshaler.MarshalBSON()
    81  		if err != nil {
    82  			return err
    83  		}
    84  		return bsonrw.Copier{}.CopyDocumentFromBytes(e.vw, buf)
    85  	}
    86  
    87  	encoder, err := e.ec.LookupEncoder(reflect.TypeOf(val))
    88  	if err != nil {
    89  		return err
    90  	}
    91  
    92  	// Copy the configurations applied to the Encoder over to the EncodeContext, which actually
    93  	// communicates those configurations to the default ValueEncoders.
    94  	if e.errorOnInlineDuplicates {
    95  		e.ec.ErrorOnInlineDuplicates()
    96  	}
    97  	if e.intMinSize {
    98  		e.ec.MinSize = true
    99  	}
   100  	if e.stringifyMapKeysWithFmt {
   101  		e.ec.StringifyMapKeysWithFmt()
   102  	}
   103  	if e.nilMapAsEmpty {
   104  		e.ec.NilMapAsEmpty()
   105  	}
   106  	if e.nilSliceAsEmpty {
   107  		e.ec.NilSliceAsEmpty()
   108  	}
   109  	if e.nilByteSliceAsEmpty {
   110  		e.ec.NilByteSliceAsEmpty()
   111  	}
   112  	if e.omitZeroStruct {
   113  		e.ec.OmitZeroStruct()
   114  	}
   115  	if e.useJSONStructTags {
   116  		e.ec.UseJSONStructTags()
   117  	}
   118  
   119  	return encoder.EncodeValue(e.ec, e.vw, reflect.ValueOf(val))
   120  }
   121  
   122  // Reset will reset the state of the Encoder, using the same *EncodeContext used in
   123  // the original construction but using vw.
   124  func (e *Encoder) Reset(vw bsonrw.ValueWriter) error {
   125  	// TODO:(GODRIVER-2719): Remove error return value.
   126  	e.vw = vw
   127  	return nil
   128  }
   129  
   130  // SetRegistry replaces the current registry of the Encoder with r.
   131  func (e *Encoder) SetRegistry(r *bsoncodec.Registry) error {
   132  	// TODO:(GODRIVER-2719): Remove error return value.
   133  	e.ec.Registry = r
   134  	return nil
   135  }
   136  
   137  // SetContext replaces the current EncodeContext of the encoder with ec.
   138  //
   139  // Deprecated: Use the Encoder configuration methods set the desired marshal behavior instead.
   140  func (e *Encoder) SetContext(ec bsoncodec.EncodeContext) error {
   141  	// TODO:(GODRIVER-2719): Remove error return value.
   142  	e.ec = ec
   143  	return nil
   144  }
   145  
   146  // ErrorOnInlineDuplicates causes the Encoder to return an error if there is a duplicate field in
   147  // the marshaled BSON when the "inline" struct tag option is set.
   148  func (e *Encoder) ErrorOnInlineDuplicates() {
   149  	e.errorOnInlineDuplicates = true
   150  }
   151  
   152  // IntMinSize causes the Encoder to marshal Go integer values (int, int8, int16, int32, int64, uint,
   153  // uint8, uint16, uint32, or uint64) as the minimum BSON int size (either 32 or 64 bits) that can
   154  // represent the integer value.
   155  func (e *Encoder) IntMinSize() {
   156  	e.intMinSize = true
   157  }
   158  
   159  // StringifyMapKeysWithFmt causes the Encoder to convert Go map keys to BSON document field name
   160  // strings using fmt.Sprint instead of the default string conversion logic.
   161  func (e *Encoder) StringifyMapKeysWithFmt() {
   162  	e.stringifyMapKeysWithFmt = true
   163  }
   164  
   165  // NilMapAsEmpty causes the Encoder to marshal nil Go maps as empty BSON documents instead of BSON
   166  // null.
   167  func (e *Encoder) NilMapAsEmpty() {
   168  	e.nilMapAsEmpty = true
   169  }
   170  
   171  // NilSliceAsEmpty causes the Encoder to marshal nil Go slices as empty BSON arrays instead of BSON
   172  // null.
   173  func (e *Encoder) NilSliceAsEmpty() {
   174  	e.nilSliceAsEmpty = true
   175  }
   176  
   177  // NilByteSliceAsEmpty causes the Encoder to marshal nil Go byte slices as empty BSON binary values
   178  // instead of BSON null.
   179  func (e *Encoder) NilByteSliceAsEmpty() {
   180  	e.nilByteSliceAsEmpty = true
   181  }
   182  
   183  // TODO(GODRIVER-2820): Update the description to remove the note about only examining exported
   184  // TODO struct fields once the logic is updated to also inspect private struct fields.
   185  
   186  // OmitZeroStruct causes the Encoder to consider the zero value for a struct (e.g. MyStruct{})
   187  // as empty and omit it from the marshaled BSON when the "omitempty" struct tag option is set.
   188  //
   189  // Note that the Encoder only examines exported struct fields when determining if a struct is the
   190  // zero value. It considers pointers to a zero struct value (e.g. &MyStruct{}) not empty.
   191  func (e *Encoder) OmitZeroStruct() {
   192  	e.omitZeroStruct = true
   193  }
   194  
   195  // UseJSONStructTags causes the Encoder to fall back to using the "json" struct tag if a "bson"
   196  // struct tag is not specified.
   197  func (e *Encoder) UseJSONStructTags() {
   198  	e.useJSONStructTags = true
   199  }