| 
									
										
										
										
											2024-03-06 09:05:45 -08:00
										 |  |  | // Copyright (C) MongoDB, Inc. 2017-present. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Licensed under the Apache License, Version 2.0 (the "License"); you may | 
					
						
							|  |  |  | // not use this file except in compliance with the License. You may obtain | 
					
						
							|  |  |  | // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package bson | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 	"reflect" | 
					
						
							|  |  |  | 	"sync" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"go.mongodb.org/mongo-driver/bson/bsoncodec" | 
					
						
							|  |  |  | 	"go.mongodb.org/mongo-driver/bson/bsonrw" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This pool is used to keep the allocations of Encoders down. This is only used for the Marshal* | 
					
						
							|  |  |  | // methods and is not consumable from outside of this package. The Encoders retrieved from this pool | 
					
						
							|  |  |  | // must have both Reset and SetRegistry called on them. | 
					
						
							|  |  |  | var encPool = sync.Pool{ | 
					
						
							|  |  |  | 	New: func() interface{} { | 
					
						
							|  |  |  | 		return new(Encoder) | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // An Encoder writes a serialization format to an output stream. It writes to a bsonrw.ValueWriter | 
					
						
							|  |  |  | // as the destination of BSON data. | 
					
						
							|  |  |  | type Encoder struct { | 
					
						
							|  |  |  | 	ec bsoncodec.EncodeContext | 
					
						
							|  |  |  | 	vw bsonrw.ValueWriter | 
					
						
							| 
									
										
										
										
											2024-03-25 11:00:36 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	errorOnInlineDuplicates bool | 
					
						
							|  |  |  | 	intMinSize              bool | 
					
						
							|  |  |  | 	stringifyMapKeysWithFmt bool | 
					
						
							|  |  |  | 	nilMapAsEmpty           bool | 
					
						
							|  |  |  | 	nilSliceAsEmpty         bool | 
					
						
							|  |  |  | 	nilByteSliceAsEmpty     bool | 
					
						
							|  |  |  | 	omitZeroStruct          bool | 
					
						
							|  |  |  | 	useJSONStructTags       bool | 
					
						
							| 
									
										
										
										
											2024-03-06 09:05:45 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewEncoder returns a new encoder that uses the DefaultRegistry to write to vw. | 
					
						
							|  |  |  | func NewEncoder(vw bsonrw.ValueWriter) (*Encoder, error) { | 
					
						
							| 
									
										
										
										
											2024-03-25 11:00:36 +00:00
										 |  |  | 	// TODO:(GODRIVER-2719): Remove error return value. | 
					
						
							| 
									
										
										
										
											2024-03-06 09:05:45 -08:00
										 |  |  | 	if vw == nil { | 
					
						
							|  |  |  | 		return nil, errors.New("cannot create a new Encoder with a nil ValueWriter") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return &Encoder{ | 
					
						
							|  |  |  | 		ec: bsoncodec.EncodeContext{Registry: DefaultRegistry}, | 
					
						
							|  |  |  | 		vw: vw, | 
					
						
							|  |  |  | 	}, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewEncoderWithContext returns a new encoder that uses EncodeContext ec to write to vw. | 
					
						
							| 
									
										
										
										
											2024-03-25 11:00:36 +00:00
										 |  |  | // | 
					
						
							|  |  |  | // Deprecated: Use [NewEncoder] and use the Encoder configuration methods to set the desired marshal | 
					
						
							|  |  |  | // behavior instead. | 
					
						
							| 
									
										
										
										
											2024-03-06 09:05:45 -08:00
										 |  |  | func NewEncoderWithContext(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter) (*Encoder, error) { | 
					
						
							|  |  |  | 	if ec.Registry == nil { | 
					
						
							|  |  |  | 		ec = bsoncodec.EncodeContext{Registry: DefaultRegistry} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if vw == nil { | 
					
						
							|  |  |  | 		return nil, errors.New("cannot create a new Encoder with a nil ValueWriter") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return &Encoder{ | 
					
						
							|  |  |  | 		ec: ec, | 
					
						
							|  |  |  | 		vw: vw, | 
					
						
							|  |  |  | 	}, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Encode writes the BSON encoding of val to the stream. | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2024-03-25 11:00:36 +00:00
										 |  |  | // See [Marshal] for details about BSON marshaling behavior. | 
					
						
							| 
									
										
										
										
											2024-03-06 09:05:45 -08:00
										 |  |  | func (e *Encoder) Encode(val interface{}) error { | 
					
						
							|  |  |  | 	if marshaler, ok := val.(Marshaler); ok { | 
					
						
							|  |  |  | 		// TODO(skriptble): Should we have a MarshalAppender interface so that we can have []byte reuse? | 
					
						
							|  |  |  | 		buf, err := marshaler.MarshalBSON() | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return bsonrw.Copier{}.CopyDocumentFromBytes(e.vw, buf) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	encoder, err := e.ec.LookupEncoder(reflect.TypeOf(val)) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-03-25 11:00:36 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Copy the configurations applied to the Encoder over to the EncodeContext, which actually | 
					
						
							|  |  |  | 	// communicates those configurations to the default ValueEncoders. | 
					
						
							|  |  |  | 	if e.errorOnInlineDuplicates { | 
					
						
							|  |  |  | 		e.ec.ErrorOnInlineDuplicates() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if e.intMinSize { | 
					
						
							|  |  |  | 		e.ec.MinSize = true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if e.stringifyMapKeysWithFmt { | 
					
						
							|  |  |  | 		e.ec.StringifyMapKeysWithFmt() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if e.nilMapAsEmpty { | 
					
						
							|  |  |  | 		e.ec.NilMapAsEmpty() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if e.nilSliceAsEmpty { | 
					
						
							|  |  |  | 		e.ec.NilSliceAsEmpty() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if e.nilByteSliceAsEmpty { | 
					
						
							|  |  |  | 		e.ec.NilByteSliceAsEmpty() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if e.omitZeroStruct { | 
					
						
							|  |  |  | 		e.ec.OmitZeroStruct() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if e.useJSONStructTags { | 
					
						
							|  |  |  | 		e.ec.UseJSONStructTags() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-06 09:05:45 -08:00
										 |  |  | 	return encoder.EncodeValue(e.ec, e.vw, reflect.ValueOf(val)) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-25 11:00:36 +00:00
										 |  |  | // Reset will reset the state of the Encoder, using the same *EncodeContext used in | 
					
						
							| 
									
										
										
										
											2024-03-06 09:05:45 -08:00
										 |  |  | // the original construction but using vw. | 
					
						
							|  |  |  | func (e *Encoder) Reset(vw bsonrw.ValueWriter) error { | 
					
						
							| 
									
										
										
										
											2024-03-25 11:00:36 +00:00
										 |  |  | 	// TODO:(GODRIVER-2719): Remove error return value. | 
					
						
							| 
									
										
										
										
											2024-03-06 09:05:45 -08:00
										 |  |  | 	e.vw = vw | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-25 11:00:36 +00:00
										 |  |  | // SetRegistry replaces the current registry of the Encoder with r. | 
					
						
							| 
									
										
										
										
											2024-03-06 09:05:45 -08:00
										 |  |  | func (e *Encoder) SetRegistry(r *bsoncodec.Registry) error { | 
					
						
							| 
									
										
										
										
											2024-03-25 11:00:36 +00:00
										 |  |  | 	// TODO:(GODRIVER-2719): Remove error return value. | 
					
						
							| 
									
										
										
										
											2024-03-06 09:05:45 -08:00
										 |  |  | 	e.ec.Registry = r | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-25 11:00:36 +00:00
										 |  |  | // SetContext replaces the current EncodeContext of the encoder with ec. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Deprecated: Use the Encoder configuration methods set the desired marshal behavior instead. | 
					
						
							| 
									
										
										
										
											2024-03-06 09:05:45 -08:00
										 |  |  | func (e *Encoder) SetContext(ec bsoncodec.EncodeContext) error { | 
					
						
							| 
									
										
										
										
											2024-03-25 11:00:36 +00:00
										 |  |  | 	// TODO:(GODRIVER-2719): Remove error return value. | 
					
						
							| 
									
										
										
										
											2024-03-06 09:05:45 -08:00
										 |  |  | 	e.ec = ec | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2024-03-25 11:00:36 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | // ErrorOnInlineDuplicates causes the Encoder to return an error if there is a duplicate field in | 
					
						
							|  |  |  | // the marshaled BSON when the "inline" struct tag option is set. | 
					
						
							|  |  |  | func (e *Encoder) ErrorOnInlineDuplicates() { | 
					
						
							|  |  |  | 	e.errorOnInlineDuplicates = true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // IntMinSize causes the Encoder to marshal Go integer values (int, int8, int16, int32, int64, uint, | 
					
						
							|  |  |  | // uint8, uint16, uint32, or uint64) as the minimum BSON int size (either 32 or 64 bits) that can | 
					
						
							|  |  |  | // represent the integer value. | 
					
						
							|  |  |  | func (e *Encoder) IntMinSize() { | 
					
						
							|  |  |  | 	e.intMinSize = true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // StringifyMapKeysWithFmt causes the Encoder to convert Go map keys to BSON document field name | 
					
						
							|  |  |  | // strings using fmt.Sprint instead of the default string conversion logic. | 
					
						
							|  |  |  | func (e *Encoder) StringifyMapKeysWithFmt() { | 
					
						
							|  |  |  | 	e.stringifyMapKeysWithFmt = true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NilMapAsEmpty causes the Encoder to marshal nil Go maps as empty BSON documents instead of BSON | 
					
						
							|  |  |  | // null. | 
					
						
							|  |  |  | func (e *Encoder) NilMapAsEmpty() { | 
					
						
							|  |  |  | 	e.nilMapAsEmpty = true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NilSliceAsEmpty causes the Encoder to marshal nil Go slices as empty BSON arrays instead of BSON | 
					
						
							|  |  |  | // null. | 
					
						
							|  |  |  | func (e *Encoder) NilSliceAsEmpty() { | 
					
						
							|  |  |  | 	e.nilSliceAsEmpty = true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NilByteSliceAsEmpty causes the Encoder to marshal nil Go byte slices as empty BSON binary values | 
					
						
							|  |  |  | // instead of BSON null. | 
					
						
							|  |  |  | func (e *Encoder) NilByteSliceAsEmpty() { | 
					
						
							|  |  |  | 	e.nilByteSliceAsEmpty = true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // TODO(GODRIVER-2820): Update the description to remove the note about only examining exported | 
					
						
							|  |  |  | // TODO struct fields once the logic is updated to also inspect private struct fields. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // OmitZeroStruct causes the Encoder to consider the zero value for a struct (e.g. MyStruct{}) | 
					
						
							|  |  |  | // as empty and omit it from the marshaled BSON when the "omitempty" struct tag option is set. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Note that the Encoder only examines exported struct fields when determining if a struct is the | 
					
						
							|  |  |  | // zero value. It considers pointers to a zero struct value (e.g. &MyStruct{}) not empty. | 
					
						
							|  |  |  | func (e *Encoder) OmitZeroStruct() { | 
					
						
							|  |  |  | 	e.omitZeroStruct = true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // UseJSONStructTags causes the Encoder to fall back to using the "json" struct tag if a "bson" | 
					
						
							|  |  |  | // struct tag is not specified. | 
					
						
							|  |  |  | func (e *Encoder) UseJSONStructTags() { | 
					
						
							|  |  |  | 	e.useJSONStructTags = true | 
					
						
							|  |  |  | } |