...

Source file src/go.mongodb.org/mongo-driver/bson/marshal.go

Documentation: go.mongodb.org/mongo-driver/bson

     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  	"bytes"
    11  	"encoding/json"
    12  	"sync"
    13  
    14  	"go.mongodb.org/mongo-driver/bson/bsoncodec"
    15  	"go.mongodb.org/mongo-driver/bson/bsonrw"
    16  	"go.mongodb.org/mongo-driver/bson/bsontype"
    17  )
    18  
    19  const defaultDstCap = 256
    20  
    21  var bvwPool = bsonrw.NewBSONValueWriterPool()
    22  var extjPool = bsonrw.NewExtJSONValueWriterPool()
    23  
    24  // Marshaler is the interface implemented by types that can marshal themselves
    25  // into a valid BSON document.
    26  //
    27  // Implementations of Marshaler must return a full BSON document. To create
    28  // custom BSON marshaling behavior for individual values in a BSON document,
    29  // implement the ValueMarshaler interface instead.
    30  type Marshaler interface {
    31  	MarshalBSON() ([]byte, error)
    32  }
    33  
    34  // ValueMarshaler is the interface implemented by types that can marshal
    35  // themselves into a valid BSON value. The format of the returned bytes must
    36  // match the returned type.
    37  //
    38  // Implementations of ValueMarshaler must return an individual BSON value. To
    39  // create custom BSON marshaling behavior for an entire BSON document, implement
    40  // the Marshaler interface instead.
    41  type ValueMarshaler interface {
    42  	MarshalBSONValue() (bsontype.Type, []byte, error)
    43  }
    44  
    45  // Marshal returns the BSON encoding of val as a BSON document. If val is not a type that can be transformed into a
    46  // document, MarshalValue should be used instead.
    47  //
    48  // Marshal will use the default registry created by NewRegistry to recursively
    49  // marshal val into a []byte. Marshal will inspect struct tags and alter the
    50  // marshaling process accordingly.
    51  func Marshal(val interface{}) ([]byte, error) {
    52  	return MarshalWithRegistry(DefaultRegistry, val)
    53  }
    54  
    55  // MarshalAppend will encode val as a BSON document and append the bytes to dst. If dst is not large enough to hold the
    56  // bytes, it will be grown. If val is not a type that can be transformed into a document, MarshalValueAppend should be
    57  // used instead.
    58  //
    59  // Deprecated: Use [NewEncoder] and pass the dst byte slice (wrapped by a bytes.Buffer) into
    60  // [bsonrw.NewBSONValueWriter]:
    61  //
    62  //	buf := bytes.NewBuffer(dst)
    63  //	vw, err := bsonrw.NewBSONValueWriter(buf)
    64  //	if err != nil {
    65  //		panic(err)
    66  //	}
    67  //	enc, err := bson.NewEncoder(vw)
    68  //	if err != nil {
    69  //		panic(err)
    70  //	}
    71  //
    72  // See [Encoder] for more examples.
    73  func MarshalAppend(dst []byte, val interface{}) ([]byte, error) {
    74  	return MarshalAppendWithRegistry(DefaultRegistry, dst, val)
    75  }
    76  
    77  // MarshalWithRegistry returns the BSON encoding of val as a BSON document. If val is not a type that can be transformed
    78  // into a document, MarshalValueWithRegistry should be used instead.
    79  //
    80  // Deprecated: Use [NewEncoder] and specify the Registry by calling [Encoder.SetRegistry] instead:
    81  //
    82  //	buf := new(bytes.Buffer)
    83  //	vw, err := bsonrw.NewBSONValueWriter(buf)
    84  //	if err != nil {
    85  //		panic(err)
    86  //	}
    87  //	enc, err := bson.NewEncoder(vw)
    88  //	if err != nil {
    89  //		panic(err)
    90  //	}
    91  //	enc.SetRegistry(reg)
    92  //
    93  // See [Encoder] for more examples.
    94  func MarshalWithRegistry(r *bsoncodec.Registry, val interface{}) ([]byte, error) {
    95  	dst := make([]byte, 0)
    96  	return MarshalAppendWithRegistry(r, dst, val)
    97  }
    98  
    99  // MarshalWithContext returns the BSON encoding of val as a BSON document using EncodeContext ec. If val is not a type
   100  // that can be transformed into a document, MarshalValueWithContext should be used instead.
   101  //
   102  // Deprecated: Use [NewEncoder] and use the Encoder configuration methods to set the desired marshal
   103  // behavior instead:
   104  //
   105  //	buf := bytes.NewBuffer(dst)
   106  //	vw, err := bsonrw.NewBSONValueWriter(buf)
   107  //	if err != nil {
   108  //		panic(err)
   109  //	}
   110  //	enc, err := bson.NewEncoder(vw)
   111  //	if err != nil {
   112  //		panic(err)
   113  //	}
   114  //	enc.IntMinSize()
   115  //
   116  // See [Encoder] for more examples.
   117  func MarshalWithContext(ec bsoncodec.EncodeContext, val interface{}) ([]byte, error) {
   118  	dst := make([]byte, 0)
   119  	return MarshalAppendWithContext(ec, dst, val)
   120  }
   121  
   122  // MarshalAppendWithRegistry will encode val as a BSON document using Registry r and append the bytes to dst. If dst is
   123  // not large enough to hold the bytes, it will be grown. If val is not a type that can be transformed into a document,
   124  // MarshalValueAppendWithRegistry should be used instead.
   125  //
   126  // Deprecated: Use [NewEncoder], and pass the dst byte slice (wrapped by a bytes.Buffer) into
   127  // [bsonrw.NewBSONValueWriter], and specify the Registry by calling [Encoder.SetRegistry] instead:
   128  //
   129  //	buf := bytes.NewBuffer(dst)
   130  //	vw, err := bsonrw.NewBSONValueWriter(buf)
   131  //	if err != nil {
   132  //		panic(err)
   133  //	}
   134  //	enc, err := bson.NewEncoder(vw)
   135  //	if err != nil {
   136  //		panic(err)
   137  //	}
   138  //	enc.SetRegistry(reg)
   139  //
   140  // See [Encoder] for more examples.
   141  func MarshalAppendWithRegistry(r *bsoncodec.Registry, dst []byte, val interface{}) ([]byte, error) {
   142  	return MarshalAppendWithContext(bsoncodec.EncodeContext{Registry: r}, dst, val)
   143  }
   144  
   145  // Pool of buffers for marshalling BSON.
   146  var bufPool = sync.Pool{
   147  	New: func() interface{} {
   148  		return new(bytes.Buffer)
   149  	},
   150  }
   151  
   152  // MarshalAppendWithContext will encode val as a BSON document using Registry r and EncodeContext ec and append the
   153  // bytes to dst. If dst is not large enough to hold the bytes, it will be grown. If val is not a type that can be
   154  // transformed into a document, MarshalValueAppendWithContext should be used instead.
   155  //
   156  // Deprecated: Use [NewEncoder], pass the dst byte slice (wrapped by a bytes.Buffer) into
   157  // [bsonrw.NewBSONValueWriter], and use the Encoder configuration methods to set the desired marshal
   158  // behavior instead:
   159  //
   160  //	buf := bytes.NewBuffer(dst)
   161  //	vw, err := bsonrw.NewBSONValueWriter(buf)
   162  //	if err != nil {
   163  //		panic(err)
   164  //	}
   165  //	enc, err := bson.NewEncoder(vw)
   166  //	if err != nil {
   167  //		panic(err)
   168  //	}
   169  //	enc.IntMinSize()
   170  //
   171  // See [Encoder] for more examples.
   172  func MarshalAppendWithContext(ec bsoncodec.EncodeContext, dst []byte, val interface{}) ([]byte, error) {
   173  	sw := bufPool.Get().(*bytes.Buffer)
   174  	defer func() {
   175  		// Proper usage of a sync.Pool requires each entry to have approximately
   176  		// the same memory cost. To obtain this property when the stored type
   177  		// contains a variably-sized buffer, we add a hard limit on the maximum
   178  		// buffer to place back in the pool. We limit the size to 16MiB because
   179  		// that's the maximum wire message size supported by any current MongoDB
   180  		// server.
   181  		//
   182  		// Comment based on
   183  		// https://cs.opensource.google/go/go/+/refs/tags/go1.19:src/fmt/print.go;l=147
   184  		//
   185  		// Recycle byte slices that are smaller than 16MiB and at least half
   186  		// occupied.
   187  		if sw.Cap() < 16*1024*1024 && sw.Cap()/2 < sw.Len() {
   188  			bufPool.Put(sw)
   189  		}
   190  	}()
   191  
   192  	sw.Reset()
   193  	vw := bvwPool.Get(sw)
   194  	defer bvwPool.Put(vw)
   195  
   196  	enc := encPool.Get().(*Encoder)
   197  	defer encPool.Put(enc)
   198  
   199  	err := enc.Reset(vw)
   200  	if err != nil {
   201  		return nil, err
   202  	}
   203  	err = enc.SetContext(ec)
   204  	if err != nil {
   205  		return nil, err
   206  	}
   207  
   208  	err = enc.Encode(val)
   209  	if err != nil {
   210  		return nil, err
   211  	}
   212  
   213  	return append(dst, sw.Bytes()...), nil
   214  }
   215  
   216  // MarshalValue returns the BSON encoding of val.
   217  //
   218  // MarshalValue will use bson.DefaultRegistry to transform val into a BSON value. If val is a struct, this function will
   219  // inspect struct tags and alter the marshalling process accordingly.
   220  func MarshalValue(val interface{}) (bsontype.Type, []byte, error) {
   221  	return MarshalValueWithRegistry(DefaultRegistry, val)
   222  }
   223  
   224  // MarshalValueAppend will append the BSON encoding of val to dst. If dst is not large enough to hold the BSON encoding
   225  // of val, dst will be grown.
   226  //
   227  // Deprecated: Appending individual BSON elements to an existing slice will not be supported in Go
   228  // Driver 2.0.
   229  func MarshalValueAppend(dst []byte, val interface{}) (bsontype.Type, []byte, error) {
   230  	return MarshalValueAppendWithRegistry(DefaultRegistry, dst, val)
   231  }
   232  
   233  // MarshalValueWithRegistry returns the BSON encoding of val using Registry r.
   234  //
   235  // Deprecated: Using a custom registry to marshal individual BSON values will not be supported in Go
   236  // Driver 2.0.
   237  func MarshalValueWithRegistry(r *bsoncodec.Registry, val interface{}) (bsontype.Type, []byte, error) {
   238  	dst := make([]byte, 0)
   239  	return MarshalValueAppendWithRegistry(r, dst, val)
   240  }
   241  
   242  // MarshalValueWithContext returns the BSON encoding of val using EncodeContext ec.
   243  //
   244  // Deprecated: Using a custom EncodeContext to marshal individual BSON elements will not be
   245  // supported in Go Driver 2.0.
   246  func MarshalValueWithContext(ec bsoncodec.EncodeContext, val interface{}) (bsontype.Type, []byte, error) {
   247  	dst := make([]byte, 0)
   248  	return MarshalValueAppendWithContext(ec, dst, val)
   249  }
   250  
   251  // MarshalValueAppendWithRegistry will append the BSON encoding of val to dst using Registry r. If dst is not large
   252  // enough to hold the BSON encoding of val, dst will be grown.
   253  //
   254  // Deprecated: Appending individual BSON elements to an existing slice will not be supported in Go
   255  // Driver 2.0.
   256  func MarshalValueAppendWithRegistry(r *bsoncodec.Registry, dst []byte, val interface{}) (bsontype.Type, []byte, error) {
   257  	return MarshalValueAppendWithContext(bsoncodec.EncodeContext{Registry: r}, dst, val)
   258  }
   259  
   260  // MarshalValueAppendWithContext will append the BSON encoding of val to dst using EncodeContext ec. If dst is not large
   261  // enough to hold the BSON encoding of val, dst will be grown.
   262  //
   263  // Deprecated: Appending individual BSON elements to an existing slice will not be supported in Go
   264  // Driver 2.0.
   265  func MarshalValueAppendWithContext(ec bsoncodec.EncodeContext, dst []byte, val interface{}) (bsontype.Type, []byte, error) {
   266  	// get a ValueWriter configured to write to dst
   267  	sw := new(bsonrw.SliceWriter)
   268  	*sw = dst
   269  	vwFlusher := bvwPool.GetAtModeElement(sw)
   270  
   271  	// get an Encoder and encode the value
   272  	enc := encPool.Get().(*Encoder)
   273  	defer encPool.Put(enc)
   274  	if err := enc.Reset(vwFlusher); err != nil {
   275  		return 0, nil, err
   276  	}
   277  	if err := enc.SetContext(ec); err != nil {
   278  		return 0, nil, err
   279  	}
   280  	if err := enc.Encode(val); err != nil {
   281  		return 0, nil, err
   282  	}
   283  
   284  	// flush the bytes written because we cannot guarantee that a full document has been written
   285  	// after the flush, *sw will be in the format
   286  	// [value type, 0 (null byte to indicate end of empty element name), value bytes..]
   287  	if err := vwFlusher.Flush(); err != nil {
   288  		return 0, nil, err
   289  	}
   290  	buffer := *sw
   291  	return bsontype.Type(buffer[0]), buffer[2:], nil
   292  }
   293  
   294  // MarshalExtJSON returns the extended JSON encoding of val.
   295  func MarshalExtJSON(val interface{}, canonical, escapeHTML bool) ([]byte, error) {
   296  	return MarshalExtJSONWithRegistry(DefaultRegistry, val, canonical, escapeHTML)
   297  }
   298  
   299  // MarshalExtJSONAppend will append the extended JSON encoding of val to dst.
   300  // If dst is not large enough to hold the extended JSON encoding of val, dst
   301  // will be grown.
   302  //
   303  // Deprecated: Use [NewEncoder] and pass the dst byte slice (wrapped by a bytes.Buffer) into
   304  // [bsonrw.NewExtJSONValueWriter] instead:
   305  //
   306  //	buf := bytes.NewBuffer(dst)
   307  //	vw, err := bsonrw.NewExtJSONValueWriter(buf, true, false)
   308  //	if err != nil {
   309  //		panic(err)
   310  //	}
   311  //	enc, err := bson.NewEncoder(vw)
   312  //	if err != nil {
   313  //		panic(err)
   314  //	}
   315  //
   316  // See [Encoder] for more examples.
   317  func MarshalExtJSONAppend(dst []byte, val interface{}, canonical, escapeHTML bool) ([]byte, error) {
   318  	return MarshalExtJSONAppendWithRegistry(DefaultRegistry, dst, val, canonical, escapeHTML)
   319  }
   320  
   321  // MarshalExtJSONWithRegistry returns the extended JSON encoding of val using Registry r.
   322  //
   323  // Deprecated: Use [NewEncoder] and specify the Registry by calling [Encoder.SetRegistry] instead:
   324  //
   325  //	buf := new(bytes.Buffer)
   326  //	vw, err := bsonrw.NewBSONValueWriter(buf)
   327  //	if err != nil {
   328  //		panic(err)
   329  //	}
   330  //	enc, err := bson.NewEncoder(vw)
   331  //	if err != nil {
   332  //		panic(err)
   333  //	}
   334  //	enc.SetRegistry(reg)
   335  //
   336  // See [Encoder] for more examples.
   337  func MarshalExtJSONWithRegistry(r *bsoncodec.Registry, val interface{}, canonical, escapeHTML bool) ([]byte, error) {
   338  	dst := make([]byte, 0, defaultDstCap)
   339  	return MarshalExtJSONAppendWithContext(bsoncodec.EncodeContext{Registry: r}, dst, val, canonical, escapeHTML)
   340  }
   341  
   342  // MarshalExtJSONWithContext returns the extended JSON encoding of val using Registry r.
   343  //
   344  // Deprecated: Use [NewEncoder] and use the Encoder configuration methods to set the desired marshal
   345  // behavior instead:
   346  //
   347  //	buf := new(bytes.Buffer)
   348  //	vw, err := bsonrw.NewBSONValueWriter(buf)
   349  //	if err != nil {
   350  //		panic(err)
   351  //	}
   352  //	enc, err := bson.NewEncoder(vw)
   353  //	if err != nil {
   354  //		panic(err)
   355  //	}
   356  //	enc.IntMinSize()
   357  //
   358  // See [Encoder] for more examples.
   359  func MarshalExtJSONWithContext(ec bsoncodec.EncodeContext, val interface{}, canonical, escapeHTML bool) ([]byte, error) {
   360  	dst := make([]byte, 0, defaultDstCap)
   361  	return MarshalExtJSONAppendWithContext(ec, dst, val, canonical, escapeHTML)
   362  }
   363  
   364  // MarshalExtJSONAppendWithRegistry will append the extended JSON encoding of
   365  // val to dst using Registry r. If dst is not large enough to hold the BSON
   366  // encoding of val, dst will be grown.
   367  //
   368  // Deprecated: Use [NewEncoder], pass the dst byte slice (wrapped by a bytes.Buffer) into
   369  // [bsonrw.NewExtJSONValueWriter], and specify the Registry by calling [Encoder.SetRegistry]
   370  // instead:
   371  //
   372  //	buf := bytes.NewBuffer(dst)
   373  //	vw, err := bsonrw.NewExtJSONValueWriter(buf, true, false)
   374  //	if err != nil {
   375  //		panic(err)
   376  //	}
   377  //	enc, err := bson.NewEncoder(vw)
   378  //	if err != nil {
   379  //		panic(err)
   380  //	}
   381  //
   382  // See [Encoder] for more examples.
   383  func MarshalExtJSONAppendWithRegistry(r *bsoncodec.Registry, dst []byte, val interface{}, canonical, escapeHTML bool) ([]byte, error) {
   384  	return MarshalExtJSONAppendWithContext(bsoncodec.EncodeContext{Registry: r}, dst, val, canonical, escapeHTML)
   385  }
   386  
   387  // MarshalExtJSONAppendWithContext will append the extended JSON encoding of
   388  // val to dst using Registry r. If dst is not large enough to hold the BSON
   389  // encoding of val, dst will be grown.
   390  //
   391  // Deprecated: Use [NewEncoder], pass the dst byte slice (wrapped by a bytes.Buffer) into
   392  // [bsonrw.NewExtJSONValueWriter], and use the Encoder configuration methods to set the desired marshal
   393  // behavior instead:
   394  //
   395  //	buf := bytes.NewBuffer(dst)
   396  //	vw, err := bsonrw.NewExtJSONValueWriter(buf, true, false)
   397  //	if err != nil {
   398  //		panic(err)
   399  //	}
   400  //	enc, err := bson.NewEncoder(vw)
   401  //	if err != nil {
   402  //		panic(err)
   403  //	}
   404  //	enc.IntMinSize()
   405  //
   406  // See [Encoder] for more examples.
   407  func MarshalExtJSONAppendWithContext(ec bsoncodec.EncodeContext, dst []byte, val interface{}, canonical, escapeHTML bool) ([]byte, error) {
   408  	sw := new(bsonrw.SliceWriter)
   409  	*sw = dst
   410  	ejvw := extjPool.Get(sw, canonical, escapeHTML)
   411  	defer extjPool.Put(ejvw)
   412  
   413  	enc := encPool.Get().(*Encoder)
   414  	defer encPool.Put(enc)
   415  
   416  	err := enc.Reset(ejvw)
   417  	if err != nil {
   418  		return nil, err
   419  	}
   420  	err = enc.SetContext(ec)
   421  	if err != nil {
   422  		return nil, err
   423  	}
   424  
   425  	err = enc.Encode(val)
   426  	if err != nil {
   427  		return nil, err
   428  	}
   429  
   430  	return *sw, nil
   431  }
   432  
   433  // IndentExtJSON will prefix and indent the provided extended JSON src and append it to dst.
   434  func IndentExtJSON(dst *bytes.Buffer, src []byte, prefix, indent string) error {
   435  	return json.Indent(dst, src, prefix, indent)
   436  }
   437  
   438  // MarshalExtJSONIndent returns the extended JSON encoding of val with each line with prefixed
   439  // and indented.
   440  func MarshalExtJSONIndent(val interface{}, canonical, escapeHTML bool, prefix, indent string) ([]byte, error) {
   441  	marshaled, err := MarshalExtJSON(val, canonical, escapeHTML)
   442  	if err != nil {
   443  		return nil, err
   444  	}
   445  
   446  	var buf bytes.Buffer
   447  	err = IndentExtJSON(&buf, marshaled, prefix, indent)
   448  	if err != nil {
   449  		return nil, err
   450  	}
   451  
   452  	return buf.Bytes(), nil
   453  }
   454  

View as plain text