// 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 ( "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 an interface implemented by types that can marshal themselves // into a BSON document represented as bytes. The bytes returned must be a valid // BSON document if the error is nil. type Marshaler interface { MarshalBSON() ([]byte, error) } // ValueMarshaler is an interface implemented by types that can marshal // themselves into a BSON value as bytes. The type must be the valid type for // the bytes returned. The bytes and byte type together must be valid if the // error is nil. type ValueMarshaler interface { MarshalBSONValue() (bsontype.Type, []byte, error) } // Marshal returns the BSON encoding of val. // // 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 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. func MarshalAppend(dst []byte, val interface{}) ([]byte, error) { return MarshalAppendWithRegistry(DefaultRegistry, dst, val) } // MarshalWithRegistry returns the BSON encoding of val using Registry r. func MarshalWithRegistry(r *bsoncodec.Registry, val interface{}) ([]byte, error) { dst := make([]byte, 0, 256) // TODO: make the default cap a constant return MarshalAppendWithRegistry(r, dst, val) } // MarshalWithContext returns the BSON encoding of val using EncodeContext ec. func MarshalWithContext(ec bsoncodec.EncodeContext, val interface{}) ([]byte, error) { dst := make([]byte, 0, 256) // TODO: make the default cap a constant return MarshalAppendWithContext(ec, dst, val) } // MarshalAppendWithRegistry 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. func MarshalAppendWithRegistry(r *bsoncodec.Registry, dst []byte, val interface{}) ([]byte, error) { return MarshalAppendWithContext(bsoncodec.EncodeContext{Registry: r}, dst, val) } // MarshalAppendWithContext 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. 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 } // 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. 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. 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. 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. 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. 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 }