@@ -50,6 +50,8 @@ import (
5050 "sync"
5151 "sync/atomic"
5252 "time"
53+
54+ "go.mongodb.org/mongo-driver/bson/bsontype"
5355)
5456
5557//go:generate go run bson_corpus_spec_test_generator.go
@@ -59,27 +61,27 @@ import (
5961
6062// Element types constants from BSON specification.
6163const (
62- ElementFloat64 byte = 0x01
63- ElementString byte = 0x02
64- ElementDocument byte = 0x03
65- ElementArray byte = 0x04
66- ElementBinary byte = 0x05
67- Element06 byte = 0x06
68- ElementObjectId byte = 0x07
69- ElementBool byte = 0x08
70- ElementDatetime byte = 0x09
71- ElementNil byte = 0x0A
72- ElementRegEx byte = 0x0B
73- ElementDBPointer byte = 0x0C
74- ElementJavaScriptWithoutScope byte = 0x0D
75- ElementSymbol byte = 0x0E
76- ElementJavaScriptWithScope byte = 0x0F
77- ElementInt32 byte = 0x10
78- ElementTimestamp byte = 0x11
79- ElementInt64 byte = 0x12
80- ElementDecimal128 byte = 0x13
81- ElementMinKey byte = 0xFF
82- ElementMaxKey byte = 0x7F
64+ ElementFloat64 = bsontype . Double
65+ ElementString = bsontype . String
66+ ElementDocument = bsontype . EmbeddedDocument
67+ ElementArray = bsontype . Array
68+ ElementBinary = bsontype . Binary
69+ Element06 = bsontype . Undefined
70+ ElementObjectId = bsontype . ObjectID
71+ ElementBool = bsontype . Boolean
72+ ElementDatetime = bsontype . DateTime
73+ ElementNil = bsontype . Null
74+ ElementRegEx = bsontype . Regex
75+ ElementDBPointer = bsontype . DBPointer
76+ ElementJavaScriptWithoutScope = bsontype . JavaScript
77+ ElementSymbol = bsontype . Symbol
78+ ElementJavaScriptWithScope = bsontype . CodeWithScope
79+ ElementInt32 = bsontype . Int32
80+ ElementTimestamp = bsontype . Timestamp
81+ ElementInt64 = bsontype . Int64
82+ ElementDecimal128 = bsontype . Decimal128
83+ ElementMinKey = bsontype . MinKey
84+ ElementMaxKey = bsontype . MaxKey
8385
8486 BinaryGeneric byte = 0x00
8587 BinaryFunction byte = 0x01
@@ -185,7 +187,7 @@ func (d D) Map() (m M) {
185187// http://bsonspec.org/#/specification
186188//
187189type Raw struct {
188- Kind byte
190+ Kind bsontype. Type
189191 Data []byte
190192}
191193
@@ -210,17 +212,22 @@ type RawDocElem struct {
210212// property.
211213//
212214// http://www.mongodb.org/display/DOCS/Object+Ids
213- type ObjectId string
215+ type ObjectId [12 ]byte
216+
217+ var NilObjectID ObjectId
214218
215219// ObjectIdHex returns an ObjectId from the provided hex representation.
216220// Calling this function with an invalid hex representation will
217221// cause a runtime panic. See the IsObjectIdHex function.
218222func ObjectIdHex (s string ) ObjectId {
219- d , err := hex .DecodeString (s )
220- if err != nil || len (d ) != 12 {
223+ if hex .DecodedLen (len (s )) != 12 {
221224 panic (fmt .Sprintf ("invalid input to ObjectIdHex: %q" , s ))
222225 }
223- return ObjectId (d )
226+ var oid ObjectId
227+ if _ , err := hex .Decode (oid [:], []byte (s )); err != nil {
228+ panic (fmt .Sprintf ("invalid input to ObjectIdHex: %q" , s ))
229+ }
230+ return oid
224231}
225232
226233// IsObjectIdHex returns whether s is a valid hex representation of
@@ -288,7 +295,7 @@ func NewObjectId() ObjectId {
288295 b [9 ] = byte (i >> 16 )
289296 b [10 ] = byte (i >> 8 )
290297 b [11 ] = byte (i )
291- return ObjectId ( b [:])
298+ return b
292299}
293300
294301// NewObjectIdWithTime returns a dummy ObjectId with the timestamp part filled
@@ -299,23 +306,23 @@ func NewObjectId() ObjectId {
299306func NewObjectIdWithTime (t time.Time ) ObjectId {
300307 var b [12 ]byte
301308 binary .BigEndian .PutUint32 (b [:4 ], uint32 (t .Unix ()))
302- return ObjectId ( string ( b [:]))
309+ return b
303310}
304311
305312// String returns a hex string representation of the id.
306313// Example: ObjectIdHex("4d88e15b60f486e428412dc9").
307314func (id ObjectId ) String () string {
308- return fmt .Sprintf (`ObjectIdHex("%x")` , string ( id ) )
315+ return fmt .Sprintf (`ObjectIdHex("%x")` , id [:] )
309316}
310317
311318// Hex returns a hex representation of the ObjectId.
312319func (id ObjectId ) Hex () string {
313- return hex .EncodeToString ([] byte ( id ) )
320+ return hex .EncodeToString (id [:] )
314321}
315322
316323// MarshalJSON turns a bson.ObjectId into a json.Marshaller.
317324func (id ObjectId ) MarshalJSON () ([]byte , error ) {
318- return []byte (fmt .Sprintf (`"%x"` , string ( id ) )), nil
325+ return []byte (fmt .Sprintf (`"%x"` , id [:] )), nil
319326}
320327
321328var nullBytes = []byte ("null" )
@@ -339,7 +346,7 @@ func (id *ObjectId) UnmarshalJSON(data []byte) error {
339346 }
340347 }
341348 if len (data ) == 2 && data [0 ] == '"' && data [1 ] == '"' || bytes .Equal (data , nullBytes ) {
342- * id = ""
349+ * id = ObjectId {}
343350 return nil
344351 }
345352 if len (data ) != 26 || data [0 ] != '"' || data [25 ] != '"' {
@@ -350,19 +357,22 @@ func (id *ObjectId) UnmarshalJSON(data []byte) error {
350357 if err != nil {
351358 return fmt .Errorf ("invalid ObjectId in JSON: %s (%s)" , string (data ), err )
352359 }
353- * id = ObjectId ( string ( buf [:]))
360+ * id = buf
354361 return nil
355362}
356363
357364// MarshalText turns bson.ObjectId into an encoding.TextMarshaler.
358365func (id ObjectId ) MarshalText () ([]byte , error ) {
359- return []byte (fmt .Sprintf ("%x" , string (id ))), nil
366+ if id .IsZero () {
367+ return nil , nil
368+ }
369+ return []byte (fmt .Sprintf ("%x" , id [:])), nil
360370}
361371
362372// UnmarshalText turns *bson.ObjectId into an encoding.TextUnmarshaler.
363373func (id * ObjectId ) UnmarshalText (data []byte ) error {
364374 if len (data ) == 1 && data [0 ] == ' ' || len (data ) == 0 {
365- * id = ""
375+ * id = ObjectId {}
366376 return nil
367377 }
368378 if len (data ) != 24 {
@@ -373,22 +383,24 @@ func (id *ObjectId) UnmarshalText(data []byte) error {
373383 if err != nil {
374384 return fmt .Errorf ("invalid ObjectId: %s (%s)" , data , err )
375385 }
376- * id = ObjectId ( string ( buf [:]))
386+ * id = buf
377387 return nil
378388}
379389
380390// Valid returns true if id is valid. A valid id must contain exactly 12 bytes.
381391func (id ObjectId ) Valid () bool {
382- return len (id ) == 12
392+ return ! id .IsZero ()
393+ }
394+
395+ // Valid returns true if id is valid. A valid id must contain exactly 12 bytes.
396+ func (id ObjectId ) IsZero () bool {
397+ return id == ObjectId {}
383398}
384399
385400// byteSlice returns byte slice of id from start to end.
386401// Calling this function with an invalid id will cause a runtime panic.
387402func (id ObjectId ) byteSlice (start , end int ) []byte {
388- if len (id ) != 12 {
389- panic (fmt .Sprintf ("invalid ObjectId: %q" , string (id )))
390- }
391- return []byte (string (id )[start :end ])
403+ return id [start :end ]
392404}
393405
394406// Time returns the timestamp part of the id.
@@ -684,11 +696,11 @@ func (raw Raw) Unmarshal(out interface{}) (err error) {
684696// during unmarshaling
685697type TypeError struct {
686698 Type reflect.Type
687- Kind byte
699+ Kind bsontype. Type
688700}
689701
690702func (e * TypeError ) Error () string {
691- return fmt .Sprintf ("BSON kind 0x%02x isn't compatible with type %s" , e .Kind , e .Type .String ())
703+ return fmt .Sprintf ("BSON kind 0x%02x isn't compatible with type %s" , byte ( e .Kind ) , e .Type .String ())
692704}
693705
694706// --------------------------------------------------------------------------
0 commit comments