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