| // 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 ( |
| "github.com/mongodb/mongo-go-driver/bson/bsoncodec" |
| "github.com/mongodb/mongo-go-driver/bson/bsonrw" |
| "github.com/mongodb/mongo-go-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 |
| } |