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