123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427 |
- // 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 (
- "bytes"
- "encoding/json"
- "go.mongodb.org/mongo-driver/bson/bsoncodec"
- "go.mongodb.org/mongo-driver/bson/bsonrw"
- "go.mongodb.org/mongo-driver/bson/bsontype"
- )
- const defaultDstCap = 256
- var bvwPool = bsonrw.NewBSONValueWriterPool()
- var extjPool = bsonrw.NewExtJSONValueWriterPool()
- // Marshaler is the interface implemented by types that can marshal themselves
- // into a valid BSON document.
- //
- // Implementations of Marshaler must return a full BSON document. To create
- // custom BSON marshaling behavior for individual values in a BSON document,
- // implement the ValueMarshaler interface instead.
- type Marshaler interface {
- MarshalBSON() ([]byte, error)
- }
- // ValueMarshaler is the interface implemented by types that can marshal
- // themselves into a valid BSON value. The format of the returned bytes must
- // match the returned type.
- //
- // Implementations of ValueMarshaler must return an individual BSON value. To
- // create custom BSON marshaling behavior for an entire BSON document, implement
- // the Marshaler interface instead.
- type ValueMarshaler interface {
- MarshalBSONValue() (bsontype.Type, []byte, error)
- }
- // Marshal returns the BSON encoding of val as a BSON document. If val is not a type that can be transformed into a
- // document, MarshalValue should be used instead.
- //
- // Marshal will use the default registry created by NewRegistry to recursively
- // marshal val into a []byte. Marshal will inspect struct tags and alter the
- // marshaling process accordingly.
- func Marshal(val interface{}) ([]byte, error) {
- return MarshalWithRegistry(DefaultRegistry, val)
- }
- // MarshalAppend will encode val as a BSON document and append the 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 transformed into a document, MarshalValueAppend should be
- // used instead.
- //
- // Deprecated: Use [NewEncoder] and pass the dst byte slice (wrapped by a bytes.Buffer) into
- // [bsonrw.NewBSONValueWriter]:
- //
- // buf := bytes.NewBuffer(dst)
- // vw, err := bsonrw.NewBSONValueWriter(buf)
- // if err != nil {
- // panic(err)
- // }
- // enc, err := bson.NewEncoder(vw)
- // if err != nil {
- // panic(err)
- // }
- //
- // See [Encoder] for more examples.
- func MarshalAppend(dst []byte, val interface{}) ([]byte, error) {
- return MarshalAppendWithRegistry(DefaultRegistry, dst, val)
- }
- // MarshalWithRegistry returns the BSON encoding of val as a BSON document. If val is not a type that can be transformed
- // into a document, MarshalValueWithRegistry should be used instead.
- //
- // Deprecated: Use [NewEncoder] and specify the Registry by calling [Encoder.SetRegistry] instead:
- //
- // buf := new(bytes.Buffer)
- // vw, err := bsonrw.NewBSONValueWriter(buf)
- // if err != nil {
- // panic(err)
- // }
- // enc, err := bson.NewEncoder(vw)
- // if err != nil {
- // panic(err)
- // }
- // enc.SetRegistry(reg)
- //
- // See [Encoder] for more examples.
- func MarshalWithRegistry(r *bsoncodec.Registry, val interface{}) ([]byte, error) {
- dst := make([]byte, 0)
- return MarshalAppendWithRegistry(r, dst, val)
- }
- // MarshalWithContext returns the BSON encoding of val as a BSON document using EncodeContext ec. If val is not a type
- // that can be transformed into a document, MarshalValueWithContext should be used instead.
- //
- // Deprecated: Use [NewEncoder] and use the Encoder configuration methods to set the desired marshal
- // behavior instead:
- //
- // buf := bytes.NewBuffer(dst)
- // vw, err := bsonrw.NewBSONValueWriter(buf)
- // if err != nil {
- // panic(err)
- // }
- // enc, err := bson.NewEncoder(vw)
- // if err != nil {
- // panic(err)
- // }
- // enc.IntMinSize()
- //
- // See [Encoder] for more examples.
- func MarshalWithContext(ec bsoncodec.EncodeContext, val interface{}) ([]byte, error) {
- dst := make([]byte, 0)
- return MarshalAppendWithContext(ec, dst, val)
- }
- // MarshalAppendWithRegistry will encode val as a BSON document using Registry r and append the 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 transformed into a document,
- // MarshalValueAppendWithRegistry should be used instead.
- //
- // Deprecated: Use [NewEncoder], and pass the dst byte slice (wrapped by a bytes.Buffer) into
- // [bsonrw.NewBSONValueWriter], and specify the Registry by calling [Encoder.SetRegistry] instead:
- //
- // buf := bytes.NewBuffer(dst)
- // vw, err := bsonrw.NewBSONValueWriter(buf)
- // if err != nil {
- // panic(err)
- // }
- // enc, err := bson.NewEncoder(vw)
- // if err != nil {
- // panic(err)
- // }
- // enc.SetRegistry(reg)
- //
- // See [Encoder] for more examples.
- func MarshalAppendWithRegistry(r *bsoncodec.Registry, dst []byte, val interface{}) ([]byte, error) {
- return MarshalAppendWithContext(bsoncodec.EncodeContext{Registry: r}, dst, val)
- }
- // MarshalAppendWithContext will encode val as a BSON document using Registry r and EncodeContext ec and append the
- // 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
- // transformed into a document, MarshalValueAppendWithContext should be used instead.
- //
- // Deprecated: Use [NewEncoder], pass the dst byte slice (wrapped by a bytes.Buffer) into
- // [bsonrw.NewBSONValueWriter], and use the Encoder configuration methods to set the desired marshal
- // behavior instead:
- //
- // buf := bytes.NewBuffer(dst)
- // vw, err := bsonrw.NewBSONValueWriter(buf)
- // if err != nil {
- // panic(err)
- // }
- // enc, err := bson.NewEncoder(vw)
- // if err != nil {
- // panic(err)
- // }
- // enc.IntMinSize()
- //
- // See [Encoder] for more examples.
- func MarshalAppendWithContext(ec bsoncodec.EncodeContext, dst []byte, val interface{}) ([]byte, error) {
- sw := new(bsonrw.SliceWriter)
- *sw = dst
- vw := bvwPool.Get(sw)
- defer bvwPool.Put(vw)
- enc := encPool.Get().(*Encoder)
- defer encPool.Put(enc)
- err := enc.Reset(vw)
- if err != nil {
- return nil, err
- }
- err = enc.SetContext(ec)
- if err != nil {
- return nil, err
- }
- err = enc.Encode(val)
- if err != nil {
- return nil, err
- }
- return *sw, nil
- }
- // MarshalValue returns the BSON encoding of val.
- //
- // MarshalValue will use bson.DefaultRegistry to transform val into a BSON value. If val is a struct, this function will
- // inspect struct tags and alter the marshalling process accordingly.
- func MarshalValue(val interface{}) (bsontype.Type, []byte, error) {
- return MarshalValueWithRegistry(DefaultRegistry, val)
- }
- // MarshalValueAppend will append the BSON encoding of val to dst. If dst is not large enough to hold the BSON encoding
- // of val, dst will be grown.
- //
- // Deprecated: Appending individual BSON elements to an existing slice will not be supported in Go
- // Driver 2.0.
- func MarshalValueAppend(dst []byte, val interface{}) (bsontype.Type, []byte, error) {
- return MarshalValueAppendWithRegistry(DefaultRegistry, dst, val)
- }
- // MarshalValueWithRegistry returns the BSON encoding of val using Registry r.
- //
- // Deprecated: Using a custom registry to marshal individual BSON values will not be supported in Go
- // Driver 2.0.
- func MarshalValueWithRegistry(r *bsoncodec.Registry, val interface{}) (bsontype.Type, []byte, error) {
- dst := make([]byte, 0)
- return MarshalValueAppendWithRegistry(r, dst, val)
- }
- // MarshalValueWithContext returns the BSON encoding of val using EncodeContext ec.
- //
- // Deprecated: Using a custom EncodeContext to marshal individual BSON elements will not be
- // supported in Go Driver 2.0.
- func MarshalValueWithContext(ec bsoncodec.EncodeContext, val interface{}) (bsontype.Type, []byte, error) {
- dst := make([]byte, 0)
- return MarshalValueAppendWithContext(ec, dst, val)
- }
- // MarshalValueAppendWithRegistry will append the BSON encoding of val to dst using Registry r. If dst is not large
- // enough to hold the BSON encoding of val, dst will be grown.
- //
- // Deprecated: Appending individual BSON elements to an existing slice will not be supported in Go
- // Driver 2.0.
- func MarshalValueAppendWithRegistry(r *bsoncodec.Registry, dst []byte, val interface{}) (bsontype.Type, []byte, error) {
- return MarshalValueAppendWithContext(bsoncodec.EncodeContext{Registry: r}, dst, val)
- }
- // MarshalValueAppendWithContext will append the BSON encoding of val to dst using EncodeContext ec. If dst is not large
- // enough to hold the BSON encoding of val, dst will be grown.
- //
- // Deprecated: Appending individual BSON elements to an existing slice will not be supported in Go
- // Driver 2.0.
- func MarshalValueAppendWithContext(ec bsoncodec.EncodeContext, dst []byte, val interface{}) (bsontype.Type, []byte, error) {
- // get a ValueWriter configured to write to dst
- sw := new(bsonrw.SliceWriter)
- *sw = dst
- vwFlusher := bvwPool.GetAtModeElement(sw)
- // get an Encoder and encode the value
- enc := encPool.Get().(*Encoder)
- defer encPool.Put(enc)
- if err := enc.Reset(vwFlusher); err != nil {
- return 0, nil, err
- }
- if err := enc.SetContext(ec); err != nil {
- return 0, nil, err
- }
- if err := enc.Encode(val); err != nil {
- return 0, nil, err
- }
- // flush the bytes written because we cannot guarantee that a full document has been written
- // after the flush, *sw will be in the format
- // [value type, 0 (null byte to indicate end of empty element name), value bytes..]
- if err := vwFlusher.Flush(); err != nil {
- return 0, nil, err
- }
- buffer := *sw
- return bsontype.Type(buffer[0]), buffer[2:], nil
- }
- // MarshalExtJSON returns the extended JSON encoding of val.
- func MarshalExtJSON(val interface{}, canonical, escapeHTML bool) ([]byte, error) {
- return MarshalExtJSONWithRegistry(DefaultRegistry, val, canonical, escapeHTML)
- }
- // MarshalExtJSONAppend will append the extended JSON encoding of val to dst.
- // If dst is not large enough to hold the extended JSON encoding of val, dst
- // will be grown.
- //
- // Deprecated: Use [NewEncoder] and pass the dst byte slice (wrapped by a bytes.Buffer) into
- // [bsonrw.NewExtJSONValueWriter] instead:
- //
- // buf := bytes.NewBuffer(dst)
- // vw, err := bsonrw.NewExtJSONValueWriter(buf, true, false)
- // if err != nil {
- // panic(err)
- // }
- // enc, err := bson.NewEncoder(vw)
- // if err != nil {
- // panic(err)
- // }
- //
- // See [Encoder] for more examples.
- func MarshalExtJSONAppend(dst []byte, val interface{}, canonical, escapeHTML bool) ([]byte, error) {
- return MarshalExtJSONAppendWithRegistry(DefaultRegistry, dst, val, canonical, escapeHTML)
- }
- // MarshalExtJSONWithRegistry returns the extended JSON encoding of val using Registry r.
- //
- // Deprecated: Use [NewEncoder] and specify the Registry by calling [Encoder.SetRegistry] instead:
- //
- // buf := new(bytes.Buffer)
- // vw, err := bsonrw.NewBSONValueWriter(buf)
- // if err != nil {
- // panic(err)
- // }
- // enc, err := bson.NewEncoder(vw)
- // if err != nil {
- // panic(err)
- // }
- // enc.SetRegistry(reg)
- //
- // See [Encoder] for more examples.
- func MarshalExtJSONWithRegistry(r *bsoncodec.Registry, val interface{}, canonical, escapeHTML bool) ([]byte, error) {
- dst := make([]byte, 0, defaultDstCap)
- return MarshalExtJSONAppendWithContext(bsoncodec.EncodeContext{Registry: r}, dst, val, canonical, escapeHTML)
- }
- // MarshalExtJSONWithContext returns the extended JSON encoding of val using Registry r.
- //
- // Deprecated: Use [NewEncoder] and use the Encoder configuration methods to set the desired marshal
- // behavior instead:
- //
- // buf := new(bytes.Buffer)
- // vw, err := bsonrw.NewBSONValueWriter(buf)
- // if err != nil {
- // panic(err)
- // }
- // enc, err := bson.NewEncoder(vw)
- // if err != nil {
- // panic(err)
- // }
- // enc.IntMinSize()
- //
- // See [Encoder] for more examples.
- func MarshalExtJSONWithContext(ec bsoncodec.EncodeContext, val interface{}, canonical, escapeHTML bool) ([]byte, error) {
- dst := make([]byte, 0, defaultDstCap)
- return MarshalExtJSONAppendWithContext(ec, dst, val, canonical, escapeHTML)
- }
- // MarshalExtJSONAppendWithRegistry will append the extended JSON encoding of
- // val to dst using Registry r. If dst is not large enough to hold the BSON
- // encoding of val, dst will be grown.
- //
- // Deprecated: Use [NewEncoder], pass the dst byte slice (wrapped by a bytes.Buffer) into
- // [bsonrw.NewExtJSONValueWriter], and specify the Registry by calling [Encoder.SetRegistry]
- // instead:
- //
- // buf := bytes.NewBuffer(dst)
- // vw, err := bsonrw.NewExtJSONValueWriter(buf, true, false)
- // if err != nil {
- // panic(err)
- // }
- // enc, err := bson.NewEncoder(vw)
- // if err != nil {
- // panic(err)
- // }
- //
- // See [Encoder] for more examples.
- func MarshalExtJSONAppendWithRegistry(r *bsoncodec.Registry, dst []byte, val interface{}, canonical, escapeHTML bool) ([]byte, error) {
- return MarshalExtJSONAppendWithContext(bsoncodec.EncodeContext{Registry: r}, dst, val, canonical, escapeHTML)
- }
- // MarshalExtJSONAppendWithContext will append the extended JSON encoding of
- // val to dst using Registry r. If dst is not large enough to hold the BSON
- // encoding of val, dst will be grown.
- //
- // Deprecated: Use [NewEncoder], pass the dst byte slice (wrapped by a bytes.Buffer) into
- // [bsonrw.NewExtJSONValueWriter], and use the Encoder configuration methods to set the desired marshal
- // behavior instead:
- //
- // buf := bytes.NewBuffer(dst)
- // vw, err := bsonrw.NewExtJSONValueWriter(buf, true, false)
- // if err != nil {
- // panic(err)
- // }
- // enc, err := bson.NewEncoder(vw)
- // if err != nil {
- // panic(err)
- // }
- // enc.IntMinSize()
- //
- // See [Encoder] for more examples.
- func MarshalExtJSONAppendWithContext(ec bsoncodec.EncodeContext, dst []byte, val interface{}, canonical, escapeHTML bool) ([]byte, error) {
- sw := new(bsonrw.SliceWriter)
- *sw = dst
- ejvw := extjPool.Get(sw, canonical, escapeHTML)
- defer extjPool.Put(ejvw)
- enc := encPool.Get().(*Encoder)
- defer encPool.Put(enc)
- err := enc.Reset(ejvw)
- if err != nil {
- return nil, err
- }
- err = enc.SetContext(ec)
- if err != nil {
- return nil, err
- }
- err = enc.Encode(val)
- if err != nil {
- return nil, err
- }
- return *sw, nil
- }
- // IndentExtJSON will prefix and indent the provided extended JSON src and append it to dst.
- func IndentExtJSON(dst *bytes.Buffer, src []byte, prefix, indent string) error {
- return json.Indent(dst, src, prefix, indent)
- }
- // MarshalExtJSONIndent returns the extended JSON encoding of val with each line with prefixed
- // and indented.
- func MarshalExtJSONIndent(val interface{}, canonical, escapeHTML bool, prefix, indent string) ([]byte, error) {
- marshaled, err := MarshalExtJSON(val, canonical, escapeHTML)
- if err != nil {
- return nil, err
- }
- var buf bytes.Buffer
- err = IndentExtJSON(&buf, marshaled, prefix, indent)
- if err != nil {
- return nil, err
- }
- return buf.Bytes(), nil
- }
|