3
// Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net>
5
// All rights reserved.
7
// Redistribution and use in source and binary forms, with or without
8
// modification, are permitted provided that the following conditions are met:
10
// 1. Redistributions of source code must retain the above copyright notice, this
11
// list of conditions and the following disclaimer.
12
// 2. Redistributions in binary form must reproduce the above copyright notice,
13
// this list of conditions and the following disclaimer in the documentation
14
// and/or other materials provided with the distribution.
16
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
// gobson - BSON library for Go.
39
// --------------------------------------------------------------------------
40
// Some internal infrastructure.
43
typeBinary = reflect.TypeOf(Binary{})
44
typeObjectId = reflect.TypeOf(ObjectId(""))
45
typeSymbol = reflect.TypeOf(Symbol(""))
46
typeMongoTimestamp = reflect.TypeOf(MongoTimestamp(0))
47
typeOrderKey = reflect.TypeOf(MinKey)
48
typeDocElem = reflect.TypeOf(DocElem{})
49
typeRaw = reflect.TypeOf(Raw{})
50
typeURL = reflect.TypeOf(url.URL{})
51
typeTime = reflect.TypeOf(time.Time{})
54
const itoaCacheSize = 32
56
var itoaCache []string
59
itoaCache = make([]string, itoaCacheSize)
60
for i := 0; i != itoaCacheSize; i++ {
61
itoaCache[i] = strconv.Itoa(i)
65
func itoa(i int) string {
66
if i < itoaCacheSize {
69
return strconv.Itoa(i)
72
// --------------------------------------------------------------------------
73
// Marshaling of the document value itself.
79
func (e *encoder) addDoc(v reflect.Value) {
81
if vi, ok := v.Interface().(Getter); ok {
82
getv, err := vi.GetBSON()
86
v = reflect.ValueOf(getv)
89
if v.Kind() == reflect.Ptr {
96
if v.Type() == typeRaw {
97
raw := v.Interface().(Raw)
98
if raw.Kind != 0x03 && raw.Kind != 0x00 {
99
panic("Attempted to unmarshal Raw kind " + strconv.Itoa(int(raw.Kind)) + " as a document")
101
e.addBytes(raw.Data...)
105
start := e.reserveInt32()
112
case reflect.Array, reflect.Slice:
115
panic("Can't marshal " + v.Type().String() + " as a BSON document")
119
e.setInt32(start, int32(len(e.out)-start))
122
func (e *encoder) addMap(v reflect.Value) {
123
for _, k := range v.MapKeys() {
124
e.addElem(k.String(), v.MapIndex(k), false)
128
func (e *encoder) addStruct(v reflect.Value) {
129
sinfo, err := getStructInfo(v.Type())
133
var value reflect.Value
134
if sinfo.InlineMap >= 0 {
135
m := v.Field(sinfo.InlineMap)
137
for _, k := range m.MapKeys() {
139
if _, found := sinfo.FieldsMap[ks]; found {
140
panic(fmt.Sprintf("Can't have key %q in inlined map; conflicts with struct field", ks))
142
e.addElem(ks, m.MapIndex(k), false)
146
for _, info := range sinfo.FieldsList {
147
if info.Inline == nil {
148
value = v.Field(info.Num)
150
value = v.FieldByIndex(info.Inline)
152
if info.OmitEmpty && isZero(value) {
155
e.addElem(info.Key, value, info.MinSize)
159
func isZero(v reflect.Value) bool {
162
return len(v.String()) == 0
163
case reflect.Ptr, reflect.Interface:
169
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
171
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
173
case reflect.Float32, reflect.Float64:
174
return v.Float() == 0
178
if v.Type() == typeTime {
179
return v.Interface().(time.Time).IsZero()
185
func (e *encoder) addSlice(v reflect.Value) {
186
if d, ok := v.Interface().(D); ok {
187
for _, elem := range d {
188
e.addElem(elem.Name, reflect.ValueOf(elem.Value), false)
190
} else if v.Type().Elem() == typeDocElem {
192
for i := 0; i < l; i++ {
193
elem := v.Index(i).Interface().(DocElem)
194
e.addElem(elem.Name, reflect.ValueOf(elem.Value), false)
198
for i := 0; i < l; i++ {
199
e.addElem(itoa(i), v.Index(i), false)
204
// --------------------------------------------------------------------------
205
// Marshaling of elements in a document.
207
func (e *encoder) addElemName(kind byte, name string) {
209
e.addBytes([]byte(name)...)
213
func (e *encoder) addElem(name string, v reflect.Value, minSize bool) {
216
e.addElemName('\x0A', name)
220
if getter, ok := v.Interface().(Getter); ok {
221
getv, err := getter.GetBSON()
225
e.addElem(name, reflect.ValueOf(getv), minSize)
231
case reflect.Interface:
232
e.addElem(name, v.Elem(), minSize)
235
e.addElem(name, v.Elem(), minSize)
242
panic("ObjectIDs must be exactly 12 bytes long (got " +
243
strconv.Itoa(len(s)) + ")")
245
e.addElemName('\x07', name)
246
e.addBytes([]byte(s)...)
248
e.addElemName('\x0E', name)
251
e.addElemName('\x02', name)
255
case reflect.Float32, reflect.Float64:
256
e.addElemName('\x01', name)
257
e.addInt64(int64(math.Float64bits(v.Float())))
259
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
262
panic("BSON has no uint64 type, and value is too large to fit correctly in an int64")
263
} else if u <= math.MaxInt32 && (minSize || v.Kind() <= reflect.Uint32) {
264
e.addElemName('\x10', name)
267
e.addElemName('\x12', name)
271
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
272
if v.Type().Kind() <= reflect.Int32 {
273
e.addElemName('\x10', name)
274
e.addInt32(int32(v.Int()))
277
case typeMongoTimestamp:
278
e.addElemName('\x11', name)
282
if v.Int() == int64(MaxKey) {
283
e.addElemName('\x7F', name)
285
e.addElemName('\xFF', name)
290
if minSize && i >= math.MinInt32 && i <= math.MaxInt32 {
291
// It fits into an int32, encode as such.
292
e.addElemName('\x10', name)
295
e.addElemName('\x12', name)
302
e.addElemName('\x08', name)
310
e.addElemName('\x03', name)
316
if et.Kind() == reflect.Uint8 {
317
e.addElemName('\x05', name)
318
e.addBinary('\x00', v.Bytes())
319
} else if et == typeDocElem {
320
e.addElemName('\x03', name)
323
e.addElemName('\x04', name)
328
et := v.Type().Elem()
329
if et.Kind() == reflect.Uint8 {
330
e.addElemName('\x05', name)
331
e.addBinary('\x00', v.Slice(0, v.Len()).Interface().([]byte))
333
e.addElemName('\x04', name)
338
switch s := v.Interface().(type) {
345
e.addElemName(kind, name)
346
e.addBytes(s.Data...)
349
e.addElemName('\x05', name)
350
e.addBinary(s.Kind, s.Data)
353
e.addElemName('\x0B', name)
359
e.addElemName('\x0D', name)
362
e.addElemName('\x0F', name)
363
start := e.reserveInt32()
365
e.addDoc(reflect.ValueOf(s.Scope))
366
e.setInt32(start, int32(len(e.out)-start))
370
// MongoDB handles timestamps as milliseconds.
371
e.addElemName('\x09', name)
372
e.addInt64(s.Unix() * 1000 + int64(s.Nanosecond() / 1e6))
375
e.addElemName('\x02', name)
379
e.addElemName('\x06', name)
382
e.addElemName('\x03', name)
387
panic("Can't marshal " + v.Type().String() + " in a BSON document")
391
// --------------------------------------------------------------------------
392
// Marshaling of base types.
394
func (e *encoder) addBinary(subtype byte, v []byte) {
396
// Wonder how that brilliant idea came to life. Obsolete, luckily.
397
e.addInt32(int32(len(v) + 4))
399
e.addInt32(int32(len(v)))
401
e.addInt32(int32(len(v)))
407
func (e *encoder) addStr(v string) {
408
e.addInt32(int32(len(v) + 1))
412
func (e *encoder) addCStr(v string) {
413
e.addBytes([]byte(v)...)
417
func (e *encoder) reserveInt32() (pos int) {
419
e.addBytes(0, 0, 0, 0)
423
func (e *encoder) setInt32(pos int, v int32) {
424
e.out[pos+0] = byte(v)
425
e.out[pos+1] = byte(v >> 8)
426
e.out[pos+2] = byte(v >> 16)
427
e.out[pos+3] = byte(v >> 24)
430
func (e *encoder) addInt32(v int32) {
432
e.addBytes(byte(u), byte(u>>8), byte(u>>16), byte(u>>24))
435
func (e *encoder) addInt64(v int64) {
437
e.addBytes(byte(u), byte(u>>8), byte(u>>16), byte(u>>24),
438
byte(u>>32), byte(u>>40), byte(u>>48), byte(u>>56))
441
func (e *encoder) addBytes(v ...byte) {
442
e.out = append(e.out, v...)